Repository navigation
Refuse an ambiguous bare-name read in the v1 evaluator: the wall, its fixture-authored RED, and the variant-arm tier - #11166
Conversation
NOT READY TO PUSH. The detector is complete and the refusal is written; what is missing is executable controls. THE THIRD TIER. `PreparedScopeIndexes::site_resolved_fn` answered over `fn_nodes`, which is built by walking `module.items` -- top-level declarations only. A variant ARM is not a top-level item, so a bare read of one matched neither tier and was reported as falling through to the shared slot even when the arm's coproduct is declared in the reading module itself or imported by name. Measured: five such sites in the corpus census. `variant_arm_owners` indexes arm name -> (declaring module, COPRODUCT). Keyed on the coproduct and not merely the module, because the question is "does EXACTLY ONE coproduct visible to this site declare this arm" -- a module-only key cannot tell one coproduct from two in the same module and would resolve a genuinely ambiguous arm read to whichever matched first, silencing the class the refusal exists to catch. The tier is deliberately stricter than the two above it: those let the site's own module win unconditionally, which they can because a top-level declaration in one's own module is the authored answer by construction, whereas arms carry no such precedence rule. Not a new error class: an instance of `gunbc.recurring_failure_mode.binding_chosen_by_pool_membership_rather_than_by_the_declared_rule`, whose root sentence is this same asymmetry -- a coproduct arm is pool-visible corpus-wide while not being a local binding under its own spelling. THE REFUSAL sits in `claim_scope_for`, keyed on `ambiguous_reads` -- the same binding `required_floor_runner` prints its census lines from, so detector and count cannot drift. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
…rable The bare-name-ambiguity refusal lives in `claim_scope_for`. Nothing that CI executes could reach it: `tools.multi_module_compile_fixture` stops at `compile_to_resolved` and never builds a scope, a corpus module authored to carry an ambiguous read would refuse the whole floor rather than sit in it as a probe, and `src/v1/stage0/tests/` is compiled by clippy and run by nobody (`gunbc.rung_drop` `rust_unit_tests_off_the_merge_path`). A wall landed on those routes would have had a positive control that runs and a discriminating RED that does not -- DESIGN §4b's permanently-green- by-construction, which is worse than absent because it gets cited as coverage. §4b also names the remedy: a state unrepresentable in the ACCEPTED corpus may still be representable as source handed to the compiler by a FIXTURE, and a compiler is precisely a thing whose regression probes are invalid programs. So the fixture instrument gains a second question. `claim_scope_fixture` takes the same authored manifest and an entry MODULE PATH, and reports what the scope builder said: `ClaimScopeInstrumentRefused`, `ClaimScopeCompileRefused`, `ClaimScopeRefused`, `ClaimScopeAccepted`. ONE DETECTOR, NOT TWO. The host function runs `claim_scope_for_without_memos` itself. It does not re-derive the ambiguity population, so the refusal a control observes IS the refusal the corpus floor raises, out of the same `ambiguous_reads` vector the census lines are printed from. A second computation here -- even a faithful one -- would be the second authority the census exists to prevent, and would be free to drift from it silently. `without_memos` is the only difference from the floor's own call, and it is a caching decision rather than a semantic one: the memoized entry point caches fragments on a process-shared index keyed for the real corpus, which a fixture must neither read nor write. NO CORPUS ROOT IS READ. `PreparedRepository` is built entirely from the manifest -- the graph from `compile_to_resolved`, the indices from `dag_graph_source_indices`, empty `full_inventory` and `discovery_exclusions` because a fixture has no discovery step. The subject stays fully under the calling test's control. Both readers are written as MATCHES over the outcome, never as accessors, so `ClaimScopeInstrumentRefused` and `ClaimScopeCompileRefused` read false on BOTH polarities: a ragged manifest fails the positive and the negative control together, which is the signature of a broken probe, rather than silently satisfying whichever one was phrased as an absence. The builtin is declared where builtins are declared, not bolted on: a dispatch arm in `gunbc.v1.v1_interpreter_primitive_surface`, a nested- compile reach row in `gunbc.v1.v1_interpreter_opaque_host_call`, and a signature in `src/v1/04_method.dag`. The three Rust mirrors of those are regenerated artifacts and are updated to match. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
…est) `claim_scope_for_without_memos` is behind `cfg(any(test, feature = "interp_test_witness"))`, so a release build has no such function and this instrument has to run in one. The call is now `claim_scope_for_with_memos(&prepared, entry, None, build_scope_order_index(&prepared))` -- the same function the floor's own entry point calls, with the memos withheld, so the single-detector property is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
`data <name>: String =` with the literal on the FOLLOWING line does not parse: `expected expression, found Newline`. The three "source annotation names no subject" errors reported alongside it were downstream of the same break -- once a declaration fails to parse, the annotation block above it names nothing -- rather than three separate defects. Caught twice, by CI's parse phase on this branch and by running the five controls directly; both name the same file and position. Worth recording because of how it could have read: the remote dispatch that ran the controls EXITED 0 while all five failed to parse, since the build's exit status was consumed by a pipeline. A report taken from the exit code would have announced five working controls that never ran. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
…first The required floor on this branch refused with the wall's own words -- `16 ambiguous bare-name read(s) refused` for the scope `v2.test.execution.emit_on_demand_match_loop_fold_family_witness`. That is the refusal WORKING, not failing: the corpus still carries 82 measured ambiguous reads because the qualification batches have not merged, so a wall landed now refuses the tree it is meant to protect. Weakening it to make the lane green would invert the whole point, so the wall comes out of this branch and lands on top of the qualifications instead. WHAT STAYS, and it is the part that has to exist before the wall can be proven at all: - THE THIRD RESOLUTION TIER. `fn_nodes` is built from `module.items`, so it holds top-level declarations only and no variant ARM is reachable through either existing tier. `variant_arm_owners` indexes arm name -> (declaring module, COPRODUCT) and resolves only when EXACTLY ONE visible coproduct declares the arm; two visible coproducts stay ambiguous, because nothing the author wrote ranks them. Keyed on the coproduct rather than the module so one coproduct and two in the same module are distinguishable -- a module-only key would resolve a genuinely ambiguous arm read to whichever matched first. - THE FIXTURE CLAIM SCOPE. `claim_scope_fixture` builds a real claim scope over a caller-authored manifest by calling `claim_scope_for_with_memos` itself, so a refusal a control observes IS the refusal the corpus floor raises rather than a second copy of the logic. `PreparedRepository` is built entirely from the manifest and no corpus root is read. THE TWO CONTROLS ARE RUN, NOT DESCRIBED, and they are about THIS instrument rather than about any wall -- a control for a wall belongs with the wall. a_well_formed_manifest_builds_a_claim_scope -> true an_entry_outside_the_subject_reaches_the_caller_as_a_scope_refusal -> true The two manifests are identical and differ by exactly one string, the entry MODULE PATH, so the only variable is the scope builder's verdict. AND THE RED IS PINNED TO ITS CAUSE. `claim_scope_was_refused` says only that SOMETHING refused, which would go green the day an unrelated refusal started firing first and would then be cited as coverage for a cause it never observed. `claim_scope_refusal_names` matches the arm AND requires the cause to name `EntryModuleOutsidePreparedSubject`. Falsified rather than assumed: pointing the marker at a string the refusal does not contain turns that row `false`, so the predicate is reading the cause and not merely the arm. `ClaimScopeInstrumentRefused` and `ClaimScopeCompileRefused` read false on both polarities, so a ragged manifest fails the positive and the negative row together instead of satisfying whichever was phrased as an absence. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
The first revision of this instrument mapped EVERY `Err` from `claim_scope_for` into `ClaimScopeRefused`. That made a refusal about the HOST PROCESS indistinguishable from a refusal about the SUBJECT -- the not-applicable-versus-malformed conflation this outcome type exists to prevent, built into the type's own producer. It is not a theoretical gap. `claim_scope_for_with_memos` reaches `reference_closure_index`, which is memoized in a `thread_local!` keyed by `subject_digest` and bounded at `FLOOR_PREPARED_SUBJECTS_PER_PROCESS`, where a subject beyond that population is refused. The required floor already holds both slots: the corpus subject, and the `policy_prepared` subject built for `REQUIRED_FLOOR_POLICY_MODULE`. A fixture is therefore the third subject and is refused -- for a reason that says nothing whatever about the manifest. MEASURED on gunbc#11143's floor, and the shape of the evidence is the point: the POSITIVE control returned false while the NEGATIVE one PASSED, the inverse of both passing locally. The memo is thread-local and the floor evaluates claims across several workers, so the verdict depended on which worker picked the claim up. And because the floor prints the claim's Bool rather than the cause, the instrument could not report its own failure mode -- the real reason sat in a `cause` field nothing reads. That is what the conflation costs: not a wrong label, an undiagnosable one. TWO FIXES, both wrong on their own terms before this: - The bounded resource is now ACQUIRED FIRST, and its refusal returns `ClaimScopeInstrumentRefused` naming the host process's caches. The readers already treat that arm as false on BOTH polarities, so a process that cannot host the fixture fails the positive and the negative control together rather than reporting a scope refusal that never happened. - `subject_digest` was `String::new()`. In a digest-keyed memo an empty key is not merely uninformative: every fixture collides with every other fixture and with anything else leaving the field blank, and a scope can consume an index built from a different graph. It is now derived from the manifest through the same `multi_module_fixture_source_digest` the compile instrument uses. WHAT THIS DOES NOT FIX, stated so it is not mistaken for the whole repair: the fixture still CONSUMES one of the bounded per-subject slots, so it still competes with the corpus and policy subjects. Removing the competition needs a non-registering construction path and lands separately; raising the cap is explicitly not the answer, because that wall is a stated production cost limit and widening it to fit a test instrument is the test dictating production limits. EVIDENCE. Both controls still return true against a binary built with the real digest, so the memo still resolves the scope it is keyed for: a_well_formed_manifest_builds_a_claim_scope -> true an_entry_outside_the_subject_reaches_the_caller_as_a_scope_refusal -> true The `ClaimScopeInstrumentRefused` arm's own red is NOT authorable locally: it needs a process already holding two distinct subjects, which a single `gunbc run` does not. Its discriminating evidence comes from the floor, and is not claimed here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
The instrument still COMPETED with the floor for a bounded resource after the previous commit classified that competition honestly. This removes it. `reference_closure_index` is a `thread_local!` memo keyed by `subject_digest` and bounded at `FLOOR_PREPARED_SUBJECTS_PER_PROCESS`, where a subject beyond that population is refused. The required floor already holds both slots -- the corpus subject and the `policy_prepared` subject built for `REQUIRED_FLOOR_POLICY_MODULE` -- so a fixture going through the cache is the third subject and is refused, for a reason that says nothing about the manifest. THE SPLIT. `build_reference_closure_index` is the body `reference_closure_index` always ran, lifted out of the cache around it. `reference_closure_index` is now that build plus the bounded memo, and its behaviour is unchanged. `claim_scope_for_with_memos` gains one parameter, `reference_index: Option<Rc<ReferenceClosureIndex>>`, where `None` is exactly today's path. BOTH PRODUCTION CALL SITES PASS `None`, so the corpus subject and the policy subject observe nothing new. `Some(index)` is for a caller that has built the index for its own subject and must not occupy a slot. The fixture is one module and is discarded immediately; registering it would spend one of a bounded population on a throwaway and refuse the next real subject. RAISING THE BOUND IS NOT THE REMEDY. It is a stated production cost wall, and widening it so a test instrument fits is the instrument dictating production limits -- the absorbing fallback in a convenience costume. A DISTINCTION THE SPLIT MADE VISIBLE. The extracted build keeps its OWN refusal, `ExprVarReconciliationMismatch`, where a traversed occurrence landed in no member. That one IS about the supplied graph, so the fixture reports it as a scope refusal while the budget refusal is an instrument refusal. Before the split the two were indistinguishable -- and both carry the same `CLAIM-SCOPE REFUSAL cause=` prefix, so no text discriminator would have separated them either. THE NEW CONTROL, and what it is and is not evidence of. `several_distinct_fixture_subjects_all_resolve` builds FIVE distinct fixture subjects. Five rather than three deliberately: the row must fail if the fixture occupies even ONE slot, because two would still fit a process that happened to have room, and a probe that passes on a lucky cache is not evidence. Locally all three controls return true, and the log now shows a real digest (`subject=dfafa6d2df784a25`) rather than the empty string the first revision passed. But THE LOCAL PASS IS NOT THE PROOF: a single `gunbc run` holds only the corpus subject, so there is room either way and the OLD code would likely pass this row too. The discriminating environment is the floor, where both slots are already taken and the old code demonstrably failed -- positive control false, negative control passed, inverted by which worker picked the claim up. The second half of the non-competition claim -- that the corpus and policy subjects still resolve -- is carried by the floor run CONTAINING this row rather than by a separate assertion: every other claim is evaluated against the corpus subject, so if these five had exhausted that cache the floor would refuse rather than report a verdict. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
`ClaimScopeCompileRefused` carried only `blocking_count: Int`. The diagnostic rows were in the host and dropped, so a `.dag` control could see THAT a manifest never reached scope construction and never WHY. That cost a wrong diagnosis, which is why this is a commit rather than a tidy-up. The wall's subject control failed; the outcome was neither Accepted nor ScopeRefused; and with no cause readable from the instrument I supplied one by inference -- reading the `undeclared_bare_type_reference_class_witness` prose and concluding that two declarers of one name must be refused by the compile's global uniqueness rule. THAT INFERENCE WAS WRONG, and the corpus refutes it in one line: `Unit` is declared by both `std.types` and `v2.std.cardinality`, `Filesystem` by both `extdeps.filesystem.filesystem_io` (a service) and `v2.extdeps.file_system` (a type), and main compiles every run. Two declarers plainly do not refuse a compile. The real cause, read by reproducing the compile by hand: resolved 1 sources (reference-derived closure entry=amb/user.dag), 2 indexed modules in the name census only error[amb/user.dag:4:3]: undefined variable 'shared_thing' `undefined variable`. The declaring modules were never in the compiled closure -- indexed in the name census only -- so the read had nothing to resolve to. Nothing to do with there being two of them. I read an ARM and supplied a CAUSE from prose. That is precisely the conflation this outcome type was split to prevent two commits ago, made in my own reasoning instead of in the code, and the instrument's silence is what let it stand. So the arm now carries `diagnostics: List<CompileDiagnosticCensusRow>` beside the count, and `claim_scope_compile_refusal_has_class` lets a control name the class it got instead of reporting a bare non-acceptance. The next person to hit this reads the cause instead of guessing it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
|
Merge hazard on this branch, recorded before it bites. This branch ( So the two branches now disagree about the tier on purpose: Merging If this branch needs anything from That should be non-zero. Zero means the tier was merged away. This is a semantic conflict with no textual signature, which is why it is written down rather than left to be noticed. — sent from witty-moth-510 |
…ure finds a tier defect THE WALL'S CONTROLS COULD NOT RUN. Every arm of the witness returned the same non-verdict, and the cause was read out of the instrument rather than inferred once `ClaimScopeCompileRefused` started carrying its diagnostic rows: `AmbiguousReference: shared_thing`. The manifest never compiled, so no scope was ever built and no control observed anything. WHY, MEASURED. v1 ALREADY refuses a bare read whose claimants it cannot rank: `global_bare_policy_candidate` picks the nearest containment ancestor, and where no candidate is an ancestor the compile emits a blocking `AmbiguousReference`. The old fixtures put both claimants and the reader in unrelated module trees, which is exactly the shape the compile refuses. The class THIS wall covers is the other one -- the read the compile SETTLES SILENTLY by ancestry, ranking two declarations by where their modules sit rather than by anything the author wrote. So the geometry now reproduces that settlement: the reader `amb.user` sits under claimant `amb`, with `elsewhere.y` as the unranked second claimant. A second measured requirement came with it -- each claimant needs a uniquely-named puller (`only_amb`, `only_elsewhere`). A manifest whose user reads only the contested name pulls in ONE claimant, so nothing collides and the arm goes accepted for a reason unrelated to the wall. WHAT THE FIXTURE THEN CAUGHT, which is the part worth the whole exercise. Both variant-arm rows were RED, and not because of the fixture: `fragment_coproduct_disj_node` read `item.inferred`, which is an item's TYPE and not its declaration. For `fn probe() -> Pick` that is the `Disj` of `Pick`, so EVERY function returning a coproduct registered itself as a second declarer of that coproduct's arms; the tier saw two visible owners where the source has one and refused a read the author had named. The branch is deleted. Reading a declaration off an inferred type is the same category error in miniature that this wall exists to refuse. ROW 5 NOW ASSERTS WHAT ACTUALLY HAPPENS. Two visible coproducts is refused at COMPILE grain as `VariantCollision`, so no scope is built and the tier's strict arm is unreachable through any manifest the compile accepts. Keeping a row that claimed a scope refusal there would be a control satisfied by a cause it never observed, so it asserts the compile class instead, and the strict arm keeps its honest standing: the fail-closed direction, with the compile wall below it as its evidence rather than a control of its own. Eight rows, all green by execution against a locally built binary: subject refuses; field label, local parameter, singly-declared arm and own-coproduct arm all accepted; two-coproduct manifest refused as VariantCollision; refusal names a declaring module and carries a pasteable import line. Also: `claim_scope_refusal_names` uses `string_contains` (std.methods) rather than the hand-rolled `(split |> count) > 1`, matching the repair already made on gunbc#11143. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
|
The wall's controlled RED is now authorable, and enrolling it found a defect in the tier. Pushed Why every arm was a non-verdict before. Once What the fixture caught. Both variant-arm rows were red, and not because of the fixture. Row 5 now asserts what actually happens. Two visible coproducts is refused at compile grain as This PR stays in draft and is inside the fleet landing freeze; it also still depends on #11156 / #11138 / #11143 landing before the corpus census reaches zero on the population the wall governs. — sent from witty-moth-510 |
|
Both failures are one cause, and it is this wall doing its job against a corpus whose repair is held by the freeze.
The 16 sites are 14 So this red is not a defect in this diff — it is the ordering the campaign was designed around: the wall goes green when the qualifications land, and until then it correctly refuses the residue. The refusal text is also the remedy #11156 applies, site by site. I am not stacking #11156 onto this branch to go green. A merge of it conflicts on This PR stays in draft until the freeze lifts and #11156 / #11138 / #11143 land. Its own eight controls are green by execution ( — sent from witty-moth-510 |
#11156 landed, so the sixteen Filesystem/Clock sites this wall refused are bound to their declaring services on main. That was the whole of this PR's floor red -- the wall was firing correctly on a corpus whose repair was still in flight. One conflict, `v1_interpreter_dispatch_generated.rs`, the generated projection both sides changed: main's file taken whole, this branch's three generated rows re-added (3 insertions, 0 deletions against origin/main). VERIFIED BY THE GATE rather than by that reasoning -- `claim_executor --required-regen` reports `first_generation_equal=true`, 155/155 planned/executed/adjudicated -- so the bytes are what the merged authorities project. The conflict disappears entirely once #11143 lands, since main then already carries these rows. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
|
Merged main ( #11156 landed, so the sixteen One conflict, Staying in draft for one more step, deliberately. I attempted to merge #11143's branch in directly so this PR would carry the two things already adjudicated there — the narrowed slot-competition commentary and the seed-growth receipt — and hit exactly the hazard recorded on this PR earlier: that merge strips the variant-arm tier ( So I aborted it. Those two repairs arrive cleanly via main once #11143 lands: main will carry no tier, this branch adds it, and there is nothing to collide. Hand-resolving a deletion into this wall's own detector to save one merge is not a trade worth making. Verified after the abort: all four tier symbols intact. — sent from witty-moth-510 |
#11143 landed, which is why the #11143-into-#11166 branch merge was aborted earlier: taking the tier-removal through a branch merge stripped the variant-arm tier (`variant_arm_owners` 5 -> 0), while taking the same content through main does not, because main carries no tier and this branch adds one. VERIFIED IN THE MERGED TREE RATHER THAN ASSUMED, since "safer" is not "checked": all four tier symbols present at their full counts, the `AmbiguousBareNameRead` refusal present, the seed-growth receipt arrived, and the narrowed slot-competition commentary arrived. FOUR RESOLUTIONS, none of them a blind side-take: 1. `claim_scope_fixture_instrument_witness_test.dag` -- main's, whole. Its commentary is the version the side-chat review adjudicated; this branch's copy is the superseded draft. 2. `multi_module_compile_fixture.dag` -- main's file, plus only this branch's own addition: the `diagnostics` field on `ClaimScopeCompileRefused` and the reader over it. Main's `NonEmptyStr` causes are kept rather than reverted to bare `String`. 3. TWO DOC BLOCKS IN `cli_run.rs` WHERE MAIN'S TEXT IS TRUE ON MAIN AND FALSE HERE, which is why neither side could simply be taken. Main's §3c frontier says this type's consumer "is not in this diff" and names the trigger that would bring it -- both are satisfied HERE, so the paragraph is replaced with the discharge rather than left describing a state that no longer holds. And main's `ScopeAccepted` doc says acceptance is SILENT about ambiguity because the builder collects without refusing; this change adds the refusal, so acceptance now DOES exclude the census population, and the doc says so with the scope stated exactly (value-position only; type-position collisions remain out, per the wall's own annotation). 4. TWO DUPLICATE DEFINITIONS GIT CREATED SILENTLY. `emit_host.rs` and `v1_interpreter.rs` auto-merged with NO conflict and produced two copies each of `claim_scope_dag_multi_module_fixture` and `claim_scope_fixture_value` -- both sides added the same function, so git kept both, and only `rustc` E0428 surfaced it. The stale copies are deleted: they were this branch's older drafts carrying two defects review already repaired on main (a transcribed measurement, and a "carries an empty subject digest" claim that stopped being true once the digest was made real). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
…er exists The floor refused `declarations` with one finding: IMPORT-MEMBER-ABSENT dag/test/claim/bare_name_ambiguity_wall_witness_test.dag:11:3: imports `claim_scope_was_refused` from `tools.multi_module_compile_fixture`, which declares no such name This witness was written against an earlier shape of the fixture instrument; gunbc#11143 deleted `claim_scope_was_refused` as a dangling declaration before landing. Each side is correct alone and the combination does not resolve. NOT REPAIRED BY RESTORING THE READER, which would re-add a weaker predicate than the one that survived. The subject control now uses `claim_scope_refusal_names` pinned to `AmbiguousBareNameRead`, so it requires the refusal to NAME its cause. That is strictly stronger and it is the shape #11143's own review blessed on the negative control, which demands `EntryModuleOutsidePreparedSubject` rather than accepting any refusal: a probe satisfied by ANY refusal goes green the day an unrelated one fires first, and is then cited as coverage for a cause it never observed. AND THE FINDING WAS NOT ASSUMED TO BE THE ONLY ONE. "One finding" may be the first rather than all, so every member imported from that instrument was audited across all 21 importing files against both trees: exactly one name differs, `claim_scope_compile_refusal_has_class`, which is this branch's own addition and resolves here. No second defect is hiding behind the first. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
… NULL
My own row errored on the floor, and it is a defect in this branch rather
than an infra stall:
adjudication BLOCKING phase=floor
identity=test.claim.bare_name_ambiguity_wall_witness
.an_arm_declared_by_two_visible_coproducts_is_refused_by_the_compile
errored: type error: filter expects a list, got Null
CAUSE, AND IT IS MINE. Resolving the main merge, I took main's Rust
projection of `ClaimScopeFixtureOutcome` and this branch's `.dag` type.
Main's projection sets only `blocking_count`; this branch's type declares
`diagnostics: List<CompileDiagnosticCensusRow>` as well. So the field was
declared and never set, arrived as Null, and the first reader to fold over
it failed. A field a type declares and a projection never sets is not a
smaller answer -- it is an unwritable one.
The projection now carries the rows, which is also what lets the
instrument say WHY a manifest failed to compile rather than only THAT it
did; that is the whole reason this branch widened the arm.
WHY THIS IS WORTH A SENTENCE BEYOND THE FIX: the merge that produced it
conflicted on the `.dag` type and NOT on the Rust projection, so the
halves were adjudicated separately and agreed with neither. Two silent
defects from that same merge were already found by a build (duplicate
definitions, E0428); this third one a build cannot see, because the
mismatch is between a `.dag` declaration and a Rust value, and only
EXECUTION reaches it. The controls are what found it.
Re-run locally on a rebuilt binary: the failing row and two neighbours
all return true.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
…hat they agree
Review 65430, REQUEST_CHANGES, and it is right on both halves. Verified in
the code rather than accepted:
cli_run.rs the wall returns Err when `ambiguous_reads` is
non-empty, BEFORE `PreparedClaimScope` exists
required_floor_runner.rs:6590 `let built = claim_scope_for(..)?`
So a non-empty population propagates the `?` and never reaches the census.
`ambiguous_read_sites` could only ever be populated from a scope that was
built, which the wall now makes impossible -- the
`[floor-bare-name-ambiguity-read]` per-site lines and the
`[floor-bare-name-ambiguity-reads]` summary could print zero and nothing
else. DESIGN §4b: "permanently green by construction, carrying no
information, and worse than absent because it will be cited as coverage."
DELETED PER §4b(4), which is the rule that distinguishes this from
weakening the floor: a climb deletes the redundant lower-rung PRODUCTION
machinery it obsoletes, while the class's discriminating RED and positive
control REMAIN ENROLLED. The evidence is separate and stays --
`bare_name_ambiguity_wall_witness_test.dag` keeps all eight rows,
including the subject that must refuse and the two controls that must not.
Removed: the per-site loop, the summary line, the `ambiguous_read_sites`
map and its population. Clippy clean, so nothing else read them.
AND THE ANNOTATION FALSIFIED ITSELF. It said "the census lines in
`required_floor_runner` read this same vector, so the refusal and the
count cannot drift apart". After this climb they cannot AGREE either --
the count is structurally silent. Withdrawn and replaced with what is
true, including why the two adjacent censuses are NOT in scope:
`ambiguous_bare_names` and `qualified_bare_reads` are populated on scopes
the wall ACCEPTS, so they keep carrying information. Only the read half
dies, because only it reads the population the wall refuses on.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
|
Review 65430's REQUEST_CHANGES is correct on both halves, and I verified each in the code rather than accepting them. Pushed 1. The read census was permanently zero by construction. The wall returns Deleted under §4b(4), which is what distinguishes this from weakening the floor — a climb deletes the redundant lower-rung production machinery it obsoletes, while the discriminating RED and positive control remain enrolled. The evidence is separate and stays: 2. The annotation falsified itself, and that is the sharper half. It claimed "the census lines in The review's framing is the part worth keeping past this PR: a climb that leaves its own census standing produces a line that can only ever agree with itself, and the fact that it was my annotation asserting the opposite is what made it findable. — sent from witty-moth-510 |
… census took with it Review 65520, REQUEST_CHANGES, three findings, all verified and all mine. 1. A MERGE-BLOCKING CLIPPY RED I INTRODUCED. `ambiguous_claimants_len` was bound for the `[floor-bare-name-ambiguity-reads]` line that the census dissolution deleted, leaving a dead binding. `unused_variables` is warn-by-default and CLAUDE.md states `cargo clippy --all-targets -- -D warnings` runs in `required-witnesses-build`, so a warning there blocks a merge. Deleted; `cargo clippy --all-targets -p v1-compiler -- -D warnings` is now clean. MY EARLIER CLIPPY RUN DID NOT COVER IT: I ran `--release -p v1-compiler --lib`, which does not build the integration-test and example targets and reports a different set. CLAUDE.md names `--all-targets` as "the only command that compiles the integration-test and example targets, so a red there is invisible to every other step", and I used the invisible one. 2 & 3. TWO DOC BLOCKS DELETED AS COLLATERAL, NOT AS DISSOLUTION. The annotations on `compile_dag_multi_module_fixture` (27 lines) and `multi_module_compile_fixture_value` (5 lines) are gone from the tree. §4b(4) authorizes deleting obsoleted PRODUCTION machinery on a climb; these are the scope statement and next-rung-trigger bookkeeping of an instrument that still runs, and §4b(2) requires a class below its ceiling to keep naming its trigger. Restored verbatim from origin/main; `git diff origin/main` on both files now deletes ZERO doc lines. HOW THEY WENT: the duplicate-definition dedup two heads ago walked upward from the function it was deleting while lines started with `///`, and swallowed the doc block belonging to the NEXT function. That is the same slice-swallow that took the string_eq doc on gunbc#11138 earlier today -- second instance, same mechanism, and the check that would have caught both is the one I ran on that PR and not on this one: after any deletion, diff against the tree the deletion was made from and count the doc lines it removes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
|
Review 65520's three findings are all verified and all mine. Pushed 1. A merge-blocking clippy red I introduced. Worth stating why I missed it: I ran 2 & 3. Two doc blocks deleted as collateral, not as dissolution. The annotations on How they went, because the mechanism matters more than the restoration: the duplicate-definition dedup two heads ago walked upward from the function it was deleting while lines started with And the check that would have caught both is one I ran on that PR and not on this one: after any deletion, diff against the tree the deletion was made from and count the doc lines it removes. On #11138 I ran it and it found nothing, because the lost block was my own branch's addition; here it would have worked, because these were main's lines. Two failures, one instrument, and I applied it to the case it couldn't see and skipped the case it could. — sent from witty-moth-510 |
…sert, and its last citation
Review 65757, REQUEST_CHANGES, three findings, all correct and all the
same class -- the climb deleted the census's CONSUMER and left everything
that fed it.
1. THE FIELD WAS RETAINED WRITE-ONLY. The wall returns `Err` whenever
`ambiguous_reads` is non-empty and BOTH entry points reach it
(`claim_scope_for_without_memos` delegates to
`claim_scope_for_with_memos`), so on every `Ok` path
`PreparedClaimScope.ambiguous_bare_reads` was the empty vector by
construction. §4b(4) says a climb deletes the lower-rung PRODUCTION
machinery it obsoletes, and the collection into the returned struct is
exactly that. Field and push both deleted.
2. THE MEMO-EQUIVALENCE ASSERT WAS `vec![] == vec![]`. A non-empty
population propagates `Err` through the `.expect("memoized scope")`
above it, so the assertion could not fail. That is the same §4b
sentence this diff already quotes to justify deleting the census
lines -- "permanently green by construction, carrying no information,
and worse than absent because it will be cited as coverage" -- and I
applied it to the printed lines while leaving an assert in the same
state two thousand lines away. Deleted. The sibling asserts on
`ambiguous_bare_names` and `qualified_bare_reads` stay: those
populations are non-empty on accepted scopes and the comparison can
still fail.
3. AND THE LAST CITATION OF THE DELETED CENSUS. The fixture doc still
said the wall reads "the same `ambiguous_reads` vector the census
prints from" while this diff deletes that census -- a named instrument
that no longer exists, which is §6's rot in the direction the rule
warns about.
I also retired two dangling symbol citations the review did not raise: two
historical sentences still named `ambiguous_bare_reads` after the field
was gone, so a reader following them greps for a symbol that does not
exist. Both now say what was deleted without naming a dead symbol. Zero
mentions remain in `src`.
`cargo clippy --all-targets -p v1-compiler -- -D warnings` clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
|
Review 65757's three findings are all correct and all the same class: the climb deleted the census's consumer and left everything that fed it. Pushed 1. The field was retained write-only. The wall returns 2. The memo-equivalence assert was The sibling asserts on 3. The last citation of the deleted census. The fixture doc still said the wall reads "the same I also retired two dangling symbol citations the review did not raise. Two historical sentences still named The generalizable part, since this is the second time today one of my climbs was half-finished: deleting a consumer is not dissolving a class. The consumer is the visible end; the producer, the field it fills, the asserts that compare it and the prose that cites it all outlive it silently, and each one reads as coverage afterward. The check is to grep the symbol and account for every hit before calling the climb done — which is what I did here only after being told.
— sent from witty-moth-510 |
… contradicting annotation
Review 65775, REQUEST_CHANGES, three findings, all correct.
1. THE WALL'S DISCRIMINATING RED HAD NEVER FIRED -- the PR title said so
and I had been treating "the rows are green" as the evidence. §4b(1)
wants the rung established by EXECUTED evidence: a discriminating RED
refused on the real acceptance path plus an accepted positive control.
Executed now, by building the seed twice against this same manifest
with only the wall's own guard disabled between them:
WALL REMOVED bare_value_read_of_an_ambiguous_name_refuses false
the_refusal_names_a_declaring_module false
a_field_label_sharing_...does_not_refuse TRUE
WALL RESTORED all three true
The two rows that assert the refusal flip with the wall and back; the
negative control holds in both directions. That last part is the
load-bearing half -- it shows the rows moved because the REFUSAL moved
and not because anything about the manifest or fixture changed. The
receipt is recorded at the rows, with the re-derivation route, and the
disabling edit is not in this branch.
2. THE NEW TIER WAS INVISIBLE TO THE MEMO-EQUIVALENCE FINGERPRINT.
`resolution_fingerprint` claims to cover "EVERY RESOLUTION THIS INDEX
SET CAN ANSWER" and did not enumerate `variant_arm_owners`, which this
PR adds and which `site_resolved_variant_arm_module` answers from. So
the new memoized fragment field travelled the memo path with zero
equivalence coverage, and a divergence there flows straight into
whether the wall fires -- the fail-open direction being §5's absorbing
fallback. One loop added. Deleting the old `ambiguous_bare_reads`
assert was right; leaving the new tier uncovered was the regression,
and both were in the same diff.
3. AND THE FIXTURE'S ACCEPTANCE ANNOTATION SAID THE OPPOSITE OF ITS RUST
TWIN. The `.dag` block still read "ACCEPTANCE IS SILENT ABOUT
AMBIGUITY... must not be cited as coverage for a refusal that is not in
this change", while this diff makes all three clauses false and the
five `claim_scope_was_accepted` control rows are precisely rows cited
as that coverage. Its Rust twin was rewritten and this one was not --
one fact, two annotations, opposite obligations (§3 meaning fork).
Worse, my paragraph was inserted BELOW the stale block, so the orphan
became the leading `//` block of `claim_scope_compile_refusal_has_class`
-- §4c binds an annotation to the declaration it leads, and that is the
third time this slice/dedup mechanism has moved prose onto the wrong
declaration in this branch.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
|
Review 65775's three findings are all correct. Pushed 1. The discriminating RED has fired. The review is right that I had been treating "the rows are green" as the evidence, and §4b(1) asks for the rung established by executed evidence — a discriminating RED refused on the real acceptance path plus an accepted positive control. Executed by building the seed twice against the same manifest, with only the wall's own The two rows asserting the refusal flip with the wall and back. The negative control holding in both directions is the load-bearing half: it shows those rows moved because the refusal moved, not because anything about the manifest or the fixture changed. Receipt recorded at the rows with its re-derivation route; the disabling edit is not in this branch and nothing re-derives it. 2. The new tier was invisible to the memo-equivalence fingerprint. The pairing is the part worth naming: deleting the obsolete 3. The fixture's acceptance annotation said the opposite of its Rust twin. All three clauses of the old block are false after this change, and the five — sent from witty-moth-510 |
…strument instead of quoting it
Review 65808, REQUEST_CHANGES, both findings correct.
1. THE ROW PROJECTION WAS HAND-COPIED THREE TIMES -- in
`compile_diagnostic_census_value`, in `claim_scope_fixture_value`, and
in `multi_module_compile_fixture_value` forty lines apart in one file.
§2's test is that "net concepts must not grow by re-invention", and the
cost here is not style: the day the `.dag` row gains a field, two of
the three keep emitting the old shape and the new field arrives NULL at
its first reader. THIS INSTRUMENT HAS ALREADY PAID THAT PRICE ONCE --
the `diagnostics` field this branch added was declared and unset, and a
control died with `type error: filter expects a list, got Null`. I fixed
that instance and then left three producers standing to do it again.
One `compile_diagnostic_census_row_value`, three callers.
2. AND MY §4b(1) RECEIPT WAS A TRANSCRIBED TABLE IN A COMMENT. It quoted
the two-binary readings and said, in its own words, that "nothing
re-derives it" -- which is §6 ("a transcribed number is unreachable
from the thing that owns it, so it rots") and §4c ("an annotation is
never evidence that a machine claim holds, because no Accepted program
can read one"). A rung resting on prose is what this wall exists to
refuse, one level up, and I wrote one into the wall's own witness while
correcting other people's transcriptions all day.
Replaced with the two things that are legitimately annotation content:
THE INSTRUMENT, named so anyone can re-derive it (negate the wall's own
`!ambiguous_reads.is_empty()` guard, rebuild, run these three rows
against both binaries), and THE PREDICATE the run decides -- the two
refusal rows must FLIP with the wall and the field-label control must
HOLD in both directions, because a run where all three move together
would mean the rows are keyed on the manifest rather than on the wall.
Stated as what the run must show rather than as what a run showed.
The next rung is named rather than claimed: the mutation is a hand edit
of the seed, not a mode of it, and making it a flag is what would turn
this receipt into an instrument.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
|
Review 65808's two findings are correct. Pushed 1. The row projection was hand-copied three times — in This instrument has already paid that exact price once. The 2. My §4b(1) receipt was a transcribed table in a comment — and it said in its own words that "nothing re-derives it", which is the confession. §6: "a transcribed number is unreachable from the thing that owns it, so it rots." §4c: "an annotation is never evidence that a machine claim holds, because no Replaced with the two things that are legitimately annotation content:
And the next rung is named rather than claimed: the mutation is a hand edit of the seed, not a mode of it, so making it a flag is what would turn this receipt into an instrument. — sent from witty-moth-510 |
…es on the floor's path); cite the real symbols; typed WitnessDeleted rows for the nine deleted lens identities (review 66247) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019aMigU7Gz7kFLQageRhCqx
Makes an ambiguous bare-name read a refusal in the v1 evaluator, rather than something the shared name slot silently settles.
The refusal
claim_scope_fornow returns a typedAmbiguousBareNameReadrefusal when a bare value reference reaches the shared name slot with two transitively-reached declarations spelling it and nothing the author wrote ranking them. Previously scope precedence picked one — a resolution no source authorizes.It carries its remedy, naming declaring modules. A site authored next week reds someone who never heard of this campaign, in a module they may not own, over a name they did not know was contested. So each row prints the bare name, the referring module, each claimant with the module that declares it and the kind, and a pasteable
import <declaring module> { <name> }— plus a warning that an import naming a re-exporter binds nothing. That warning is measured, not hypothetical: copying an adjacent file's import line is howimport std.types { String }came to appear in ~1951 modules while binding nothing.The evidence: a fixture that authors the ambiguity
dag/test/claim/bare_name_ambiguity_wall_witness_test.dagbuilds a synthetic multi-module source set in whichshared_thingis genuinely declared twice and read bare — so the RED is authored rather than waited for. Eight rows:AmbiguousBareNameReadcause rather than satisfied by any refusalVariantCollisionthe compile raises, because no scope is ever built there; a control asserting a scope refusal it never observes would be satisfied by a cause it never sawTwo geometry facts were measured, not assumed, and are recorded at the rows: the reader must be a containment descendant of one claimant (otherwise v1 refuses the compile with
AmbiguousReferenceand no scope exists — the class this wall covers is the one the compile silently settles by ancestry), and each claimant needs a uniquely-named puller, or only one claimant enters the scope and the arm passes for an unrelated reason.The discriminating RED has fired
Beyond the authored fixture, the guard itself was shown to be the cause: the seed was built twice with only
!ambiguous_reads.is_empty()disabled between them. The two refusal rows flip with it and back; the field-label control holds in both directions. Flipping one way proves a red exists — flipping back, with a neighbour held fixed, proves the guard causes it. The witness names that instrument and states the predicate it decides rather than transcribing readings.The variant-arm tier
fn_entrieswalks top-level items only, so an arm oftype TestClass = Unit | Hermetic | Integrationwas invisible to both resolution tiers — five corpus sites read as defects while being correctly written. The tier derives arm owners by walking every top-level coproduct and resolves a site from its own module or its authored import binding, keyed on(module, coproduct): two visible coproducts declaring one arm stay ambiguous, which is the fail-closed direction.It does not read
item.inferred— that branch was removed after the fixture caught it registering every coproduct-returning function as a declarer of its return type's arms. An item's inferred node is its type, not its declaration.What the climb deletes
The
[floor-bare-name-ambiguity-read]census lines, theambiguous_bare_readsfield that fed them, and the memo-equivalence assert over it. Once the wall returnsErrbefore a scope exists, all three could only ever report zero — §4b's "permanently green by construction … worse than absent because it will be cited as coverage." §4b(4) dissolves the production machinery and keeps the evidence: the eight fixture rows stay enrolled. The declaration-grain and qualified-read censuses survive, because they are populated on scopes the wall accepts.resolution_fingerprintnow includes the new tier, so the memo-equivalence witness covers it.Corpus state
Zero ambiguous bare-name reads remain for the wall to refuse: the sixteen
Filesystem/Clocksites were qualified by #11156, and the five variant-arm sites are resolved by the tier rather than excused by a list.🤖 Generated with Claude Code
https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT