Skip to content

Native canary: a resolved declaration reference is an arrow body in its own right; eval's well_formed refusal names the ill-formed node - #12377

Merged
gunbai-bot[bot] merged 14 commits into
mainfrom
session/deep-deer-746
Sep 28, 2026
Merged

gunbai-bot[bot] merged 14 commits into
mainfrom
session/deep-deer-746

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Fixes the native v2 route's canary: v2.test.native_lane_smoke native_route_positive_population_smoke (body true) was refused at eval with eval_rejected_invalid_node at bd2c586.

Chain (DESIGN §6b)

  • eval / eval_with_context admit only if well_formed(tree.root) holds over the whole prepared module, so the refusal was never about true: one ill-formed node anywhere refuses every test in the module, anchored at the root.
  • Door probe reaches translate: lower data_decl to a named member and ground it (flip the expecting-red) #12197 lowers data d: D = A to a nullary Arrow whose body is the initializer; Resolver-minted declaration references carry an unauthorable marker; the reader never keys on the spine shape a literal also has #12220 mints the resolved reference as a one-edge Conj under <declaration-reference>.
  • Earliest unjustified boundary: v2.std.node classify_arrow_body_form read every Conj body as RecordConstructBody, whose field gate needs the first edge to target an Atom. The bare spine passed by accident (head → Atom); the marked Conj does not. The smoke module and the control pair's module (v2.native_lane_fixture.control) both carry data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly.
  • Seed-interpreted probe (srv1, 3dd1968): the same test module without the data line passes with no ill-formed node; with it, refused at eval, first ill-formed node Arrow[..., arrow_body_edge -> Conj[<declaration-reference> -> Conj]]. Interpreted and native routes agree.

Change

  • v2.std.node: ArrowBodyForm gains DeclarationReferenceBody, keyed on the marker — so well_formed itself checks shape and label; any other one-edge Conj stays RecordConstructBody and is refused by its gate exactly as before. Structurally admitted; not an eval entry (eval refuses a declaration reference in value position as a binding miss, by design).
  • To make that possible (ruling A on review 71638): the Symbol seam pair symbol_intern_lexeme / symbol_lexeme (host seams, with symbol_lexeme_host_disposition) and declaration_reference_marker move from v2.std.compilers.lexing / v2.std.qualified_name into v2.std.node, beside the Symbol they convert. v2.std.qualified_name imports the marker; nothing re-derives it. Importers re-pointed.
  • Seed — a MOVE, net −1 line (git diff --numstat -- src/v1): the v4_bridge family for both arms is now v2.std.node (gunbc.v1_interpreter_primitive_surface rows → v1_interpreter family block, generated dispatch EvalCallBridgeStdCompilersLexingArm → EvalCallBridgeStdNodeArm, dispatch-authority test); std.primitive_projection and gunbc.symbol_identity_census rows follow. The Rust registry is name-keyed and unchanged.
  • Routed around, not neutral: the seam signatures in v2.std.node name the kernel String unimported instead of std.string_type { String }. Importing std.string_type pulled it into the self-host closure, where its string_lex_compare does not emit (E0308 in the TCO loop, String vs Rc<Vector<i64>>; emit-build at ad31e55). That is the known defect gunbc.recurring_failure_mode accepted_source_emits_uncompilable_target, and the open kernel-String question (XL-0T text ruling, on hold). This PR does not resolve it; it avoids adding std.string_type to the closure.
  • Bare-provider roster: compile_door_ledger.dag#ends_with, and what it resolved to. The interpreter realizes ends_with only as a method (method_call.ends_with); there is no free-function builtin. So the file's free call ends_with(s: p, suffix: ".dag") resolves to the one user declaration, gunbc.rust_item_scan ends_with, at 287bb7f and at 6791886 alike: no rebinding, and that dependency on a gunbc-private helper is exactly the pair the roster carried. The roster went stale at 6791886 (287bb7f had 0 refusals from this gate) because merging main brought Require emitted runtime bodies for every primitive bridge #12389, whose std.primitive_identity imports gunbc.rust_item_scan, putting the provider inside the file's closure (compile_door_ledger → v2.compiler.compile → v2.lens.determinism → std.primitive_identity → gunbc.rust_item_scan): hidden, not fixed. The repair is in the file: it now uses the substrate method p.ends_with(suffix: ".dag"), the std method row, so it no longer depends on the helper, and the ImportsFixed retirement is true on its own terms. (The retirement commit fb131b9's message misattributes the cause to the symbol move; this corrects it.)
  • 05_eval: the gate names the first ill-formed node, not the module root.
  • Reader census (no wildcard added): production readers are v2.std.node (admission => true, eval entry => false) and 05_eval callee dispatch (gated by eval entry). translate/emit do not read ArrowBodyForm; the emitted native eval is the same .dag. Test mirrors in arrow_body_form_semantic_helpers got the arm explicitly.
  • RFM declaration_reference_recognised_by_a_shape_a_literal_also_has: receipt for this second shape-keyed reader, and for the split-law first cut review 71638 caught.

Evidence (srv1, run by neat-boar-16 at 153c6df; 10a6f29 after it only moves one // note to module-item grain)

  • Seed regen: required-regen first_generation_equal=true (161/161 planned, executed, adjudicated); generated-artifact main_wet rc=0 with no drift from the committed dispatch; cargo test --test interpreter_dispatch_authority 2/2.
  • Seed-interpreted (A): arrow_body_form_witness_test 27/27, including arrow_body_form_reference_shape_without_marker_refused_holds (well_formed itself refuses the unmarked shape) and _refused_at_resolve_holds (resolve, a non-eval gate, refuses it); native_decl_selection_test 5/5, including the real-route the_requested_declaration_is_selected_and_evaluated over a fixture carrying a data declaration.
  • Mutation (B) (declaration_reference_body_marked returns false, arm kept = the pre-fix classifier): native_decl_selection_test 4/5, the_requested_declaration_is_selected_and_evaluated FAILS; arrow_body_form_witness_test 24/27, the three reference-admission claims fail, and the two unmarked-refusal claims still pass (the refusal does not depend on the arm).
  • Native (C) (self-host emitted binary): {"module":"v2.test.native_lane_smoke","declaration":"native_route_positive_population_smoke"} → NativeTestPassed. The lane's remaining admission refusal is unattributed_file_refusals_present: 7 pre-existing body_lowering_reason_call_argument_unread files in the smoke's closure, also refused on main; their owner row lands with Native lane: ownership rows for four unowned body-lowering fatal causes #12365.
  • Earlier, at 46445a1 (first cut) and 3dd1968 (diagnosis probes), see the history in this PR's comments.
  • Control pair — NOT yet observed, owed after merge. v2.native_lane_fixture.control (native_lane_false_control / native_lane_true_control) is not in the smoke selection, and I know of no gunbc test selection label that runs it alone: the pair is observed only by the broad native lane's receipt (gunbc.witness_v2_native_route native_route_live_pair_standing = LivePairRequired). neat-boar-16 will observe it in the broad native rerun after merge and report it. Expected: ReturnedFalse / Passed, since its module's only ill-formed node was the same data live_tree_disposition body this PR admits.

Heads: diagnosis probes at 3dd1968; (A), (B) and (C) all at 46445a1 (the RFM receipt commit after it touches only dag/gunbc/recurring_failure_mode/).

🤖 Generated with Claude Code

gunbc-ci-auto-heal and others added 2 commits September 26, 2026 21:25
…ts own right; eval's well_formed refusal names the ill-formed node

data d: D = A lowers (#12197) to a nullary Arrow whose body is the initializer, and resolve mints
the reference (#12220) as a one-edge Conj under the <declaration-reference> marker. v2.std.node
classify_arrow_body_form read every Conj body as a record construct, whose field gate refuses a
first edge that does not target an Atom, so every module holding such a declaration failed
well_formed and eval refused all of its tests: v2.test.native_lane_smoke (body 'true') and the
live control pair's module, both of which carry data live_tree_disposition = SubstrateInputsOnly.

- v2.std.node: ArrowBodyForm gains DeclarationReferenceBody. node.dag owns the SHAPE (one Named edge
  over a Conj, disjoint from a construct whose tag edge targets an Atom); structurally admitted;
  not an eval entry (eval refuses a declaration reference in value position as a binding miss).
- v2.std.qualified_name declaration_reference_body_label_conforms: the LABEL half (node.dag cannot
  intern the marker), the #12240 type_binder precedent.
- 05_eval: the well_formed gate names the first node failing either half instead of the module
  root, which is why the canary's refusal located nothing.
- Controls: arrow_body_form_witness (classification, well_formed, the record-construct mutation
  mirror refuses, reference shape under an authored label refused, not an eval entry);
  native_decl_selection's fixture now carries a data declaration so the real route's
  the_requested_declaration_is_selected_and_evaluated exercises it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…he second shape-keyed reader (ArrowBodyForm), the native canary receipt

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review September 26, 2026 22:19
@gunbai-bot

gunbai-bot Bot commented Sep 26, 2026

Copy link
Copy Markdown
Contributor Author

Review 71638 is correct, verified against the head: declaration_reference_body_label_conforms has one production caller (05_eval's gate). The other production well_formed gates (03_name_resolve, 03_resolve, 03_normalize, 03_body_producer, 02_parse, 04_infer, 06_translate, program_partition, ingested_fixture_arrows, and the std predicates) now admit an unmarked one-field record over a record that the record-construct gate used to refuse, and the comment in v2.std.qualified_name claiming otherwise is false. That is a silent widening, not an admissible interim.

Patching each gate with a second predicate would reproduce the fork, since v2.std.node well_formed would stay the obvious function a new caller reaches for. The repair I've proposed to the v2 foundation manager: re-home the marker's interning at or below v2.std.node, so well_formed itself checks the label and there is one admission predicate. That moves symbol_intern_lexeme's bridge, which the seed dispatch and extdeps.languages.rust.emit rt_function_registry key to v2.std.compilers.lexing. I'm waiting on that ruling before pushing; the PR should not merge at this head.

— sent from deep-deer-746

…l seam pair moves into v2.std.node (review 71638)

Review 71638 (REQUEST_CHANGES, valid): the marker half of DeclarationReferenceBody ran only beside
eval's gate, so every other production well_formed gate (name_resolve, resolve, normalize,
body_producer, parse, infer, translate, program_partition, ...) admitted an unmarked one-field
record over a record that the record-construct gate used to refuse -- a silent widening.

Ruling A (v2 foundation manager): one authority, no second predicate.
- v2.std.node now declares symbol_intern_lexeme / symbol_lexeme (host seams, with
  symbol_lexeme_host_disposition) beside the Symbol they convert, and declaration_reference_marker.
  classify_arrow_body_form keys DeclarationReferenceBody on the marker; any other one-edge Conj
  stays a record construct and is refused by its gate as before.
- v2.std.qualified_name: declaration_reference_body_label_conforms deleted; the marker is imported,
  not re-derived. 05_eval's gate is back to locally_well_formed alone (still names the first
  ill-formed node).
- v2.std.compilers.lexing no longer declares the pair; 60+ importers re-pointed to v2.std.node.
- Seed, a MOVE (net -1 line): the v4_bridge family for both arms is now v2.std.node
  (gunbc.v1_interpreter_primitive_surface rows, v1_interpreter family block, generated dispatch,
  dispatch-authority test); std.primitive_projection and gunbc.symbol_identity_census rows follow.
  The Rust registry is name-keyed and unchanged.
- Control: arrow_body_form_reference_shape_without_marker_refused_holds now asserts well_formed
  itself refuses it; _refused_at_resolve_holds shows resolve (not eval) refusing it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Sep 26, 2026

Copy link
Copy Markdown
Contributor Author

Addressed review 71638 in ad31e55, under the v2 foundation manager's ruling A: the marker now lives in v2.std.node (with the symbol_intern_lexeme / symbol_lexeme seam pair it needs, moved from v2.std.compilers.lexing), and classify_arrow_body_form keys DeclarationReferenceBody on it. So well_formed itself checks shape and label, and every gate that admits by well_formed refuses the unmarked one-field record over a record, as it did before this PR. The second predicate in v2.std.qualified_name is deleted, and the false comment with it. New controls: arrow_body_form_reference_shape_without_marker_refused_holds asserts well_formed refuses it, and arrow_body_form_reference_shape_without_marker_refused_at_resolve_holds shows resolve (a non-eval gate) refusing it. The seed side is a move, net -1 line. srv1 reruns and the mirror fixed point are pending.

— sent from deep-deer-746

gunbc-ci-auto-heal and others added 7 commits September 26, 2026 23:16
…type (emit-build: it pulled std.string_type's unemittable string_lex_compare into the compiler closure)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ct_demand's seam rows to v2.std.node

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…; the annotation-channel test hands lex_walk_artifact chars(s:)

Both files are touched only by the symbol-seam import move, so the floor's touched-file gate checked
them whole and refused two pre-existing findings:
- v2.lens.schedule_lens used plan.schedule.first() / stage.first() as a value behind count guards.
  Each site now matches the Optional; Absent answers the verdict the guard already gave
  (EmptySchedule / SingleBatchOnly / no duplicate), never a fabricated batch.
- gunbc.test.claim.dag_line_comment_annotation_channel_test passed a kernel String where
  lex_walk_artifact takes v2.std.text.String; it now converts with chars(s:), as every other caller does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…tem annotation grain, DESIGN 4c)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… disposition control names v2.std.node

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	src/v2/compiler/body_lowering_fold.dag
#	src/v2/extdeps/languages/dag.dag
gunbc-ci-auto-heal and others added 4 commits September 27, 2026 19:32
# Conflicts:
#	src/v2/compiler/body_lowering_fold.dag
…sFixed (floor RosterStale after the symbol import moved to v2.std.node)

The floor's gate derived that src/v2/workflow/compile_door_ledger.dag no longer carries the pair
once its import of symbol_intern_lexeme moved from v2.std.compilers.lexing to v2.std.node, and
named the one admitted move. The gate re-derives the file and refuses the row as
RetiredImportsFixedButCarried if the claim is false.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…t gunbc.rust_item_scan's helper

The free call ends_with(s:, suffix:) has no substrate provider (the interpreter realizes ends_with
only as method_call.ends_with), so at every head it bound to the one user declaration,
gunbc.rust_item_scan ends_with -- the pair the bare-provider roster carried. #12389 put that module
into this file's closure through std.primitive_identity, which hid the dependency without changing
it. The method form p.ends_with(suffix:) is the std method row, so this v2 compiler file no longer
depends on a gunbc-private helper and the roster's ImportsFixed retirement is true on its own terms.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… symbol_lexeme stays on v2.std.node)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Verdict: APPROVE d6c4098

No blocking finding. DeclarationReferenceBody is recognized by the one reserved declaration-reference marker in v2.std.node, consumed by both the qualified-name producer and the shared arrow-body classifier. It is not inferred from an arbitrary one-edge Conj shape. Unmarked records retain their existing classification/refusal, the marked reference is not an eval entry, and recursive node well-formedness still checks its payload.

The Symbol host-seam pair is moved rather than duplicated: imports, primitive projection, dispatch and census identities follow the node authority. The seed change is disclosed and directly serves the v2 native/self-host route. The kernel-String choice and the deferred text/emitter issue are explicitly bounded, not represented as a completed text migration.

The eval gate preserves the same locally_well_formed predicate and fold as well_formed, carrying the first offending node instead of only a Boolean. Both eval and eval_with_context consume the shared reader; no root-level admission is weakened to make the canary pass.

I inspected the source and recorded evidence: the marker-disable mutation turns the real declaration-selection route red while the unmarked-refusal controls stay green; the emitted native canary has an explicitly reported NativeTestPassed. All five jobs in exact-head run 36361393247 succeeded. The broad native lane and its live true/false pair remain separate post-integration observations; this approval does not claim those have qualified. I did not rerun tests locally.

Approval is bound to this SHA. A later main merge or conflict repair requires an exact-head delta re-review.

@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Sep 28, 2026
Merged via the queue into main with commit 02360ee Sep 28, 2026
6 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/deep-deer-746 branch September 28, 2026 13:06
gunbai-bot Bot pushed a commit that referenced this pull request Oct 1, 2026
… also re-admit the deleted-lane countable); keep only the #12377 seam-home claim

#12377 moved the Symbol seam pair from v2.std.compilers.lexing into
v2.std.node and re-pointed effect_demand's seam rows; the roster is right
and floor_join_witness_live_seam_modules_are_the_fourteen_seams_homes
expected the old home.

Co-Authored-By: Claude Opus 5.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