Repository navigation
Give the fixture instrument a claim scope, with the third resolution tier - #11143
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
Review 64472 is right and this removes the tier rather than defending it. THE FINDING. This PR shipped a third resolution tier that changes what `claim_scope_for` reports -- five corpus sites leave the `ambiguous_bare_reads` population the census consumes -- and NOTHING in the diff executed it. The three enrolled rows exercise `ClaimScopeAccepted`, `EntryModuleOutsidePreparedSubject` and the memo bound; none authors a variant-arm read, so none goes red if the tier resolves the wrong coproduct or over-resolves. DESIGN §5: done means a real consumer green by execution PLUS a discriminating input that goes red when the behaviour is wrong. MY EARLIER DEFENCE DOES NOT REACH IT. I argued that a control for a wall belongs with the wall. True, and irrelevant here: the tier is not the deferred wall. It is landed production behaviour that shrinks a census population in this diff, and it has to carry its own red. THE FIX IS PACKAGING, NOT NEW MACHINERY. The tier's controls already exist -- the singly-declared-arm row and the two-visible-coproducts row in the wall's set -- so the tier goes where they are. That is also the coherent story: the tier exists FOR the wall, because without it the wall would refuse five correctly-written sites. Landing them together means neither arrives unexercised. A note on HOW, because the method mattered more than the edit: I removed the tier by hand twice and broke this file both times, once deleting ~7000 lines when a pattern over-matched. What worked was `git diff <tier commit> | git apply -R` -- reversing the commit's OWN recorded hunks instead of re-deriving them. A change made as a commit has an authority on what it touched, and reconstructing that by pattern is the second derivation §3 warns about. ALSO, REVIEW 64472's SECOND FINDING: two comments transcribed instrument output. One left with the tier. The other claimed "MEASURED, on gunbc#11143's floor before this: the POSITIVE control returned false while the NEGATIVE one PASSED" and now names the producer -- the required floor job whose control rows re-derive it -- keeping the irreducible rationale (§4c) without the copied observation (§6). EVIDENCE. All three instrument controls still pass with the tier gone, so they never depended on it: a_well_formed_manifest_builds_a_claim_scope -> true an_entry_outside_the_subject_reaches_the_caller_as_a_scope_refusal -> true several_distinct_fixture_subjects_all_resolve -> true Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
|
Review 64472 is right on both findings. Fixed in The tier had no discriminating control, and that is disqualifying on its own terms. It changes what My earlier defence does not reach it. I argued a control for a wall belongs with the wall. That is true and irrelevant here: the tier is not the deferred wall, it is landed production behaviour shrinking a census population in this diff, and it has to carry its own red. So the fix is packaging, not new machinery. The tier's controls already exist — the singly-declared-arm row and the two-visible-coproducts row — in #11166's set. The tier goes where they are. That is also the coherent story: the tier exists for the wall, because without it the wall would refuse five correctly-written sites. Landing them together means neither arrives unexercised. You also correctly identified that the instrument this PR builds is the harness that can author that red. Worth flagging for whoever picks up #11166: I have since measured that authoring an ambiguous read in a fixture manifest does not work yet — the declaring modules are not pulled into the compiled closure, so the read is Second finding — transcribed instrument output. Both sites fixed. One left with the tier. The other now names the producer (the required floor job whose control rows re-derive it) rather than copying the observation, keeping the irreducible rationale §4c protects without the transcription §6 forbids. Same point review 64326 made about the admission roster, so the same treatment. Evidence the removal is clean — all three instrument controls still pass, so they never depended on the tier: — sent from witty-moth-510 |
Review 64487, all three findings verified against the code and all three correct. TWO DOC BLOCKS WERE SILENTLY RELOCATED. Both new functions were inserted by anchoring on an existing `fn` line, which put them BETWEEN that function and its doc comment. Rustdoc then attached the older rationale to the newer function and left the original bare: emit_host.rs -- `compile_dag_multi_module_fixture`'s block, including "Unlike the census it does NOT arm `with_type_ref_hit_ne_bind_measure`", came to document `claim_scope_dag_multi_module_fixture`, which does not touch that knob at all. v1_interpreter.rs -- `multi_module_compile_fixture_value`'s block, including "a compile that never ran must never arrive as `FixtureCompileCompleted` with an empty diagnostic list", came to document `claim_scope_fixture_value`, which has no such arm. Both are §5 rationale receipts -- the reasoning for why an arm exists -- and a receipt filed against the wrong declaration is worse than one missing, because it reads as authority. §4c is the citation: prose in the quarantine channel is still authored data with an owner, and one describing a DIFFERENT declaration is below the bar it sets. Each block is moved back, and `claim_scope_fixture_value` gains its own doc stating what its four arms keep distinct. THIS IS THE SAME MISTAKE AS THE IMPORT INSERTION EARLIER IN THIS CAMPAIGN, in a different channel: anchoring an insertion on a declaration line without accounting for what precedes it. There the anchor was the last line starting with `import` and the insertion landed inside a multi-line import block; here the anchor was the `fn` line and the insertion landed inside its doc block. Both are silent -- the code compiles and rustdoc renders -- and both are only visible by reading what the neighbouring text now claims. A FALSE FACT USED AS A REASON. The memo-free path was justified by "whose PreparedRepository is synthesized here and carries an empty subject digest". That was true of the first revision and stopped being true when the digest was made real; the sentence survived as the stated REASON for the design. The reason is the bounded population, not the digest, so it now says so. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
|
Review 64487 — all three findings verified against the code, all three correct, fixed in Two rationale receipts had been silently relocated. Both new functions were inserted by anchoring on an existing
Your §4c citation is the right one. These are §5 rationale receipts, and a receipt filed against the wrong declaration is worse than a missing one, because it reads as authority — a later reader would have taken "does not arm Worth naming: this is the same mistake as the import insertion earlier in this campaign, in a different channel. There the anchor was "the last line starting with Third finding — a false fact used as a reason. The memo-free path was justified by "whose PreparedRepository is synthesized here and carries an empty subject digest". That was true of the first revision and stopped being true when the digest was made real in — sent from witty-moth-510 |
…ing uses Review 64493, both findings verified and both correct. A DOC ASSERTING A CALL THAT CANNOT EXIST. Two blocks -- the `ClaimScopeFixtureOutcome` doc and the `.dag` surface comment -- said the instrument "runs `claim_scope_for_without_memos` itself". It does not: it calls `claim_scope_for_with_memos(.., None, .., Some(reference_index))`. And `claim_scope_for_without_memos` is `cfg(any(test, feature = "interp_test_witness"))`, so the sentence asserted a call a RELEASE BUILD HAS NO FUNCTION FOR -- while the code's own comment three files away says exactly that. Both now name the function actually called, and say what differs from the floor's call (memo arguments, a caching decision) and why the obvious spelling is unavailable. THIS IS THE THIRD INSTANCE OF ONE PATTERN IN THIS PR, and worth naming as a pattern rather than three defects: prose written against one state of the code and not re-read when the code moved. The others were the stale "empty subject digest" justification and the two relocated rationale receipts. All three compile, all three read as authority, and none is visible except by reading what the text claims against what the code does. A DECLARATION WITH NO CONSUMER. `claim_scope_was_refused` was declared and used by nothing -- its one caller became `claim_scope_refusal_names` when that reader was tightened to pin the cause, and the weaker one was left standing. §3c: name the consumer and the route, or it is dangling. Deleted. The surrounding comment now records WHY only one refusal reader exists, because that is the part worth keeping: a reader answering "did it refuse" goes green the day an unrelated refusal fires first, and two readers where one is strictly weaker is an invitation to reach for the weaker. Shipping both would have re-created the failure the stronger one was written to prevent. EVIDENCE: both fixture controls still pass after removing a symbol from the instrument's surface -- a_well_formed_manifest_builds_a_claim_scope -> true an_entry_outside_the_subject_reaches_the_caller_as_a_scope_refusal -> true Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
|
Review 64493 — both findings verified, both correct, fixed in A doc asserting a call the code cannot make. Two blocks said the instrument "runs This is the third instance of one pattern in this PR, and I'd rather name it as a pattern than as three defects: prose written against one state of the code and not re-read when the code moved. The others were the stale "empty subject digest" justification and the two relocated rationale receipts. All three compile, all three read as authority, and none is visible except by reading what the text claims against what the code does. The fix for the class is re-reading the prose whenever the call it describes changes — which is what the reviews have been doing for me. A declaration with no consumer. I kept the reason in the surrounding comment rather than just removing the symbol, because that is the part with value: a reader answering "did it refuse" goes green the day an unrelated refusal fires first, and shipping two readers where one is strictly weaker is an invitation to reach for the weaker — re-creating exactly the failure the stronger one exists to prevent. Your note that the file's own comment already argued for its deletion is the sharpest part of the finding: the case against it was written down and then not acted on. Evidence the removal is clean — both controls still pass after taking a symbol off the instrument's surface: — sent from witty-moth-510 |
|
Review 64495 — the seed-growth point is fair and the diff did not say what it should have. Added to the PR body rather than pushed, since it is a statement of admission and not a code change. The finding is right: ~170 lines of hand-Rust into the v1 seed with no stated admission, under an authority whose test is strict — What I found when I looked rather than argued: this is growth of an existing, already-reasoned class. Where I have qualified rather than asserted: the argument is that v2 is emitted by v1, so a resolution defect in the seed propagates into everything v1 emits, and this is what lets a refusal for that class carry an executable red. That is about the seed's correctness, not about shrinking it — and this change makes the seed larger. I have said so in the body rather than let "serves the self-host program" do silent work. It is worth disputing; I would rather it be disputed than assumed. Your framing that this is ctrl review policy rather than a Noting also that your clean-checks list independently confirmed the two things I most wanted a second pair of eyes on: that every pre-existing — sent from witty-moth-510 |
The floor on this head is CLEAN -- `verdict=FloorClean`, `claims_failed=0` -- and the namespace phase reports `0 unadjudicated delta(s)`. What blocked it was `1 stale admission(s)`. This branch predates #11137's merge, so its own roster never carried that row; CI builds the MERGE REF, and the merged tree is where the row came from. Merging main here makes that explicit rather than leaving the branch and its tested tree disagreeing about what is in the roster. The row is deleted. #11137 merged, its narrowed import is at the base, the delta it admitted stopped being producible, and a row matching no delta blocks the phase. Its own recorded trigger was "this row goes when #11137 merges", and this is a roster touch on which that came due. THAT IS THE FOURTH BRANCH TO PAY THIS DEBT, which is the shape worth recording rather than the deletion: a row that declares its own retirement does not retire itself, and it does not merely linger -- it REFUSES every PR carrying it until someone lands the removal. #11138, #11156 and the wall branch each hit it independently and each deleted it. The deletion is owed once, so a delete-versus-delete conflict between them resolves by keeping the deletion. The roster returns to EMPTY, its resting state. Empty is not permissive: a run carrying any delta no row names still refuses it as unadjudicated, so an empty roster means no transition is currently admitted rather than that transitions are unchecked. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
Review 64511 is right, and this is the FOURTH instance of one pattern in this PR: prose written against a state of the code and not re-read when the code moved. `ScopeAccepted`'s doc said "`claim_scope_for` accepted, and the scope holds no ambiguous bare-name read." The wall was deliberately removed from this branch, and `claim_scope_for_with_memos` does not refuse on ambiguity -- it COLLECTS `ambiguous_reads` and returns them on the accepted scope. `grep -c AmbiguousBareNameRead` over this branch's `cli_run.rs` is 0. So the arm is compatible with any number of ambiguous bare reads and the sentence is false. WHY THIS ONE IS WORSE THAN STALE, which is the review's sharpest point. Both positive controls -- `a_well_formed_manifest_builds_a_claim_scope` and `several_distinct_fixture_subjects_all_resolve` -- assert through `claim_scope_was_accepted`. A doc promising "no ambiguous bare-name read" on that arm turns two rows that establish nothing about ambiguity into what reads as coverage for a wall that is not in this diff. That is §4b rung inflation with a citation already attached, and it would have been cited by someone who had no way to know the wall left. Both the Rust arm and the `.dag` reader now say what acceptance means and what it is silent about, and point a reader who needs the stronger claim at `ambiguous_bare_reads` instead of letting them infer it. ON THE PATTERN, since four is enough to call it one rather than a run of accidents: every instance was prose that was TRUE WHEN WRITTEN and became false when the code under it moved -- the without_memos call, the empty subject digest, the two relocated rationale receipts, and now this. None was caught by compiling, and none by me. The habit that would have caught them is re-reading the prose attached to every symbol a change touches, not just the lines the change edits, and that is what these reviews have been doing on my behalf. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
|
Review 64511 — verified and fixed in The claim was false. Why it was worse than stale. Both positive controls assert through On the pattern, since four is enough to call it one rather than a run of accidents. Every instance was prose that was true when written and became false when the code under it moved: the I'll note the asymmetry plainly: the code in this PR has held up under review; the prose about the code has not. That is a real quality signal about how I work, not a run of bad luck, and it is worth more to me than the individual fixes. — sent from witty-moth-510 |
… duplicate of it Delete-versus-delete, resolved by keeping ONE record rather than two. Both sides removed the `gunbc#11137` row and both wrote a dissolution note for it. Main's landed first, so main's note is the one the ledger keeps; this branch's copy is dropped. A ledger recording one deletion twice is worse than one recording it once -- the same correction this campaign already made on the string_eq branch, arrived at again from the other direction. The roster stays EMPTY, which is its resting state and is not permissive: a run carrying any delta no row names still refuses it as unadjudicated. This branch adds no rows, because the instrument and the resolution-tier split left nothing here that produces a namespace delta. That closes the #11137 row's story: four branches reached its retirement independently, because a stale row refuses every PR carrying it, and the deletion was owed exactly once. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
…al one Review 64522 is right and this is the worst of the prose defects in this branch, because it cost a real receipt to buy a false one. WHAT THE HUNK DID. It added a `THIRTY-SIXTH DISSOLUTION (gunbc#11143)` paragraph saying "the `gunbc#11137 ...` row is deleted, leaving the roster EMPTY". This PR deletes no row. The roster is ALREADY empty at the base -- main carries `= &[];` and its own `RETIRED (2026-09-12): #11137 merged as 34d2a8d` -- and this branch's own merge commit says exactly that. So the paragraph was a receipt for work performed elsewhere, written in the first person of a change that did not perform it. §4b(1): a reported rung must equal the rung established by executed evidence. §4c: an annotation is never evidence that a machine claim holds. AND IT WAS NOT FREE. The same hunk deleted the surviving `THE gunbc#10671 ROWS DISSOLVED HERE (2026-09-06)` record -- a real adjudication, carrying the three-direction join that established CONSUMED for those four rows rather than asserting it. So the change was a net LOSS of evidence: one genuine receipt removed, one fabricated receipt added, in a file whose entire value is that its history can be read back. The file is restored to main's version byte for byte. This branch has no roster obligation and should touch this file not at all, which is now what it does. HOW IT HAPPENED, since the mechanism is the reusable part: the conflict resolution on this branch replaced a region of the doc chain rather than taking one side of it, and the replacement silently swallowed a paragraph that neither side was in conflict about. Resolving by REGION is how you lose text no one edited; resolving by SIDE is not. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
|
Review 64522 — verified and fixed in The paragraph claimed work this PR does not do. It said "the And it was not free. The same hunk deleted the surviving The file is restored to main's version byte for byte. This branch has no roster obligation and should touch it not at all, which is now what it does. The mechanism, since it is the reusable part: my conflict resolution replaced a region of the doc chain instead of taking one side of it, and the replacement swallowed a paragraph neither side was in conflict about. Git flagged the conflict correctly; my resolution is what lost the text. Resolving by region is how you delete text no one edited — resolving by side is not. I had already been bitten once this session by reconstructing a change by hand instead of using git's own recorded hunks, and this is the same lesson in the conflict-resolution direction. Noting your clean-checks list confirms the parts I most wanted independently verified: one detector via — sent from witty-moth-510 |
Review 64528's non-blocking point: `ClaimScopeInstrumentRefused` and `ClaimScopeRefused` typed `cause` as bare `String` while the sibling coproduct one screen up types the same fact as `NonEmptyStr`. Strictly weaker construction for an identical fact, so it should be strengthened (§5, construction over validation). IT IS NOT A BARE TYPE SWAP, and the measurement is why this commit exists rather than a one-line edit. Branding the field broke the instrument: function 'split' not found in scope method 'count' cannot be resolved: receiver type 'Primitive()' establishes no method surface `split` is declared over `String`, and the `NonEmptyStr` brand establishes no method surface of its own -- so `claim_scope_refusal_names`, the reader that pins the discriminating red to its CAUSE, stopped resolving. The Rust built clean; the `.dag` resolve failed. A green build would have shipped a PR whose controls silently stop running. The brand is kept where it earns its keep -- on the FIELD, where it makes an empty cause unwritable rather than merely unwritten -- and coerced at the single site that reads it (`c as String`). The cost is one ascription, located where it is visible. FALSIFIED, NOT ASSUMED, because the coercion sits inside the very comparison the discriminating arm exists to probe. Three green rows are equally consistent with "the coercion restored the reader" and "the coercion made the reader permissive"; only the wrong-marker arm separates them: a_well_formed_manifest_builds_a_claim_scope -> true an_entry_outside_the_subject_reaches_the_caller_as_a_scope_refusal -> true several_distinct_fixture_subjects_all_resolve -> true same row with a marker the refusal does not contain -> false Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
|
Review 64528 — the Branding the field broke the instrument:
The brand is kept where it earns its keep — on the field, where it makes an empty cause unwritable rather than merely unwritten — and coerced at the one site that reads it ( Falsified rather than assumed, because the coercion sits inside the exact comparison the discriminating arm exists to probe. Three green rows are equally consistent with "the coercion restored the reader" and "the coercion made the reader permissive" — only the wrong-marker arm separates them: On the advisory receipt point: the v1 admission is already in the PR body from review 64495 — it names the existing reasoned class ( — sent from witty-moth-510 |
Review 64545, two findings, both correct. RE-INVENTION WITH A COMMENT DEFENDING IT. Containment was hand-rolled as `(split(s: c as String, delimiter: cause_marker) |> count) > 1` while the corpus already carries the authority: `string_contains`, declared at `std.methods` `string_contains_method`, 4095 call sites, and used by a SIBLING INSTRUMENT IN THE SAME DIRECTORY (`gunbc.instruments.dag_compile_clean_seam`). §2: net concepts must not grow by re-invention. The comment made it worse rather than better. It defended the hand-rolled form as "the idiom the corpus already uses for this" -- true of the weaker idiom only, and it pre-answered the question a reader would otherwise have asked. I copied a pattern from one neighbouring file and asserted corpus-wide practice from a sample of one. THE FRONTIER WAS GESTURED AT, NOT DECLARED. §3c admits an unconsumed declaration in exactly one form: a named consumer landing in a named later change, with the trigger stated beside it. "Lands separately and brings its own controls" names neither. The type now names both -- the `AmbiguousBareNameRead` refusal on `session/witty-moth-510-wall2` (gunbc#11166), and the trigger that the census population it governs must reach zero, which needs the qualification batches merged AND the variant-arm tier that stops the census over-counting five correctly-written sites. One sentence the review did not ask for is added with it: if that refusal is abandoned, this instrument has no remaining consumer and should be DELETED rather than retained. Without that, a declared frontier quietly becomes a permanent resting state, which is how dangling declarations survive review. EVIDENCE, and the falsification is re-run rather than carried over from the previous predicate, because `string_contains` is a DIFFERENT comparison than the one that arm last falsified: a_well_formed_manifest_builds_a_claim_scope -> true an_entry_outside_the_subject_reaches_the_caller_as_a_scope_refusal -> true several_distinct_fixture_subjects_all_resolve -> true same row, marker the refusal does not contain -> false Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
|
Review 64545 — both findings verified and fixed in Re-invention, with a comment defending it. Containment was hand-rolled as The comment made it harder to catch, not easier. It defended the hand-rolled form as "the idiom the corpus already uses for this" — true of the weaker idiom only. I copied a pattern from one neighbouring file and asserted corpus-wide practice from a sample of one, then wrote that assertion down where it would pre-answer the question a reader should have asked. Your phrasing — "true of the weaker idiom only" — is precisely the gap. The frontier was gestured at, not declared. §3c admits an unconsumed declaration in exactly one form: a named consumer in a named later change with the trigger beside it. "Lands separately and brings its own controls" names neither, and I had thought that sentence discharged the obligation. It now names the consumer (the I added one sentence you didn't ask for: if that refusal is abandoned, this instrument has no remaining consumer and should be deleted rather than retained. A frontier without that clause quietly becomes a permanent resting state, which is how dangling declarations survive. Evidence — falsification re-run rather than carried over, because Noted your credit on the rung-honesty points; those were the parts I was least sure I'd got right, so it is useful to know they read correctly from outside. — sent from witty-moth-510 |
`src/v1/stage0/src/v1_interpreter_dispatch_generated.rs` is a generated projection both sides changed since the merge base, which is the `GeneratedArtifactConcurrentDivergence` case: neither side's bytes are the projection of the MERGED authorities, and the driver refuses rather than answering. Resolved the way the driver's own route says: take main's file whole, re-add only this branch's three generated rows for `claim_scope_dag_multi_module_fixture`, so the result deletes ZERO of main's lines (3 insertions, 0 deletions against origin/main). VERIFIED BY THE GATE, NOT BY THAT REASONING. `claim_executor --required-regen --source-root dag --source-root src/v2` reports `first_generation_equal=true`, planned=155 executed=155 adjudicated=155 -- so the bytes in the tree ARE what the merged authorities project, as judged by the instrument that owns the question. Hand-reasoning that a reconstruction "must" be the projection is exactly what that gate exists to stop anyone trusting. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
Review 64893 read this change's §3c frontier as answered and the SEED-SIDE receipt as missing. That reading is right, and the two are genuinely different questions: "who consumes this `.dag` type" says nothing about "why is this Rust". The repo has an authority for the second one -- `gunbc.seed_growth_admission` `seed_growth_forward_freeze_policy_note` makes unenumerated hand growth in `src/v1` a stop-line and states exactly what a receipt must carry -- so this is filed as a row under that authority rather than as prose in a PR body, which is unreachable from the code. The row enumerates the four hand declarations by identity (`ClaimScopeFixtureOutcome`, `build_reference_closure_index`, `claim_scope_dag_multi_module_fixture`, `claim_scope_fixture_value`), states why it is Rust (the subject IS a seed function, and a `.dag`-side re-derivation would be a SECOND detector free to drift from the census the floor prints -- the instrument calls the same `claim_scope_for_with_memos` the floor's entry point calls), names the owning lane and the deletion trigger, and states the current boundary. WHAT IS NOT NETTED is named rather than counted against the additions, because `seed_growth_deletions_offset_nothing` executes that rule: the parameter added to `claim_scope_for_with_memos` and the body lifted out of `reference_closure_index` are `ExistingSeedItemModified`, and the three generated dispatch rows are exempt by generation authority rather than by my say-so. The hand-item and hand-LOC deltas are deliberately NOT restated: `gunbc.rust_item_host_observation` derives them from the diff, and an authored copy is the second representation that policy note measured going wrong on gunbc#9095. Consumed, not dangling: the row is imported by `gunbc.seed_growth_admission` and added to `seed_growth_justification_roster()`, which is the live population G1 joins against. `gunbc compile` on that module: 0 blocking errors. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
|
Review 64893's seed-side receipt is now paid, in the repo's own authority rather than in this PR body — pushed The review is right that the §3c frontier and the seed receipt are different questions, and that the first says nothing about the second. The repo does resolve the second: What it records:
Consumed rather than dangling: imported by Thanks for separating the two questions — the frontier answer had been standing in for a receipt it cannot give. — sent from witty-moth-510 |
|
Item 3 from my side-chat review request is now answered by execution, not by argument. I asked whether So I ran the falsification: re-armed registration in the fixture path (pass The RED is authorable and discriminating: it fires exactly when the fixture occupies a bounded slot, and the neighbouring positive control does not move — which is the difference between a control and a row that reds whenever anything at all is wrong. The arm is reverted and is not in this branch. That closes the one place where this PR's evidence was weaker than its claim. The other two items I raised — that the builtin calls the same — sent from witty-moth-510 |
Side-chat source review held gunbc#11143 on this comment block alone --
not the test, not the implementation, both of which it cleared. Two
claims in it did not follow:
(a) "the row fails if the fixture occupies even ONE slot" is a universal
this row cannot support. Their counterexample is source-level and
correct: an implementation that registered only the FIRST fixture, on
a worker with spare capacity, spends a slot while all five calls still
accept. This row inspects neither occupancy nor memo contents.
(b) "a green enclosing floor establishes the production subjects still
resolve after the fixture" is not a named post-fixture read. Nothing
here says which production subject is queried afterwards, on which
worker, or whether that query reaches the affected memo. A green
aggregate establishes what that run obtained, not a postcondition over
every relevant thread-local.
Neither is an observed failure -- the committed path takes the
non-registering route, and the review found no actual registration or
eviction in it. The defect was in the commentary's reach, so the
commentary is what changes.
The block now separates three things it had merged: WHAT FOLLOWS FROM THE
CODE (the bound argument, labelled as an argument and not a run), WHAT WAS
EXECUTED (the registration-restoration mutation was run ONCE against an
arm that is NOT in this tree: this row returned false while the
neighbouring positive control on the same binary returned true, so the red
is authorable and discriminating -- and nothing committed re-derives that),
and WHAT NEITHER ESTABLISHES (the two claims above, kept as stated
limitations rather than deleted).
I did not paste the reviewer's suggested closing sentence, "the
registration-restoration mutation has not been executed against this row".
It was true when they wrote it and is false now -- I ran exactly that
mutation before the hold arrived. Pasting it would have put the same
defect class back in the row with the sign flipped.
Re-run on a binary rebuilt from the reverted source, all three controls
true. Worth recording why that sentence is here: the first re-run reported
this row FALSE, which was my own stale falsification binary, not a
regression -- the revert had not been rebuilt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
#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
#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
Review 65549, verified, and it is the most serious finding this PR has taken. THE ROSTER GRANDFATHERED THE WITNESSES THIS CHANGE ADDS. The generating floor run was cut PART-WAY THROUGH this lane, so three claims added by this very diff were discovered as population and enrolled as grandfathered on the day they were written: the_cpu_observation_is_still_carried_when_another_limit_fires, the_eval_step_standing_carries_both_figures_in_its_refusing_arm, and the calibration specimen itself. That is the escape hatch the roster exists to deny, in the words of its own header -- "a roster that admitted rows would let every expensive new witness be grandfathered on the day it landed". The calibration module states the same rule about the specimen BY NAME, recording that it was REDUCED so it would sit under the new-witness ceiling because "grandfathering would have granted exactly that exemption". It was granted anyway. Two paragraphs asserting the rule did not stop the mechanism breaking it, which is why DESIGN section 5 prefers construction to prose. STRIKING THEM IS A CONSTRUCTION CORRECTION, NOT A REMOVAL, and the distinction matters. A declared removal is a typed disposition for a row that was LEGITIMATELY a member at the cut and whose identity later died -- all_removals_name_roster_members requires every removal to name a row the roster still HOLDS, and floor_grandfathered_holds reads only the chunks, so a removal documents without subtracting. These three identities are LIVE and were never eligible, because the population they came from post-dates the cut the roster claims to be. A removal row would both fail that witness and misdescribe what happened. NOTHING IS HIDDEN, AND IT IS MEASURED. All three now face the new-witness tier and all three pass it: at required floor run 34759050978, artifact required-floor-claim-cost, they read 111, 87 and 55,011 eval_steps against a 100ms-of-work budget. The four identities of this lane that remain in the roster are exactly the four the declared removals name -- dead spellings, each with its disposition. TWO WITNESSES REPLACE THE TWO PARAGRAPHS. this_lane_s_own_new_witnesses_are_not_grandfathered asserts the three are absent, and a_struck_identity_selects_the_new_witness_tier asserts an absent name selects NewWitnessTier rather than falling through. Proven discriminating rather than assumed: re-inserting the specimen into a chunk fails both. A SECOND, PRE-EXISTING DRIFT SURFACED AND IS FIXED HERE. w_grandfather_population_matches_the_grounded_surface went red -- not from anything this PR changed, but because editing that witness's file is what makes the floor SELECT it. The authority gunbc.v1_interpreter_opaque_host_call carries the operation claim_scope_dag_multi_module_fixture, added by gunbc#11143; the v2-tower PROJECTION in this module did not. required_floor.dag's own prose says that list "is the v2-tower projection of that authority, NOT a second one", held together by exactly this executed two-way join. So adding the member is syncing a projection to an authority that already made the finding -- not growing a population by declaration, which the same paragraph forbids. The drift is on main and has been since #11143; this change surfaces and closes it. Also threads EvalStepCount through preemption_reachability's three call sites, which is the consumer the previous commit missed. Evidence: 20 eval-step-budget witnesses and 12 preemption-reachability witnesses pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HEXWMSsFt2oMwwXdn3LZzg
Prerequisite for the bare-name-ambiguity wall, landing ahead of it. Census instrument: #11078. Qualification batches: #11137, #11145, #11146.
Still a draft until the qualification batches merge, because the wall it enables must not land before the corpus is ready for it — but the instrument and the tier below are complete and their controls are run.
Why the wall is NOT in this PR
An earlier revision of this branch carried it, and the required floor refused with the wall's own words:
That is the refusal working. The corpus still carries 82 measured ambiguous reads because the qualification batches have not merged, so a wall landed now refuses the tree it exists to protect. Weakening it to green the lane would invert the point, so the wall was removed and lands on top of the qualifications instead.
The third resolution tier
site_resolved_fnanswered overfn_nodes, which is built frommodule.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 or imported by name. Measured: five such sites in the corpus census (property: Unitmeaning systemd'sUnit=;spelling: Intmeaning a C++ surface spelling).variant_arm_ownersindexes arm name → (declaring module, coproduct) and resolves only when exactly one visible coproduct declares the arm. Keyed on the coproduct rather than the module because 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 wall exists to catch.The tier is deliberately stricter than the two above it, which let the site's own module win unconditionally. They can: a top-level declaration in one's own module is the authored answer by construction. Arms carry no such precedence rule — an arm of one's own coproduct and an arm of an imported one are named with equal standing — so two visible coproducts refuse.
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.The fixture claim scope, and why it was needed
tools.multi_module_compile_fixtureroutes throughcompile_to_resolvedand never builds a claim scope, so nothing CI executes could reach a refusal living inclaim_scope_for. The corpus cannot host the red either — a module authored to carry one would refuse the whole floor rather than sit in it as a probe — andsrc/v1/stage0/tests/is compiled by clippy and run by nobody. DESIGN §4b names exactly this remedy: a state unrepresentable in the accepted corpus may still be representable as source handed to the compiler by a fixture.One detector, not two. The host function calls
claim_scope_for_with_memositself rather than re-deriving anything, so a refusal a control observes is the refusal the corpus floor raises.PreparedRepositoryis built entirely from the manifest; no corpus root is read.The controls are run, not described
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.
The red is pinned to its cause, and that was falsified rather than assumed.
claim_scope_was_refusedsays only that something refused; such a probe goes green the day an unrelated refusal fires first and is then cited as coverage for a cause it never observed.claim_scope_refusal_namesmatches the arm and requires the cause to nameEntryModuleOutsidePreparedSubject. Pointing the marker at a string the refusal does not contain turns that rowfalse— so the predicate reads the cause, not merely the arm.ClaimScopeInstrumentRefusedandClaimScopeCompileRefusedread false on both polarities, so a ragged manifest fails the positive and negative rows together rather than satisfying whichever was phrased as an absence.Ordering
Merge after #11137, #11145, #11146. The wall follows this PR.
🤖 Generated with Claude Code
https://claude.ai/code/session_01M5dKcSuYW3nvAjtVcDxqhT
v1 seed admission (added for review 64495)
This adds ~170 lines of hand-written Rust to the v1 seed — the host builtin, its projection, the dispatch rows and the registry row. That is growth, and the review is right that the diff did not say why it is admitted.
gunbc.v1_maintenance_standingv1_seed_standingsets a strict test: admitted when it serves the v2 self-host program, full stop.It is growth of an existing, already-reasoned class rather than a new one. The corpus has two nested-compile instruments —
gunbc.compile_diagnostic_censusandtools.multi_module_compile_fixture— and both route through a host builtin for a stated reason recorded atv1.tests.claim.reference_derived_disposition_census_witness: a nested compile is not evaluable in the interpreter, so the pipeline cannot be called from.dagat all. This is a third instrument of that same kind, for that same reason, one stage further along the same pipeline (scope construction rather than compile).Why it serves the self-host program, stated so it can be disputed rather than assumed: v2 is emitted by v1, so the v1 resolver's answers are the substrate v2 is built on. A resolution defect in the seed — a bare read settled by scope precedence rather than by anything the author wrote — propagates into everything v1 emits. This instrument is what lets a refusal for that class carry an executable red. Without it the wall is a check whose red cannot fire, which §4b calls worse than absent.
The honest qualification: that argument is about the seed's correctness, not about shrinking the seed, and this change makes the seed larger. I am not claiming it reduces v1. It is admitted on the ground that the class it protects is one v2 inherits, and it is worth a reviewer disputing that rather than my asserting it.
Dissolution trigger — the same one the precedent carries: a nested-execution capability in the interpreter, at which point these instruments stop needing a host builtin and become ordinary
.dag. That is the trigger already recorded for the two existing nested-compile instruments; this one does not mint a new one, because it is the same deferral grown rather than a second.