Skip to content

The third state of 0 -> 1: a derived module's binding to its generator's declared input - #10871

Merged
briansrls merged 9 commits into
mainfrom
fix/derived-binding-classification
Sep 9, 2026
Merged

briansrls merged 9 commits into
mainfrom
fix/derived-binding-classification

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

The wave-admission wall has refused every change that ADDS a failure-mode row file
since gunbc#10822, and admitted every change that edits one. Measured across five
lanes and seven changes with no exceptions: #10710, #10842 and #10837 refuse;
#10832, #10841, #10811 and #10835 pass. #10835 is the one that names the predicate
correctly -- it is additions-only by diffstat and PASSES, so "additive" is not the
discriminator and no diffstat can be. The predicate is a row MODULE THAT IS NEW AT
THE BASE, which is a question about state.

WHY IT REFUSED. binding_disposition reads 0 -> 1 through authorship: the target grew
a name this module was reaching for (a coincidence in the pool, cause elsewhere) versus
this module's own author writing what resolves a name it already spelled (the repair
the wall wants). THAT DISCRIMINATOR PRESUMES A MODULE THAT HAS AN AUTHOR. Since
gunbc#10822 the roster is generated from the row directory, so it has none:
authored_here is false for every binding it will ever acquire, and each new row read
as a coincidence. The membership arm already reached the opposite answer on the same
files -- an added row edge auto-admits as ExplicitlyEvaluatedZeroDelta, "reached by a
name this module authors" -- so the two arms disagreed about one file, which is the
tell that the disposition and not the population was wrong.

This is the SAME SHAPE as the 2026-08-27 split that created AuthoredReferenceResolution
after the wall refused gunbc#9485, and it lands the same way: one symbol carrying two
states with opposite owners and opposite repairs, separated rather than weakened.

WHAT IS ADMISSIBLE IS NOT "THE MODULE IS GENERATED", and that distinction is the whole
arm. Exempting the category would auto-admit every binding any generated module ever
acquires, on the one surface where a wrong binding has no human reader -- the same
state-space conflation committed in the fail-open direction. What is admissible is a
binding that is THE MECHANICAL IMAGE OF THE GENERATOR'S DECLARED INPUT RELATION:
derived_row_roster declares the roster is produced by reading ROW_MODULE's directory,
so a roster binding whose every candidate is a module of that directory is the
deterministic consequence of a file the change adds, decidable from the generator's own
constants rather than from a reader's judgement.

EVIDENCE, BOTH ARMS IN THIS COMMIT
a_derived_roster_binding_to_a_new_row_module_is_the_generators_declared_input
classifies DerivedGeneratorInputResolution AND adjudicates. Disabling the new arm
turns it RED, so the green is the fix's and not the fixture's.
a_derived_roster_binding_outside_its_generators_inputs_still_refuses
same derived module, same 0 -> 1, same absence of an author, target outside the
generator's inputs: stays NewPoolCoincidenceResolution and stays unadjudicated.
It is GREEN IN BOTH STATES -- with the arm and without it -- which is what makes it
a positive control rather than a mirror of the first test. If it ever greens as
admitted, the wall was widened rather than sharpened.
Full wall suite 52/52, including the vocabulary check that refuses when the host enum
and the .dag authority disagree about the coproduct.

THE FIXTURE ITSELF CARRIES A FINDING. A first version had the roster spell the row name
bare, and produced ZERO deltas -- because a row module is a SIBLING of the roster, so
the bare name resolved to nothing on both sides and the sets were equal. Both arms were
then asserting over an empty list: a test that cannot fail, for a reason unrelated to
what it claims to test. The generated roster imports each row explicitly, which is what
makes the candidate set move {} -> {module}, and the fixture now reproduces that
transition rather than resembling it -- verified against the subject and detail string
the production report emits.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01GwvzQ3SQoWWDgHkAeffMeF

Acceptance

Unblocks every change adding a failure-mode row module, not just the asker's. All five new-at-base modules across the three refusing PRs are direct children of ROW_MODULE with no nested directory, which is exactly the condition the predicate tests:

PR new module
#10710 …authored_quotation_terminates_the_string_it_is_authored_in
#10710 …unresolved_callee_conflated_with_dispatched_elsewhere
#10842 …declared_frontier_outlives_the_firing_of_its_own_trigger
#10842 …unresolved_name_is_reported_as_a_decidability_verdict
#10837 …handwritten_population_wrong_by_gain_and_by_loss

#10837 belongs to a lane unconnected to this one and is cleared by the same arm, not by a special case. That table is a structural argument; the executed proof for all three is CI on their own heads once this lands.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GwvzQ3SQoWWDgHkAeffMeF

gunbai-bot Bot and others added 2 commits September 9, 2026 00:43
…tor's declared input

The wave-admission wall has refused every change that ADDS a failure-mode row file
since gunbc#10822, and admitted every change that edits one. Measured across five
lanes and seven changes with no exceptions: #10710, #10842 and #10837 refuse;
#10832, #10841, #10811 and #10835 pass. #10835 is the one that names the predicate
correctly -- it is additions-only by diffstat and PASSES, so "additive" is not the
discriminator and no diffstat can be. The predicate is a row MODULE THAT IS NEW AT
THE BASE, which is a question about state.

WHY IT REFUSED. binding_disposition reads `0 -> 1` through authorship: the target grew
a name this module was reaching for (a coincidence in the pool, cause elsewhere) versus
this module's own author writing what resolves a name it already spelled (the repair
the wall wants). THAT DISCRIMINATOR PRESUMES A MODULE THAT HAS AN AUTHOR. Since
gunbc#10822 the roster is generated from the row directory, so it has none:
`authored_here` is false for every binding it will ever acquire, and each new row read
as a coincidence. The membership arm already reached the opposite answer on the same
files -- an added row edge auto-admits as ExplicitlyEvaluatedZeroDelta, "reached by a
name this module authors" -- so the two arms disagreed about one file, which is the
tell that the disposition and not the population was wrong.

This is the SAME SHAPE as the 2026-08-27 split that created AuthoredReferenceResolution
after the wall refused gunbc#9485, and it lands the same way: one symbol carrying two
states with opposite owners and opposite repairs, separated rather than weakened.

WHAT IS ADMISSIBLE IS NOT "THE MODULE IS GENERATED", and that distinction is the whole
arm. Exempting the category would auto-admit every binding any generated module ever
acquires, on the one surface where a wrong binding has no human reader -- the same
state-space conflation committed in the fail-open direction. What is admissible is a
binding that is THE MECHANICAL IMAGE OF THE GENERATOR'S DECLARED INPUT RELATION:
derived_row_roster declares the roster is produced by reading ROW_MODULE's directory,
so a roster binding whose every candidate is a module of that directory is the
deterministic consequence of a file the change adds, decidable from the generator's own
constants rather than from a reader's judgement.

EVIDENCE, BOTH ARMS IN THIS COMMIT
  a_derived_roster_binding_to_a_new_row_module_is_the_generators_declared_input
    classifies DerivedGeneratorInputResolution AND adjudicates. Disabling the new arm
    turns it RED, so the green is the fix's and not the fixture's.
  a_derived_roster_binding_outside_its_generators_inputs_still_refuses
    same derived module, same `0 -> 1`, same absence of an author, target outside the
    generator's inputs: stays NewPoolCoincidenceResolution and stays unadjudicated.
    It is GREEN IN BOTH STATES -- with the arm and without it -- which is what makes it
    a positive control rather than a mirror of the first test. If it ever greens as
    admitted, the wall was widened rather than sharpened.
Full wall suite 52/52, including the vocabulary check that refuses when the host enum
and the .dag authority disagree about the coproduct.

THE FIXTURE ITSELF CARRIES A FINDING. A first version had the roster spell the row name
bare, and produced ZERO deltas -- because a row module is a SIBLING of the roster, so
the bare name resolved to nothing on both sides and the sets were equal. Both arms were
then asserting over an empty list: a test that cannot fail, for a reason unrelated to
what it claims to test. The generated roster imports each row explicitly, which is what
makes the candidate set move `{} -> {module}`, and the fixture now reproduces that
transition rather than resembling it -- verified against the subject and detail string
the production report emits.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwvzQ3SQoWWDgHkAeffMeF
…ition is stated

review 62773, both findings verified against the tree and both real.

THE INTERLOCK ONE IS THE DEFECT I HAVE BEEN FILING ALL DAY, COMMITTED BY ME. The
partition paragraph enumerated FOUR auto-admitted dispositions; the arm I added made
it five, and I recorded the fifth only beside the arm. One authority then answered
the same question two ways -- a section 3 fork, and a stale-claim instance in
miniature: my edit was correct and it falsified a sentence elsewhere that nothing
joins to it. The sentence now carries the fifth member, with a note saying why it
belongs there rather than only at the declaration that introduced it.

THE SEED-GROWTH ONE: derived_generator_input_binding is enumerated in
hand_authored_declarations, in the CLASS A prose list, and in the trigger's
pure-fold list -- the three places that roster claims exact name-bijection, the
bijection gunbc#10856 repaired and which decays the moment a lane adds a declaration
without a row. Verified by IDENTITY JOIN rather than by count, filtered on
module_path: 43 rostered for this module against 43 declared, empty in both
directions. The unfiltered join reports a false positive (`dotted_chain`, a
legitimate row for v1_compiler.declaration_index), which is why the filter is part
of the check rather than a detail.

AND THE RECEIPT IS HONEST ABOUT WHAT THIS GROWTH BOUGHT: NOTHING WAS DELETED. No
scaffold removed, no fork consolidated; the count goes 42 to 43. What it buys is the
wall's ability to admit an append the generator itself produces, which before this
refused across five lanes and seven changes. The alternative adding NO declaration --
widening authored_here so every generated module counts as authored -- is the
fail-open direction of the conflation this split repairs, so the declaration is the
price of not weakening the wall. CLASS A, dissolving with its neighbours unchanged.

Wall suite 52/52 after both edits.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwvzQ3SQoWWDgHkAeffMeF
@gunbai-bot

gunbai-bot Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

Both findings in review 62773 verified against the tree and fixed in e5802ed89a.

The interlock one is the defect I have spent the day filing, committed by me. The partition paragraph enumerated four auto-admitted dispositions; my arm made it five, and I recorded the fifth only beside the arm. One authority then answered the same question two ways — §3 — and it is a stale_claim_survives_its_own_correct_edit instance in miniature: the edit was correct, and it falsified a sentence elsewhere that nothing joins to it. The partition sentence now carries the fifth member, with a note saying why it belongs there rather than only at the declaration that introduced it.

The seed-growth one. derived_generator_input_binding is now enumerated in hand_authored_declarations, in the CLASS A prose list, and in the trigger's pure-fold list — the three places that roster claims exact name-bijection.

Verified by identity join rather than count, filtered on module_path: 43 rostered for v1_compiler.namespace_wave_admission against 43 declared, empty in both directions. Worth stating because the unfiltered join reports a false positive — dotted_chain, a legitimate row for v1_compiler.declaration_index — so the filter is part of the check, not a detail. A count comparison would have read 44 vs 43 and sent me looking for a defect that is not there.

The hand-Rust receipt says plainly that nothing was deleted. No scaffold removed, no fork consolidated; 42 → 43. What it buys is the wall's ability to admit an append the generator itself produces, which before this refused across five lanes and seven changes. The alternative that would have added no declaration — widening authored_here so every generated module counts as authored — is the fail-open direction of the conflation this split repairs, so the declaration is the price of not weakening the wall rather than a convenience. CLASS A, dissolving with its neighbours unchanged.

Wall suite 52/52 after both edits, including the vocabulary check that refuses when the host enum and the .dag coproduct disagree.

— sent from quick-heron-85

…g_disposition

review 62782, verified. Inserting the new predicate directly above
binding_disposition attached that function's ENTIRE doc block to the new symbol --
"Which disposition a changed candidate SET carries", "EVERY ARM IS OVER SETS",
"`0 -> 1` IS TWO STATES", and the discriminator paragraph -- and left
binding_disposition, whose signature this PR changed, with no documentation at all.
The block also carried two summary lines for one item.

THIS IS THE SAME CLASS AS THE FINDING ONE ROUND EARLIER, and that is worth naming
rather than fixing quietly: a correct edit silently re-homed a claim about a
DIFFERENT symbol, with nothing joining the claim to the thing it describes. The
interlock partition sentence, the roster's bijection, and now this -- three
instances in one change, each caught by a reader and none by a mechanism.

Re-split so each block sits on the symbol it describes: the set-disposition and
third-state paragraphs on binding_disposition, only the generator-input paragraphs
on derived_generator_input_binding.

AND ONE THE REVIEW DID NOT RAISE, WHICH THE RE-SPLIT EXPOSED. That paragraph said
"the discriminator BELOW" -- a positional reference. The move happened to make it
accurate again, which is exactly why the form is wrong: a position silently
re-points under any edit above it and cannot be checked, which is what section 3's
cite-the-symbol rule is for. It now names `authored_here`.

Wall suite 52/52.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwvzQ3SQoWWDgHkAeffMeF
@gunbai-bot

gunbai-bot Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

Verified and fixed in 724ccc15d3.

The finding is right and it is a defect rather than a style note: inserting the new predicate directly above binding_disposition attached that function's entire doc block to the new symbol, leaving binding_disposition — whose signature this PR changed — with no documentation at all, and putting two summary lines on one item. Re-split so each block sits on the symbol it describes.

Worth naming rather than fixing quietly: this is the third instance of one class in this change. The interlock partition sentence, the seed-growth roster's bijection, and now this doc block — each a correct edit that silently re-homed or falsified a claim about a different symbol, with nothing joining the claim to the thing it describes. All three were caught by a reader; none by a mechanism. That is stale_claim_survives_its_own_correct_edit behaving exactly as its row predicts, in a change whose own subject is a wall that adjudicates deltas — which I think makes the row's next-rung trigger more interesting, not less.

One the review did not raise, which the re-split exposed. That paragraph said "the discriminator below" — a positional reference. Moving the block happened to make it accurate again, and that is precisely why the form is wrong: a position silently re-points under any edit above it and cannot be checked. §3's cite-the-symbol rule covers exactly this, so it now names authored_here instead.

Wall suite 52/52 after the re-split, and the classifier itself is unchanged by this commit — no arm, predicate, or test was touched, only where the prose attaches.

— sent from quick-heron-85

Brian Searls and others added 2 commits September 9, 2026 01:38
…r owns its module name

review 62792 (APPROVE, non-blocking) and it is worth fixing rather than deferring.
The wall recovered the roster's module name with
`ROSTER_BASENAME.strip_suffix(".dag").unwrap_or("roster")` -- a GUESS substituted
when the suffix is absent. It cannot fire today, but the arm it guards is an
AUTO-ADMISSION on a safety wall: respell that constant and the predicate keeps
comparing against a plausible fabricated name instead of refusing, which is the
fabricated plausible output section 5 forbids outright.

FIXED AT THE AUTHORITY RATHER THAN THE CONSUMER, which is the reviewer's sharper
half: the wall was re-deriving a name its GENERATOR owns. derived_row_roster now
declares ROSTER_MODULE, with the reason recorded there -- any consumer recovering
the name must decide what to do when the suffix is missing, and every such choice
is a guess about a name that module owns. The wall consumes the constant, so there
is no default left to guess: the state is unwritable rather than defaulted, which
is construction over a better fallback.

The seed-growth receipt records it honestly: this adds a constant to ANOTHER
module's roster and REMOVES a fabricated default from this one, rather than adding
capability here.

Wall suite 52/52, clippy --all-targets clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwvzQ3SQoWWDgHkAeffMeF
…al receipt

A consequence of the previous commit, caught before CI: derived_row_roster carries
its OWN seed-growth roster, so declaring ROSTER_MODULE there put THAT module's
name-bijection out by one -- the same decay review 62773 flagged on the wall's
roster, one module over. It is enumerated now, and the receipt records what the
addition actually is: it REMOVES a consumer's guess rather than adding capability.
One constant added, one strip-and-default recovery deleted from an auto-admission
path, no new host capability, dissolving with this row's existing trigger.

AND A NOTE ON THE INSTRUMENT, because it nearly produced a large wrong repair. My
first join over that file reported `rostered: 0, declared: 14` -- a module with
nothing enumerated at all. The roster was fine; my regex assumed multi-line
DeclarationRef blocks while that file writes them on ONE line. Trusting it would
have meant "repairing" fourteen rows that were already correct. A join is only as
good as its extractor, and an extractor that silently matches nothing reports the
same shape as a genuinely empty roster.

Wall suite 52/52; the generator's bijection is empty in both directions again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwvzQ3SQoWWDgHkAeffMeF
@gunbai-bot

gunbai-bot Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

Fixed in 3c1f517f7f and 2a9be56dba — the finding is worth acting on, and acting on it exposed a second one.

The fabricated default is gone, and the fix is at the authority rather than the consumer — which is the sharper half of your point. The wall was re-deriving a name its generator owns. derived_row_roster now declares ROSTER_MODULE directly, with the reason recorded there: any consumer recovering the name has to decide what to do when the suffix is absent, and every such choice is a guess about a name that module owns. The wall consumes the constant, so there is no default left to guess — the state is unwritable rather than defaulted. On an auto-admission path the consequence of the guess would have been a comparison that silently succeeds against a name nobody declares, instead of a refusal.

The consequence I caught before CI did: derived_row_roster carries its own seed-growth roster, so declaring the constant there put that module's name-bijection out by one — the same decay review 62773 flagged on the wall's roster, one module over. Enumerated, with a receipt stating what the addition is: one constant added, one strip-and-default recovery deleted, no new host capability.

And a note on the instrument, because it nearly produced a large wrong repair. My first join over that file reported rostered: 0, declared: 14 — a module with nothing enumerated at all. The roster was fine; my extractor assumed multi-line DeclarationRef blocks while that file writes them on one line. Trusting it would have meant "repairing" fourteen rows that were already correct. An extractor that silently matches nothing reports the same shape as a genuinely empty roster, which is the failure mode of every join whose extractor is unverified.

Wall suite 52/52 throughout, clippy --all-targets clean, and both bijections empty in both directions.

— sent from quick-heron-85

Brian Searls and others added 4 commits September 9, 2026 01:50
… one and union the reasoning

CONVERGENT EVOLUTION RATHER THAN A DISAGREEMENT, and the resolution follows from
that. While this PR was in review, main landed the IDENTICAL constant --
`ROSTER_MODULE = "gunbc.recurring_failure_mode.roster"` -- for the same section 3
reason, and consumes it in the generator body. So the conflict is two lanes reaching
one conclusion, and the correct resolution is ONE declaration rather than mine
winning.

Main's declaration stands. My separate one is gone. What my commit added survives as
the part main's doc did not carry: WHY it is a constant rather than a strip of the
filename -- a consumer recovering the name must choose what to do when `.dag` is
absent, and on the wave-admission wall that recovered name gates an AUTO-ADMISSION,
where a fabricated fallback compares against a plausible name instead of refusing.
The two doc blocks are unioned rather than one overwriting the other.

VERIFIED ON THE MERGED TREE, not assumed from a clean merge: one `pub const
ROSTER_MODULE`, zero conflict markers, NO duplicate roster row -- main had not
enumerated it, so the row this branch adds is what keeps derived_row_roster's
bijection exact, empty in both directions. Wall suite 52/52, clippy --all-targets
zero errors.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwvzQ3SQoWWDgHkAeffMeF
The arm trusts the generator's DECLARED inputs, and what it checks is the
declaration rather than the generator's behaviour. A generator whose implementation
drifts from what it declares -- reading a second directory, emitting a binding no
input explains -- would be auto-admitted against a stale premise, silently, because
that premise is precisely what the wall is not in a position to re-derive.

Recorded beside the arm because a residual risk that lives only in a review thread
is not reachable from the thing it qualifies. It is an honest boundary rather than a
rung: the ceiling is a generator whose declared inputs ARE its inputs by
construction, and until that exists the mitigation is that declaration and
implementation share one module, so drift is a same-file edit rather than action at
a distance.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwvzQ3SQoWWDgHkAeffMeF
…nd would need

The prose explained the arm well enough that a reader would reasonably conclude it
generalizes over generators with declared inputs. It does not: the realization
refuses every module that is not the failure-mode roster, so a second derived module
is refused exactly as the first was and the repair would be someone editing the
predicate to name it. That is a hand-maintained membership list where each member
costs an edit -- the shape gunbc#10822 has just finished deleting one layer up.

DISCLOSED RATHER THAN GENERALIZED, because the narrowness is probably right: it is
decided from that generator's OWN constants rather than a literal spelled in the
wall, and a general arm needs a carrier where a generator declares its input
relation. That carrier does not exist -- gunbc.generated_artifact's GeneratedArtifact
is a closed coproduct of artifact IDENTITIES and carries no inputs -- so there is
nothing for a general predicate to consult, and inventing one inside a required-gate
repair would be modelling a substrate concept to unblock a wall.

The absence is the trigger, and it is now stated in the authority rather than left
for the next author to discover by hitting a refusal and reading prose that overstates
its own reach. That failure -- an authority that keeps claiming what stopped being
true, with nothing reclassifying it -- is the class this lane filed a row about
yesterday.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwvzQ3SQoWWDgHkAeffMeF
…tion needed correcting

Main landed a much fuller doc block on ROSTER_MODULE than mine, including a
paragraph headed NOT THE NAMESPACE WAVE that corrects an earlier claim of mine.
That correction was true when it was written and this branch makes it false: the
wave's DISCOVERY still finds the roster by path and reads no constant, but the
new classifier derived_generator_input_binding reads ROSTER_MODULE to decide
whether the module under classification IS this generator, and ROW_MODULE to
decide whether what it binds to is a declared input.

So the resolution keeps main's block whole -- the speller pair, the fail-closed
divergence, the const-context trigger and the honest rung-1 reading of the
composition assertion -- and rewrites only that one paragraph to name the real
consumer. Folded into it is the reason my side existed at all, which main does
not say: the recovery-by-stripping alternative would put a fabricated default on
an AUTO-ADMISSION path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwvzQ3SQoWWDgHkAeffMeF
@briansrls
briansrls merged commit d2559c3 into main Sep 9, 2026
4 checks passed
@briansrls
briansrls deleted the fix/derived-binding-classification branch September 9, 2026 03:19
briansrls pushed a commit that referenced this pull request Sep 9, 2026
…classifies a delta that no longer occurs (#10889)

* Delete the derived-generator-input arm: #10856 fixed the root, so it classifies a delta that no longer occurs

#10871 auto-admits a `0 -> 1` binding on the derived failure-mode roster whose
every candidate is a module of the generator's declared input directory. That
delta no longer exists, and it was already gone when the arm merged.

#10856 (aba7939, 2026-09-08T18:51:35-04:00) fixed the ROOT. Its own doc block
states the mechanism: `roster.dag` is gitignored and written on the read path, so
a baseline reconstructed by dropping only diff-TOUCHED paths inherited the HEAD's
roster bytes as the BASE's. Base and head were the same bytes, so an ordinary
append read as not-locally-authored and classified NewPoolCoincidenceResolution.
With the base side derived from the base tree's row membership, an append
produces no binding delta at all.

#10871 (d2559c3) merged at 23:19:18 -- four and a half hours later --
classifying that symptom.

MEASURED, THREE RUNS ACROSS TWO BRANCHES, all on base 3480039:
DerivedGeneratorInputResolution count 0 in every floor log; NewPoolCoincidence-
Resolution count 0; no binding deltas at all. Both ledger PRs adjudicated on
membership alone.

Three DESIGN readings, all pointing the same way. Section 3: with the root fix
landed, the symptom classifier is a second structure answering one question, and
the surviving one is an attractor. Section 3c: its only consumers were the two
fixtures shipped with it. Section 5: a populationless arm that WIDENS what a
required gate auto-admits cannot go red, and will be cited as coverage of a class
it never sees.

The deletion is the census. If a real delta of that shape exists, the gate refuses
and names it -- which is the evidence the arm never had.

NO REGRESSION PROBE IS ADDED, AND THAT IS ARGUED RATHER THAN OMITTED. The obvious
worry is that the root fix could regress with nothing to catch it. #10856 already
enrolled that evidence: `the_base_side_is_the_base_listing_not_the_head_directory`
and `a_base_tree_with_no_row_files_has_no_roster_module_rather_than_an_empty_one`
in `derived_row_roster`, both passing here. A second probe would fork existing
evidence. What is true, and is a pre-existing declared drop rather than this
change's to repair, is that those are `#[cfg(test)]` under `repo_self_test_command`,
which no CI step runs -- `gunbc.rung_drop` `rust_unit_tests_off_the_merge_path`.
The evidence exists at rung 2 and does not execute on the merge path. That gap is
the same with or without this revert; the arm did not close it, because an
auto-admission cannot be evidence of anything.

Reverts #10871 (d2559c3) in full. Nothing has touched these files since, so
this is the exact inverse rather than a hand-reconstruction. 50 wall tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwvzQ3SQoWWDgHkAeffMeF

* Drop a stowaway: this branch was NOT the exact inverse it claimed to be

Review 62904 found `src/v2/test/claim/modules_under_container_test.dag` in a
commit whose own message calls itself the exact inverse of d2559c3. Verified,
all three ways it stated: the file is absent from origin/main, a clean revert of
that commit touches six files and this is a seventh, and the subject it imports --
`modules_under_container` -- is defined nowhere in the tree. It is residue from
the CLOSED #10836, whose FreeMonoid-returning version was withdrawn; it survived
as an untracked file in this worktree and I swept it in with `git add -A`.

So the commit added a test over a subject that does not exist (DESIGN section 6,
a new artifact with no final consumer) inside an operator-gated revert of a
required-gate arm, which is the last place unrelated work should ride along.

The claim was the worse half of the defect. "Exact inverse" was checkable and
false, and a reader who trusted it would not have looked -- the same shape as the
arm this branch deletes, where four reviewers checked that a thing was correct
and none checked that it was still needed. The revert IS a clean `git revert` of
d2559c3; the message asserted more than the diff delivered.

The six arm files are untouched by this commit and remain byte-for-byte the
inverse. The file is preserved outside the repo, not lost.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwvzQ3SQoWWDgHkAeffMeF

---------

Co-authored-by: Brian Searls <briansearls1@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 9, 2026
OPERATOR RULING REVERSED (2026-09-09), after review 5155887943 supplied a
DESIGN §3 reading that neither the earlier ruling nor my framing of it had.
The correction is mine to own: the three scopings I put to the operator were
all deletion-scoped, so the choice was made from a menu that never contained
the right option.

WHY THE DELETION WAS WRONG, from the passage rather than from preference. The
delete-first root here is the obsolete `func` DECLARATION FORM. This wall is
not another spelling of that fact -- it asks an independent safety question,
whether subject membership or occurrence binding changed without adjudication,
and its refusal WAS the deletion census doing its job. §3 says to fix a
surfaced dependent FORWARD from first principles, not to delete the question
it was enforcing. Two clauses decide it: a GAP-INTOLERANT BOUNDARY -- which a
required merge wall is -- keeps the STAGED form, Y built in shadow and then one
transition; and the minimum Y must PRESERVE EVERY REQUIRED REFUSAL or it has
erased a correctness distinction rather than completed the replacement.
Deleting with no Y did precisely that.

MY EARLIER ARGUMENT ANSWERED THE WRONG CARVE-OUT. I argued that freezing
preserves the refusal and so the carve-out could not apply. That addresses the
FROZEN carve-out; the applicable one is the STAGED carve-out, where preserving
the refusal is the REASON the wall holds the cut rather than an objection to it.

WHAT IS RESTORED, AND FROM WHERE. The module, its host realization and its
tests come from origin/main rather than from the deleted copy, so main's later
work on the wall survives -- including the #10871/#10889 disposition churn.
Roster membership, the executor phase, the interlock milestone, the status
row, the seed-growth justification and the two guarantee-stall rows are the
inverse of the deleting commit. `head_index` returns with the phase that was
its only consumer. The rung drop is DELETED rather than retired: nothing
dropped, so there is no drop to declare.

THE FAILURE-MODE ROW STAYS AND CHANGES ROLE. It is now a prerequisite rather
than a postmortem: the class is unchanged, its next-rung trigger is unchanged,
and it travels with the repair instead of being resolved by removing its only
specimen. §4b(4) keeps it enrolled as regression evidence after the climb.

CONSEQUENCE, STATED RATHER THAN DISCOVERED IN CI: with the wall restored this
branch's own wave-admission phase now refuses, because the grammar change is
exactly what it cannot read across revisions. That is the staged carve-out
working. The `func` cut lands only after revision-relative acquisition does.

`cargo clippy --all-targets -- -D warnings` exit 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZZi3QsDvibJqy8k8PwzZ9
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