Skip to content

feat: add Node.ident: Int field (additive) - #404

Closed
briansrls wants to merge 1 commit into
mainfrom
ident-int-additive
Closed

briansrls wants to merge 1 commit into
mainfrom
ident-int-additive

Conversation

@briansrls

Copy link
Copy Markdown
Contributor

Summary

  • Adds ident: Int to the Node struct alongside name: String (field count 17 → 18)
  • Every Node construction site initializes ident: 0
  • First half of the name → ident migration: field exists so a follow-up can wire intern() at construction time, then delete name: String
  • ident is a parse-time structural fact (same category as span and ident_span), not compiler-derived analysis

Test plan

  • cargo build — clean
  • cargo test -p v2-compiler-tests — 401 passed, 0 failed, 50 ignored
  • Stage0 diagnostic ratchet — 0 diagnostics
  • +168/-2 across 11 files (1-line .dag change + mechanical ident: 0 insertion)

🤖 Generated with Claude Code

@briansrls

briansrls commented Apr 12, 2026 •

Copy link
Copy Markdown
Contributor Author

ChatGPT Review

I reviewed the uploaded PR diff against the thesis first. On that standard, I would block this PR.

The core problem is that Node.ident is being added as if it were a structural fact, but in this diff it is not one. In the reviewed changes, the field is introduced on Node, yet every write I found initializes it to 0, and I did not find any new consumer that reads it to make a real compilation decision. That makes it placeholder metadata, not validated identity. The thesis says new mechanisms should only exist when they carry real structural meaning, and the invariants explicitly reject speculative metadata, duplicate authorities, and fabricated defaults. chatgpt-review-72c824c1-3033-42…

chatgpt-review-61a1b6e9-066b-41…

The first blocking issue is duplicate authority. After this PR, Node has both name and ident, but name remains the only semantic authority. The roadmap is very explicit that Track 3’s root cause is Node.name being used as semantic authority, that stable identity still lacks a real consumer, and that Node.name deletion is still blocked. Adding a dead ident field increases dual-representation debt instead of dissolving it. chatgpt-review-d915d196-7990-44…

The second blocking issue is that identity is not preserved through transformations. Helpers that rebuild nodes, such as map_children, with_optional_cardinality, with_required_cardinality, parser item constructors, and infer/resolve rewrites, all reset ident back to 0 instead of preserving anything. So even if a later producer started assigning meaningful IDs, this change as written would erase them across normal compiler flows. That violates the “facts flow forward” / explicit-boundary contract in the invariants: facts must be carried, not dropped and reconstructed later. chatgpt-review-61a1b6e9-066b-41…

The third blocking issue is that no end-to-end boundary lands here. The invariants say a new semantic boundary is not accepted unless at least one downstream consumer in the same change reads it as authority for a real decision. I do not see that here. The test updates are mechanical constructor churn, and the suite still contains resolve_node_uses_node_name_for_lookup, which is a pretty direct sign that semantic lookup remains name-based after this PR. chatgpt-review-61a1b6e9-066b-41…

chatgpt-review-bcfcc6ac-e219-4e…

On compositional modeling quality, there is not much .dag surface change beyond the core Node definition itself. And that change does not look like the project’s own modeling style. Compared to std-library.dag, where identities are usually modeled as meaningful/branded values rather than ambient integers, ident: Int is too weak. It says nothing about scope, uniqueness, stability, or whether 0 is invalid. The modeling docs are explicit that when structure is missing, the fix is to model the structure, not add metadata-shaped placeholders. chatgpt-review-3af5cd38-1a49-4d…

ROADMAP.md is not modified in this PR, so there is no roadmap-doc drift to call out. Conceptually, though, this looks aimed at Track 3 / stable binding identity and maybe ownership Layer 1. I do not think it advances either one. The roadmap says last-use clone elision is blocked on stable binding identity because name-keyed tables collapse distinct bindings; a field that is always 0 does not unblock that. It also says the real blockers are remaining name-based consumers plus the lack of an actual identity consumer. Those remain true after this diff. chatgpt-review-d915d196-7990-44…

General code review concerns:

  • This adds a field to Node, the hottest recursive IR type in the system, so it imposes a memory/serialization/churn cost everywhere. The performance invariant says that kind of global tax needs a justified asymptotic reason up front. Here the cost is real now, while the benefit is hypothetical. chatgpt-review-61a1b6e9-066b-41…
  • Because Node is serialized and propagated widely, a dead constant-zero field increases bootstrap/fixed-point surface area without increasing correctness.
  • The test coverage is missing the cases that matter: unique assignment at production time, preservation across node-copying helpers, stability through regeneration/fixed-point, and at least one real consumer switching from name-keyed to ident-keyed behavior. The thesis’s verification story depends on structural facts becoming testable obligations, not just being threaded mechanically. chatgpt-review-72c824c1-3033-42…

chatgpt-review-d915d196-7990-44…

The minimal shape I would accept is: a real producer assigns meaningful IDs, every node-rebuilding helper preserves them, at least one downstream consumer switches to using them as authority, and tests cover uniqueness/preservation/consumer behavior. Otherwise this should stay out; as written, it is additive in syntax but not additive in soundness.


View conversation

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b490926855

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/v2/stage0/src/v2_std_core.rs Outdated
pub fn map_children(node: &Rc<Node>, transform: impl Fn(Rc<Node>) -> Rc<Node> + Clone) -> Rc<Node> {
Rc::new(Node {
name: node.name.clone(),
ident: 0,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve existing node identifier in map_children

map_children is intended to rebuild a node with transformed children while retaining the rest of the node metadata, but this change hard-codes ident: 0 instead of carrying node.ident. Any caller that passes a node with a non-zero identifier (the field is public and parse-time IDs are the stated migration target) will silently lose symbol identity after this transform, which can break downstream logic that expects node identity to survive rewrites (e.g., inference/resolve passes that call map_children).

Useful? React with 👍 / 👎.

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cursor · composer-2 · b4909268

Review (INVARIANTS: 1, MODELING: 1+/1-, ROADMAP: 0✓/0!)

INVARIANTS — Violations (1)

ROOT CAUSE ANALYSIS

  • src/v2/00_core.dag Node.ident is added without a single compositional rule for which operations preserve it; map_children, with_optional_cardinality, with_required_cardinality, and many infer/resolve rebuilds hardcode 0 instead of propagating the prior node’s ident when only children or metadata change — upstream fix: declare shell-preservation (same logical Node) vs fresh synthetic Node in 00_core.dag comments or helpers, add one stage0 constructor that copies ident with overridden children, and use it in those transforms so stable ids assigned at parse (next step) survive the pipeline (M1 single authority, M4 structural identity over string/name heuristics).

MODELING — Strengths

  • src/v2/00_core.dag Adding ident: Int on Node matches the documented need for stable IDs in acyclic encodings of graphs and keeps the kernel on finite numeric data (Int as OrderedRing in std/types.dag).

MODELING — Improvements

  • src/v2/00_core.dag Bare Int is weak domain fidelity for an opaque identity; refine to a branded NodeId-style alias (e.g. NonNegativeInt or a dedicated newtype per MODELING.md refinements) and document invariants next to Node so emitters and transforms do not treat 0 as “always safe” once allocation exists.

Additive Node.ident field aligns the IR with stable-ID graph encodings, but the rollout must replace blanket ident: 0 on shell-preserving transforms with ident propagation (or shared constructors) before relying on it for causal or map-backed algorithms.

Comment thread src/v2/stage0/src/v2_std_core.rs Outdated
pub fn map_children(node: &Rc<Node>, transform: impl Fn(Rc<Node>) -> Rc<Node> + Clone) -> Rc<Node> {
Rc::new(Node {
name: node.name.clone(),
ident: 0,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invariant violation: Invariant violation: Core Node transforms copy name/span/ident_span but set ident: 0, erasing the new identity slot while claiming the same outer node — conflicts with thesis causal traceability and INVARIANTS guidance that cyclic structure should use stable IDs in encodings, not recomputed proxies.

@briansrls

Copy link
Copy Markdown
Contributor Author

cursor · composer-2 · b4909268

Review (INVARIANTS: 1, MODELING: 1+/1-, ROADMAP: 0✓/0!)

INVARIANTS — Violations (1)

ROOT CAUSE ANALYSIS

  • src/v2/00_core.dag Node.ident is added without a single compositional rule for which operations preserve it; map_children, with_optional_cardinality, with_required_cardinality, and many infer/resolve rebuilds hardcode 0 instead of propagating the prior node’s ident when only children or metadata change — upstream fix: declare shell-preservation (same logical Node) vs fresh synthetic Node in 00_core.dag comments or helpers, add one stage0 constructor that copies ident with overridden children, and use it in those transforms so stable ids assigned at parse (next step) survive the pipeline (M1 single authority, M4 structural identity over string/name heuristics).

MODELING — Strengths

  • src/v2/00_core.dag Adding ident: Int on Node matches the documented need for stable IDs in acyclic encodings of graphs and keeps the kernel on finite numeric data (Int as OrderedRing in std/types.dag).

MODELING — Improvements

  • src/v2/00_core.dag Bare Int is weak domain fidelity for an opaque identity; refine to a branded NodeId-style alias (e.g. NonNegativeInt or a dedicated newtype per MODELING.md refinements) and document invariants next to Node so emitters and transforms do not treat 0 as “always safe” once allocation exists.

Additive Node.ident field aligns the IR with stable-ID graph encodings, but the rollout must replace blanket ident: 0 on shell-preserving transforms with ident propagation (or shared constructors) before relying on it for causal or map-backed algorithms.

Adds ident: Int to the Node struct alongside name: String. The emitter
now fills default zero-values (Int→0, Bool→false, String→"") for struct
fields not explicitly set in .dag source, guarded by an all_defaultable
check that prevents false positives from cross-module type name collisions.

This solves the bootstrap wall for additive field changes: new fields
with known zero-values are automatically emitted, so regen produces
correct output without touching every .dag construction site.

Stage0 regenerated and fixed-point verified (pass1 == pass2).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@briansrls
briansrls force-pushed the ident-int-additive branch from b490926 to b8a4ab0 Compare April 12, 2026 02:17
@briansrls

Copy link
Copy Markdown
Contributor Author

ChatGPT review in progress... (view conversation)

@briansrls

Copy link
Copy Markdown
Contributor Author

Closing in favor of a split approach: emitter default-value support ships separately, and the ident field comes in a PR that includes parser assignment + at least one consumer + transform preservation. The ChatGPT review correctly identified that a placeholder ident with no consumer violates the project's structural-meaning invariant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant