Skip to content

Repair: qualified same-module reference emits wrong module / as fn item - #7685

Merged
briansrls merged 2 commits into
mainfrom
session/zesty-carp-424
Aug 2, 2026
Merged

briansrls merged 2 commits into
mainfrom
session/zesty-carp-424

Conversation

@briansrls

@briansrls briansrls commented Aug 2, 2026 •

Copy link
Copy Markdown
Contributor

Auto-opened by session-dashboard for session zesty-carp-424.
Pushing to session/zesty-carp-424 advances this PR.

Worker attestation

  • Title describes the change (not the session id or branch).
  • PR body summarises what and why (replace the TODO below).
  • Tests run: name the command (e.g. npm test, cargo test) and the result.
  • If this closes a work item, the body contains a Closes #N directive. (n/a — internal dashboard node, no GitHub issue)
  • No commits on this branch are surprises (no fork/cherry-pick I did not make).
  • No secrets / credentials / large binaries staged.

Summary

A fully qualified same-module declaration reference used inside a data initializer was emitting against the wrong Rust module, and rendering as a plain function item (foo) instead of a call (foo()). Root cause in emit_var_ref (src/v1/05_emit_rust.dag): a qualified reference (module.leaf) was looked up in the item registry by its full dotted spelling, but the registry is keyed by bare leaf name — so for a same-module qualified reference the lookup missed the intended (correctly-scoped) entry and instead resolved via last-write-wins against whichever module happened to register that leaf name last, and the is_data call-suffix decision fell through to the fn-item (non-call) rendering path. dag/extdeps/container/oci/digest.dag had previously worked around this by respelling the same-module reference as a bare name, leaving a qualified_self_reference_emit_defect_note documenting the dodge.

Fix: emit_var_ref / emit_rust_expr_var now take the current module_name and (1) normalize a self-qualified reference (module_name.leaf where module_name == the emitting module) to its bare spelling before registry lookup, reusing the already-correct bare-name path, and (2) key the general dotted-reference registry lookup on the leaf name rather than the full qualified string, so the is_data call-suffix decision fires correctly for every qualified reference — same-module or cross-module — not just the bare-name case.

The OCI workaround note (qualified_self_reference_emit_defect_note) is deleted: its dissolution trigger — the underlying emitter defect being fixed — has fired. The carrier's spelling in dag/extdeps/container/oci/digest.dag is left as-is (bare reference); only the note documenting the workaround is removed, per the brief (fix the general lowering, not the OCI spelling).

Test plan

New regression witness: dag/test/claim/qualified_declaration_reference_emit_witness_test.dag, with two discriminating fixtures so the fix cannot pass by collapsing both cases together:

  • w_same_module_qualified_reference_emits_call — a same-module qualified reference (qdref_same.qdref_same_base) in a data initializer; asserts the emitted Rust contains qdref_same_base() and does NOT contain qdref_same_base.clone() (the fn-item-as-value symptom).
  • w_cross_module_qualified_reference_emits_call — a genuine cross-module qualified reference (std.emit_on_demand.interpreter_surviving_roles_ceiling); asserts it still resolves to its real declaring module and renders as interpreter_surviving_roles_ceiling(). This is the sibling that proves the same-module fix didn't just special-case self-references at the expense of general dotted resolution.

Commands run and results:

  • cargo run --release -p v1-compiler --bin claim_batch -- --source-root dag --source-root src/v2 --entry dag/test/claim/qualified_declaration_reference_emit_witness_test.dag --functions same_module_qualified_reference_emits_call_not_fn_item,cross_module_qualified_reference_emits_call_from_correct_module — both test fns PASSED by execution (real compile_dag_rust_emit_check compilation against the live corpus, not a mock).
  • cargo run --release -p v1-compiler --bin regen_stage0 -- --verify — regen_divergence_count=0, confirmed twice (fixed point: the .dag source and the generated .rs agree).
  • cargo fmt --all --check — clean (also enforced by the pre-commit/pre-push hooks on every commit).
  • CI run 30761268145 on this PR's head (42ee125) — build, regen, heal_generated_artifacts, and ci (the composed .dag witness/gate floor pass, which discovers and runs the new witness file via the standard dag/test/claim discovery scan) all passed, confirming the fixture executes inside the real regeneration/discovery closure rather than sitting beside it inert.

Not run locally: full cargo test --workspace / cargo clippy --all-targets -- -D warnings. Three genuine attempts (default jobs, reduced jobs, single-crate) all failed with rustc ICEs and sccache spawn failures reproducing even on unrelated trivial upstream crates (unicode-ident, utf8_iter, stable_deref_trait) under heavy host memory/swap pressure — diagnosed as shared-host environment instability, not a regression from this change. CI's build/ci jobs (which do run the equivalent gates on a separate runner) passed, closing this gap.

Scope check against the brief: all six listed items are done — general lowering fixed (not the OCI spelling), same-module + cross-module discriminating fixtures added, correctness proven by execution, fixture sits in the real regen/discovery closure (confirmed via the passing ci CI job), and the OCI workaround note is deleted.

Brian Searls and others added 2 commits August 2, 2026 17:51
The general emit_var_ref lowering keyed its registry lookup on the raw
qualified name instead of the leaf, so a same-module qualified
reference (module.decl) could miss the registry entirely, land on an
unrelated same-named declaration, and render as a bare fn item instead
of a call. Normalize a self-qualified reference to its bare spelling
before lookup, and key the general dotted-reference lookup on the leaf
name so the call-suffix decision fires for both same-module and
cross-module qualified references.

Adds dag/test/claim/qualified_declaration_reference_emit_witness_test.dag
proving correct module selection and call syntax by execution (real
compile via compile_dag_rust_emit_check), with a same-module and a
cross-module fixture so the fix can't pass by collapsing the two
cases. Deletes the now-obsolete qualified_self_reference_emit_defect_note
workaround note in dag/extdeps/container/oci/digest.dag; the OCI
carrier's bare-reference spelling itself is left unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 2, 2026 18:30
@briansrls
briansrls merged commit d14ffd9 into main Aug 2, 2026
5 of 10 checks passed
@briansrls
briansrls deleted the session/zesty-carp-424 branch August 2, 2026 20:08
briansrls pushed a commit that referenced this pull request Aug 2, 2026
…on main (#7705)

Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 2, 2026
Per quiet-hawk-219: containment binding closes pool-membership coincidence
on the RESOLVE path only; emit-side item_registry leaf-key collision
(#7685/#7705) is a separate surviving instance explicitly out of slice.

Co-authored-by: Cursor <cursoragent@cursor.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 2, 2026
#7685 did not repair cross-module same-leaf emit collision; #7705
detector is RED on main (bottom rung). Cite warm-wolf-814 ownership;
name as separate live instance, not guarded. Add PR-B motivation note.

Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls pushed a commit that referenced this pull request Aug 2, 2026
gunbai-bot Bot pushed a commit that referenced this pull request Aug 2, 2026
Per quiet-hawk-219: containment binding closes pool-membership coincidence
on the RESOLVE path only; emit-side item_registry leaf-key collision
(#7685/#7705) is a separate surviving instance explicitly out of slice.

Co-authored-by: Cursor <cursoragent@cursor.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 2, 2026
#7685 did not repair cross-module same-leaf emit collision; #7705
detector is RED on main (bottom rung). Cite warm-wolf-814 ownership;
name as separate live instance, not guarded. Add PR-B motivation note.

Co-authored-by: Cursor <cursoragent@cursor.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 3, 2026
Per quiet-hawk-219: containment binding closes pool-membership coincidence
on the RESOLVE path only; emit-side item_registry leaf-key collision
(#7685/#7705) is a separate surviving instance explicitly out of slice.

Co-authored-by: Cursor <cursoragent@cursor.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 3, 2026
#7685 did not repair cross-module same-leaf emit collision; #7705
detector is RED on main (bottom rung). Cite warm-wolf-814 ownership;
name as separate live instance, not guarded. Add PR-B motivation note.

Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls pushed a commit that referenced this pull request Aug 3, 2026
…er + new witnesses)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
briansrls pushed a commit that referenced this pull request Aug 3, 2026
briansrls pushed a commit that referenced this pull request Aug 3, 2026
* N2 slice 2 PR-A: TypeReferenceBindingContext + P2 input builder

Land the graph-wide OccurrenceBindingCandidateInputs projector and
TypeReferenceBindingContext carrier per quiet-hawk-219 PR-A scope:
containment-tree exposure derivation (RootExposure at module-root,
Module/Lexical otherwise), multi-module merge, and five executing
fixture witnesses. v1 ModuleGraph adapter is a thin PR-B stub only;
no stage0 enrollment and no resolve_node_bounded wiring until 7515.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Document resolve-only path scope for N2 slice-2 claims

Per quiet-hawk-219: containment binding closes pool-membership coincidence
on the RESOLVE path only; emit-side item_registry leaf-key collision
(#7685/#7705) is a separate surviving instance explicitly out of slice.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: regenerate drifted generated artifacts (ci auto-heal)

* Correct emit-side scope: LIVE instance with RED #7705 control

#7685 did not repair cross-module same-leaf emit collision; #7705
detector is RED on main (bottom rung). Cite warm-wolf-814 ownership;
name as separate live instance, not guarded. Add PR-B motivation note.

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: N2 slice 2 (import-deletion program): FIRST TypeReference PRODUCTION con

* Revert premature stage0 regen; defer production stub to PR-B

CI auto-heal pulled std.occurrence_binding* into stage0 before #7515/#7708
fn Clone emit lands — emitted Rust did not compile. PR-A is dag authority +
witnesses only; remove src/v1 production stub that entered regen closure.
Restore stage0 + emit plan to main; regen_stage0 --verify divergence_count=0.

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: N2 slice 2 (import-deletion program): FIRST TypeReference PRODUCTION con

* Fix lexical exposure witness: compare OccurrenceId, not Int.

nested_containment_derives_lexical_exposure_holds compared
scope.terminal.value to an OccurrenceId binding, which always
evaluated false at runtime and failed CI batch 3.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
briansrls pushed a commit that referenced this pull request Aug 3, 2026
* WIP: URGENT: repair post-#7685 leaf-keyed qualified lookup collision on main

* Repair leaf-keyed qualified lookup collision in emit_var_ref

#7685 keyed the flat item_registry on leaf names, so cross-module
qualified references could bind to the wrong module when homonymous
leaves collide. Merge a qualified-name overlay at emit time, route
cross-module lookups through the full normalized spelling, and use
the qualifier prefix as the module-path authority in emit_value_ref_ident.

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: URGENT: repair post-#7685 leaf-keyed qualified lookup collision on main

* WIP: URGENT: repair post-#7685 leaf-keyed qualified lookup collision on main

* Fix cross-module same-leaf data refs and dissolve quarantine

Route is_data value references through emit_value_ref_ident so
cross-module qualified data initializers emit the qualifier module's
crate path instead of a bare homonym leaf. Deletes the #7711 expect-red
enrollment now that cross_module_same_leaf_emits_qualifier_module_not_registry_winner
greens via claim_batch.

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: URGENT: repair post-#7685 leaf-keyed qualified lookup collision on main

* Address #7709 review blockers: cross-kind witnesses and registry-driven emit

- Add cross-kind homonym fixtures (data/fn and fn/data) with reversed import
  order so kind and module binding are proven independent of registry order
- Route qualified rendering through exact registry lookup; refuse missing rows
  and duplicate module.leaf overlay keys via compile_error! at emit sites
- Regenerate stage0 so committed seed matches the updated emitter (regen --verify)

Co-authored-by: Cursor <cursoragent@cursor.com>

* WIP: ci fix

* WIP: ci fix

* Wire duplicate qualified-item marker through emit refuse sites

Correct the marker note to name its real consumers and regenerate stage0 so the seed carries the same DEFINE-AND-CONSUME refuse path as 05_emit_rust.dag (addresses review 47679).

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Brian Searls <briansearls1@gmail.com>
gunbai-bot Bot pushed a commit that referenced this pull request Aug 17, 2026
…raph order

`item_registry` is keyed by BARE leaf name, and the corpus collides on
leaves — the emitter carries its own wall for that class (#7685). So
unioning the scoped modules' registries is not a merge of disjoint maps.
It is a resolution, and something decides it.

The union iterated `modules` — the scope's members in whatever order they
sit in `prepared.graph.modules` — and inserted last-write-wins. That gave
the decision to a fact about the corpus rather than a fact about the
scope. Two scopes with identical members and different precedence would
resolve a collision identically, which is the exact thing `scope_identity`
is folded in order to deny; and a module's own declaration could lose its
own bare name to an unrelated module that merely sorted later.

`order` is the authority that was already sitting three lines below,
under its own note: own module first, then the compiler's
precedence-ordered import closure, then the reference closure, "and order
is exactly what decides which declaration wins a colliding bare name."
The union now walks it and keeps the first write.

WHAT THIS IS NOT: a measured fix for any census class. It was found while
tracing `undefined variable: operator_host_srv1` (111 rows) and it does
not obviously explain that one — the name is specific enough that a
collision is unlikely, and the cause there is still open. It is committed
on its own correctness, not on a claim about the failure count, and the
next full run measures it rather than this message.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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