Repository navigation
Native diagnostics through the result boundary: the verdict carries the located chain, ambiguity names its lookup class and competing declarations - #11965
Merged
Conversation
…he failing stage's located chain, ambiguity names its lookup class and competing declarations
The native test route's refused verdict was `NativeTestRefused { stage, reason: Symbol }`,
filled everywhere by folding the failing stage's NonEmptyDiagnostics to its last reason. The
stage had computed a located, typed cause (v2.std.diagnostic Diagnostic: reason, locus,
correction) and the boundary kept one field of it, so every persisted population row and every
line the operator read said WHAT refused and could not say WHERE. One seam earlier the resolver
did the same to itself: `SymbolIndexAtomAmbiguous` was a bare variant standing where the lookup
had answered `LexicalAmbiguous { candidates }`, so an ambiguous reference reported one symbol
while the resolver had known which lookup was ambiguous and which declarations competed.
Subject: the NativeRouteMemberRow the native lane persists and the operator line beside it.
Implementation boundary: v2.compiler.native_test_vocabulary NativeTestVerdict (refused arm now
carries the stage's NonEmptyDiagnostics; reason is DERIVED at the consumer through the new
v2.std.diagnostic diagnostics_fatal_reason, which also dissolves the two per-consumer spellings of
"the fatal is the last" in the CLI and the compile fold); v2.compiler.resolve
AmbiguousLookupClass (lexical chain with candidates / global bare / qualified head shadowing an
absolute hit) carried as class + competing-declaration diagnostics in front of the fatal;
v2.std.diagnostic Locus gains DeclarationLocus { declaration: QualifiedName } -- DESIGN section
3's cite-the-symbol form, which the corpus had faked by putting a module QN into a Textual file
-- so a competing binder is named by identity rather than dragged in as its body node; the
emitted eval driver prints one `[native-verdict]` stderr line per non-passing row, rendered by
gunbc.witness_v2_native_route native_route_member_row_text; lens_verdict renders a NodeLocus as
its occurrence identity instead of "<node locus, no file>".
Positive control and failure controls: v2.test.claim.native_route.native_refusal_detail, six
claims over supplied sources through the real native_test_context_from_ingest and
native_lane_module_resolution fold (warm producer enrolled). Mutation A (resolver folds the
ambiguity back to a singleton) reds exactly the three ambiguity claims; mutation B (the verdict
boundary folds back to the reason) reds all five detail claims; the pre-existing reason-only
walls stay green under both, which is the measurement that they never covered the detail.
Disposition: `native_test_fatal_reason` and `cli_fatal_diagnostic` deleted in favour of the std
fold; the reason-only verdict arm has no constructor left (native_test_refused_located demands a
locus). Declared remainder: NativeTestFileRefusal (Context-stage rows) keeps head/fatal reasons
because the seed host runner's TSV decoder reads that shape; and a node-anchored fatal renders
its occurrence but not a file, because the parse SpanIndex is dropped before normalize and
occurrence ids are per-file -- rostered in the new recurring_failure_mode row.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… wearing the advisory's name The built CLI's specimen read `infer_grounding_not_derived x35 | FATAL AT <node locus, no file>`. The last-link pick was choosing the refusing link -- but that link was spelled with the ADVISORY's symbol: canonical_grounding_from_inferred_facts (v2.compiler.infer) and translate's grounding gate both REFUSED with `infer_grounding_not_derived`, the symbol infer carries as a frontier advisory on its Accepted path (review 46789 routed the gate through the shared fn so it would). One name, two contracts (DESIGN section 3), so no reader of the chain could tell the refusal from the rows in front of it; eval's gate had already drawn the line with its own reason. - root: canonical_grounding_from_inferred_facts refuses with infer_grounding_demanded_not_derived (coercion and translate's coerce fold reach it) -- the earliest unjustified boundary; - translate's gate refuses with translate_rejected_grounding_not_derived, mirroring eval; - v2.cli.compile_cli's CliRunRefused.reason was d.head.reason -- the first pending advisory, the grammar-global overlap residue on every broken entry -- and is now the fatal; its chain renders each link located (lens_verdict_diagnostics_located_chain_text; cli_diagnostic_chain deleted); - both new reasons owned at FatalGrain in compile_door_cause_ownership. Controls: v2.test.cli.v2_native_cli runs the real v2_cli_run over a supplied two-file ingest whose second file leaves tokens after its module -- reason == parse_g0_tokens_remain with the overlap advisory in front, detail `FATAL AT <compilation unit> bytes ...` (warm producer enrolled); translate_underived_refusal_test asserts the fatal is translate's own AND is not the advisory; infer_self_grounding_wall_test and ingest_bridge_test retarget from head to fatal under the root's name. Head-reason claims on paths where a real infer runs in front stay green -- there the head is the advisory. Recurring-failure-mode row extended with this receipt. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
briansrls
added this pull request to the merge queue
Sep 21, 2026
Contributor
Author
|
Side-chat review approved merging this head (67ac2bb) as an increment. That approval is under the operator's delegation. Pkg2 stays OPEN for native qualification: the emitted driver must preserve a located refusal, an advisory before the fatal, and an ambiguity naming the competing declarations. Note: the witness-floor job 106378500935 declined its phases (the dependency pool did not resolve), so its green is not counted as coverage for this change. |
gunbai-bot Bot
pushed a commit
that referenced
this pull request
Sep 21, 2026
…used assembly Reconciles with #11965 (merged) and addresses review 69607. - lens_verdict: ONE `match d.at`. The index-free door is now a projection of the index-taking one with an empty index, so the two cannot disagree about a locus -- there is only one set of arms. #11965's lens_verdict_node_occurrence_text stays the single answer for every case the index cannot resolve, and is called rather than restated. Its own note said resolving the ordinal "needs that graph's SpanIndex, which the stages past parse do not carry"; program_assembly now carries it, so this is that sentence's other half and not a second renderer. - review 69607 finding 1: the refused arm returned an empty index while the annotation above it claimed the opposite -- prose asserting behavior the code did not have (DESIGN 4c). Fixed functionally, not by trimming the prose: ProgramAssemblyLocatedFoldFailed carries spans, and the per-read result carries them across its own refusal, so a file that parsed and then failed to normalize or graft stays locatable. That is the arm where the occurrence carry matters most. A grammar refusal reports empty honestly -- nothing was parsed. - review 69607 finding 2: attribution_assembly() had no caller. Deleted. The whole chain is now located per link, each with its own span: infer_grounding_not_derived @ fixtures/native_cli_door/door_probe.dag bytes 89..90 -> ... -> FATAL AT fixtures/native_cli_door/door_probe.dag bytes 0..6 The earlier mangled rendering was the probe supplying a caret literal where the emitted main supplies `path.clone()`; the claim now interns the path, as production does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Subject
The row the native test route persists for a refused identity, and the line the operator reads beside it. Before this change a refused row was
{identity, verdict: NativeTestRefused { stage, reason }}— one symbol copied out of a located, typed cause the failing stage had already computed. The persisted output, the admission authority and the operator command all read that symbol; none could say where.Implementation boundary
v2.compiler.native_test_vocabularyNativeTestVerdict— the refused arm carries the stage'sNonEmptyDiagnosticsunfolded (the same stancenative_module_resolve_verdictalready takes at the census grain). The reason every roster keys on is derived at the consumer, so admission verdicts do not change.v2.std.diagnosticdiagnostics_fatal/diagnostics_fatal_reason— "the fatal is the last diagnostic" is created byrejected_with_pendingand was spelled twice by consumers (cli_fatal_diagnostic,native_test_fatal_reason). Hoisted to the home that creates the ordering; both consumer spellings deleted.v2.compiler.resolveAmbiguousLookupClass—SymbolIndexAtomAmbiguouswas a bare variant standing where the lookup had answeredLexicalAmbiguous { candidates }. It now carries which lookup was ambiguous (lexical chain / global bare / qualified head shadowing an absolute hit), andambiguous_symbol_diagnosticsemits the class row and oneresolve_ambiguous_competing_declarationrow per binder in front of the unchanged fatalresolve_reason_ambiguous_symbol. "Where available" is honest: the global-bare index collapsed its binders at fill time, so that class names itself and carries zero candidates rather than a fabricated list.v2.std.diagnosticLocusgainsDeclarationLocus { declaration: QualifiedName }— DESIGN §3's cite-the-symbol form. The corpus faked it (resolve_module_not_foundputs a module QN into aTextual.file); a competing binder is now named by identity rather than dragged in as its declaration node (which is its whole body, and would size every persisted row by the binder). All exhaustiveLocusmatches extended; the frontier probe's serializable projection gainsCauseLocationDeclaration.v2.std.lens_verdict— aNodeLocusrenders as its occurrence identity (<node occurrence #N>) instead of<node locus, no file>; newlens_verdict_diagnostics_located_chain_textrenders each link located.v1.compiler.emit_rustemit_source_root_eval_driver_main_rs) prints one[native-verdict]stderr line per non-passing row beside the JSON it persists, rendered bygunbc.witness_v2_native_routenative_route_member_row_text; the seed runner already relays that stderr. Declared on the driver contract instd.compiler_entry. The stage0 mirror was regenerated by the documented recipe (claim_executor --required-regen, first pass) and the delta is exactly the template insertion — the two other drifts the regen reports (std_integer.rs,gunbc_cli_dispatch_surface.rs) pre-exist on main and are not installed here.DeclarationLocus(<module>.<decl>);native_test_refused_locatedis the only reason-first constructor and it demands a locus.The fatal pick, and why the specimen's fatal LOOKED like an advisory (manager direction, 2026-09-21)
The built CLI's specimen read
infer_grounding_not_derived ×35 | FATAL AT <node locus, no file>. The last-link pick (#11507) was choosing the refusing link — but that link was spelled with the advisory's name:canonical_grounding_from_inferred_facts(04_infer) and translate's grounding gate both refused withinfer_grounding_not_derived, the same symbol infer carries as a frontier advisory on its Accepted path (review 46789 did that on purpose). One name, two contracts — a §3 meaning fork — so no reader of the flat chain could tell the refusal from the rows riding in front of it. eval's gate had already drawn the line (eval_rejected_grounding_not_derived).canonical_grounding_from_inferred_factsnow refuses withinfer_grounding_demanded_not_derived(the earliest unjustified boundary; coercion and translate's coerce fold reach it).translate_rejected_grounding_not_derived, mirroring eval.CliRunRefused.reasonwasd.head.reason— the first pending advisory (the grammar-global overlap residue, identical on every broken entry). It is nowdiagnostics_fatal_reason.FatalGrainincompile_door_cause_ownership(the former population was counted under the advisory's row).Controls:
v2.test.cli.v2_native_clia_trailing_token_refusal_names_the_refusing_link_as_its_reason_holds(supplied two-file ingest through the realv2_cli_run; reason ==parse_g0_tokens_remain, with the overlap-residue advisory in front) and…_locates_its_fatal_in_the_file_holds(FATAL AT <compilation unit> bytes …);translate_underived_refusal_testtranslate_refused_canonical_groundingasserts the fatal is translate's own and is not the advisory;infer_self_grounding_wall_test/ingest_bridge_testretargeted from the head to the fatal with the root's new name. The claims that assertd.head.reason == infer_grounding_not_derivedon paths where a real infer runs in front (cross-language compile, compile Eval mode) stay green — there the head really is the advisory.Positive control
v2.test.claim.native_route.native_refusal_detail— six claims over supplied sources reaching the realnative_test_context_from_ingest→native_lane_module_resolutionfold (the producer of the persisted rows), warm producerndp_resolutionsenrolled infloor_cross_claim_pure_producers_warm:unbound_reference_row_locates_its_source_occurrence_holds— fatal reason + a minted node occurrenceshadowed_reference_row_names_lookup_class_and_both_competing_declarations_holds— lexical class + both binders onDeclarationLocus, exactly twoglobal_bare_collision_row_names_its_lookup_class_without_fabricating_candidates_holdsoperator_line_names_subject_stage_cause_and_competing_declaration_holds— the consumer-level control overnative_route_member_row_textoperator_line_renders_the_source_occurrence_holdsclean_module_resolves_holds— the denominator10/10 PASS locally (these six plus the four touched existing witnesses) via
claim_batch; the fatal-pick claims and every retargeted witness PASS at the current head (see the commit list).Failure / mutation controls (executed)
ambiguous_symbol_diagnosticsreturns the fatal singleton (drops class + candidates): the three ambiguity claims go FAIL, everything else PASS.native_lane_module_resolutionfolds the verdict back toreasonwith a port locus: all five detail claims go FAIL;clean_module_resolves_holdsand the pre-existing walls PASS.namespace_only_policy_chain_shadow_ambiguous_refuses_holdsandshared_root_validation_refusal_stays_at_prepare_for_each_identitystay green — the measurement that the pre-existing walls read only the reason and never covered the detail.Exact-head handback
the branch head (final sha in the last commit). Interpreted evidence is at this head; the
[native-verdict]driver line is prepared, not qualified — the native lane is a declared rung drop until Pkg1 restores native artifact production, and a run of the built driver is the qualification this PR cannot perform.Disposition of what it replaces
NativeTestRefused.reasondeleted;native_test_fatal_reason,cli_fatal_diagnosticdeleted in favour ofv2.std.diagnostic diagnostics_fatal(_reason).native_test_observation_refusednow takes diagnostics; supplied-verdict tests usenative_test_refused_located.gunbc.recurring_failure_mode.located_cause_folded_to_its_reason_at_a_result_boundary(receipts: gunbc#11507's CLI, this route; next-rung trigger named).Named remainders
NativeTestFileRefusal(Context-stage rows) keepshead_reason/fatal_reasononly, although front-end diagnostics carry the most actionable loci (Textualfile + byte range). Widening it is a change to the seed host runner's TSV decoder as well; Context rows are located atTextual { file, WholeFile }for now.FATAL AT <node locus, no file>withinfer_grounding_not_derived×35 — after this change it readsFATAL AT <node occurrence #N>and the chain renders each link's occurrence. A file is not derivable at that boundary: the parseSpanIndex(occurrence → file+extent) is dropped insideprogram_assemblybefore normalize, and occurrence ids are allocated per file from 0, so an id cannot be joined to a file inside a grafted tree. Attributing by searching the tree for an equal node would be a plausible guess, not a fact (§5). Trigger: carry the per-fileSpanIndex(or ingest-unique occurrence ids viaOccurrenceIdAllocator's min-next seeding) through normalize/resolve on the context, so the renderer's join is a lookup. That is aprogram_assemblychange and its own package.resolve_module_not_found's QN-as-Textual.fileencoding is left in place; it now has a home to migrate to.Ownership vs. the original session's PRs
Checked against #11919 (native-route universe selection) and #11952 (eval driver verb/plan surface): no hunk overlap. All three touch
src/v1/05_emit_rust.dagin different regions; the one-line stage0 mirror will need a regen round after whichever lands second.🤖 Generated with Claude Code