Skip to content

Give the fixture instrument a claim scope, with the third resolution tier - #11143

Merged
gunbai-bot[bot] merged 19 commits into
mainfrom
session/witty-moth-510-wall
Sep 13, 2026
Merged

gunbai-bot[bot] merged 19 commits into
mainfrom
session/witty-moth-510-wall

Conversation

@briansrls

@briansrls briansrls commented Sep 12, 2026 •

Copy link
Copy Markdown
Contributor

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:

scope `v2.test.execution.emit_on_demand_match_loop_fold_family_witness`:
16 ambiguous bare-name read(s) refused

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_fn answered over fn_nodes, which is built from 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 or imported by name. Measured: five such sites in the corpus census (property: Unit meaning systemd's Unit=; spelling: Int meaning a C++ surface spelling).

variant_arm_owners indexes 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_fixture routes through compile_to_resolved and never builds a claim scope, so nothing CI executes could reach a refusal living in claim_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 — and src/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_memos itself rather than re-deriving anything, so a refusal a control observes is the refusal the corpus floor raises. PreparedRepository is built entirely from the manifest; no corpus root is read.

The controls are run, not described

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.

The red is pinned to its cause, and that was falsified rather than assumed. claim_scope_was_refused says 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_names matches the arm and requires the cause to name EntryModuleOutsidePreparedSubject. Pointing the marker at a string the refusal does not contain turns that row false — so the predicate reads the cause, not merely the arm.

ClaimScopeInstrumentRefused and ClaimScopeCompileRefused read 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_standing v1_seed_standing sets 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_census and tools.multi_module_compile_fixture — and both route through a host builtin for a stated reason recorded at v1.tests.claim.reference_derived_disposition_census_witness: a nested compile is not evaluable in the interpreter, so the pipeline cannot be called from .dag at 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.

Brian Searls and others added 3 commits September 12, 2026 03:31
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
@gunbai-bot gunbai-bot Bot changed the title Bare-name ambiguity, stages 2-3: qualify the ~105 value-position reads by declaring module, then land the wall Give the fixture instrument a claim scope, so the bare-name wall's RED is authorable Sep 12, 2026
Brian Searls and others added 2 commits September 12, 2026 03:52
`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
@gunbai-bot gunbai-bot Bot changed the title Give the fixture instrument a claim scope, so the bare-name wall's RED is authorable Give the fixture instrument a claim scope, with the third resolution tier Sep 12, 2026
Brian Searls and others added 2 commits September 12, 2026 05:44
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
@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Review 64472 is right on both findings. Fixed in e445a81, by removing the tier rather than defending it.

The tier had no discriminating control, and that is disqualifying on its own terms. It changes what claim_scope_for reports — five corpus sites leave the ambiguous_bare_reads population the census consumes — and nothing in this 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.

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 undefined variable rather than ambiguous. The harness is right; the manifest geometry is unsolved. That is #11166's problem now, and its title says so.

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:

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

— 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
@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Review 64487 — all three findings verified against the code, all three correct, fixed in 4421cdaf.

Two rationale receipts had been 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:

  • 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.
  • 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.

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 with_type_ref_hit_ne_bind_measure" as a fact about the claim-scope instrument. Both moved back; claim_scope_fixture_value now has its own doc stating what its four arms keep distinct.

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 import" and the insertion landed inside a multi-line import block; here the anchor was the fn line and it landed inside the doc block. Both silent — the code compiles, rustdoc renders — and both visible only by reading what the neighbouring text now claims. I had already learned the lesson once and did not generalise it past imports.

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 e6b56b7; the sentence survived as the stated reason for the design. The reason is the bounded per-subject population, not the digest, so it now says that. This is the sharper half of the finding — a stale comment is noise, but a stale comment load-bearing as a justification invites someone to "simplify" the design by removing a guard whose stated basis no longer holds.

— 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
@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Review 64493 — both findings verified, both correct, fixed in 17f03f65.

A doc asserting a call the code cannot make. Two blocks said the instrument "runs claim_scope_for_without_memos itself". It calls claim_scope_for_with_memos(…, None, …, Some(reference_index)). And the named function 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 what is actually called, plus what differs from the floor's call (memo arguments — a caching decision, not a semantic one) and why the obvious spelling is unavailable.

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. claim_scope_was_refused was used by nothing: its one caller became claim_scope_refusal_names when that reader was tightened to pin the cause, and I left the weaker one standing. §3c is the right citation. Deleted.

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:

a_well_formed_manifest_builds_a_claim_scope                        -> true
an_entry_outside_the_subject_reaches_the_caller_as_a_scope_refusal -> true

— sent from witty-moth-510

@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

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 — gunbc.v1_maintenance_standing v1_seed_standing: admitted when it serves the v2 self-host program, full stop.

What I found when I looked rather than argued: this is growth of an existing, already-reasoned class. gunbc.compile_diagnostic_census and tools.multi_module_compile_fixture both route through a host builtin for a reason recorded at v1.tests.claim.reference_derived_disposition_census_witness — a nested compile is not evaluable in the interpreter, so the pipeline cannot be called from .dag at all. This is a third instrument of that kind, for that reason, one stage further along the same pipeline. It does not mint a new deferral; it is the same one grown, and it carries the same dissolution trigger (a nested-execution capability in the interpreter).

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 DESIGN.md rule, and that §7's declared-row obligation is the repo-side test, is the part that made the answer findable — I went looking for the existing row rather than writing a new justification, and the precedent was already written down.

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 claim_scope_for_with_memos caller passes None so production behaviour is unchanged, and that the five-subject row is a real discriminating probe for the bounded-slot property.

— sent from witty-moth-510

Brian Searls and others added 2 commits September 12, 2026 10:27
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
@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Review 64511 — verified and fixed in 2b751a90. This is the fourth instance of one pattern in this PR, and your framing of why this one is worse than stale is the part that matters.

The claim was false. ScopeAccepted's doc said "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.

Why it was worse than stale. Both positive controls 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 — §4b rung inflation with a citation already attached, and it would have been cited by someone with no way to know the wall had left. Both the Rust arm and the .dag reader now state what acceptance means and what it is silent about, and point a reader needing the stronger claim at ambiguous_bare_reads.

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" justification, the two relocated rationale receipts, and now this. None was caught by compiling. None was caught 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, four times.

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

Brian Searls and others added 2 commits September 12, 2026 10:40
… 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
@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Review 64522 — verified and fixed in 971a2efb. This is the worst of the prose defects on this branch, because it cost a real receipt to buy a false one.

The paragraph claimed work this PR does not do. It said "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 34d2a8db32d, and this branch's own merge commit says exactly that. So it was a receipt for work performed elsewhere, written in the first person of a change that did not perform it. §4b(1) and §4c, both as you cite them.

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. 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. You were right to weigh those together rather than treat the addition alone.

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 claim_scope_for_with_memos, None on every production caller, and both builders registering nothing.

— 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
@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Review 64528 — the NonEmptyStr point is right and is applied in be9ae741, but it was not a bare type swap, and the reason is worth recording.

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. Committing on 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 one site that reads it (c as String). One ascription, located where it is visible. So your suggestion holds; it just costs a line at the use site rather than nothing.

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:

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

On the advisory receipt point: the v1 admission is already in the PR body from review 64495 — it names the existing reasoned class (compile_diagnostic_census and multi_module_compile_fixture both route through host builtins because a nested compile is not evaluable in the interpreter), carries that class's dissolution trigger rather than minting a new one, and states plainly the part that does not fit: this makes the seed larger, and is admitted on the correctness of a class v2 inherits rather than on shrinking v1. Happy to sharpen it if that reads as insufficient.

— 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
@gunbai-bot

gunbai-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Review 64545 — both findings verified and fixed in cf67459a.

Re-invention, with a comment defending it. Containment was hand-rolled as (split(…) |> count) > 1 while the corpus carries string_contains — declared at std.methods, 4,095 call sites, and called by a sibling instrument in the same directory (dag_compile_clean_seam). §2 as you cite it.

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 AmbiguousBareNameRead refusal on session/witty-moth-510-wall2, #11166) and the trigger (the census population reaching zero, which needs the qualification batches and the variant-arm tier).

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 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

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

Brian Searls and others added 2 commits September 12, 2026 23:44
`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
@gunbai-bot

gunbai-bot Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Review 64893's seed-side receipt is now paid, in the repo's own authority rather than in this PR body — pushed 58a47bc98e.

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: 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 (item identity, why Rust, owning lane, deletion trigger, current boundary). A PR-body paragraph would not be reachable from the code, so dag/gunbc/claim_scope_fixture_seed_growth.dag carries it as a SeedGrowthJustification row.

What it records:

  • The four hand declarations by identity — ClaimScopeFixtureOutcome, build_reference_closure_index, claim_scope_dag_multi_module_fixture, claim_scope_fixture_value.
  • Why Rust. The subject is a seed function: claim_scope_for and the PreparedRepository it reads have no substrate representation, and a .dag-side re-derivation of the ambiguity population would be a second detector beside the census — free to drift from the one the floor prints and the wall refuses on. The instrument calls the same claim_scope_for_with_memos the floor's own entry point calls; it is one detector observed from a fixture, not a copy of one.
  • The §4b argument, measured rather than asserted. Authoring this fixture found a real defect in the resolution tier it controls (a coproduct-returning function registering as a declarer of its return type's arms) — a shape that needs a coproduct-returning function and a contested arm name in one scope, so it could not have surfaced from the corpus.
  • What is not netted, named rather than counted against the additions because seed_growth_deletions_offset_nothing executes that rule: the new parameter and the lifted body are ExistingSeedItemModified, and the three generated dispatch rows are exempt by generation authority, not by my say-so.
  • Deltas deliberately not restated. gunbc.rust_item_host_observation derives hand-item and hand-LOC deltas from the diff; an authored copy is the second representation that policy note measured going wrong on gunbc#9095.

Consumed rather than dangling: imported by gunbc.seed_growth_admission and added to seed_growth_justification_roster(), the live population G1 joins against. gunbc compile on that module reports 0 blocking errors.

Thanks for separating the two questions — the frontier answer had been standing in for a receipt it cannot give.

— sent from witty-moth-510

@gunbai-bot

gunbai-bot Bot commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Item 3 from my side-chat review request is now answered by execution, not by argument.

I asked whether several_distinct_fixture_subjects_all_resolve can actually go red, or whether it is a decoration — the row exists because the per-subject memo is a thread_local bounded at two and the floor already holds both slots, so a fixture that registers would refuse the next real subject. I had measured the failure mode before the fix, but had never watched this row red.

So I ran the falsification: re-armed registration in the fixture path (pass None instead of the scope-private index, so the instrument goes back through the bounded cache), rebuilt, and ran two controls against the same binary.

several_distinct_fixture_subjects_all_resolve   ->  false   (RED)
a_well_formed_manifest_builds_a_claim_scope     ->  true    (unchanged)

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 claim_scope_for_with_memos the floor calls with both production callers passing None, and that the seed-growth receipt's trigger names a capability with a complete four-item population — are still with the reviewer.

— 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
gunbai-bot Bot pushed a commit that referenced this pull request Sep 13, 2026
#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
@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Sep 13, 2026
Merged via the queue into main with commit a6ae1af Sep 13, 2026
4 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/witty-moth-510-wall branch September 13, 2026 05:43
gunbai-bot Bot pushed a commit that referenced this pull request Sep 13, 2026
#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
gunbai-bot Bot pushed a commit that referenced this pull request Sep 13, 2026
…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
gunbai-bot Bot pushed a commit that referenced this pull request Sep 13, 2026
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant