diff --git a/DESIGN.md b/DESIGN.md index 336c46a4d67..e57ed42034e 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -116,6 +116,11 @@ At a service boundary, rung honesty has a commercial consequence: a dimension ma Every newly discovered error class — incident, review finding, runtime exception, falsifier divergence — files or updates one row: invalid state, harm, distinguishing facts, rung found at, ceiling with reason, next trigger. Declared drops are rostered in full — previous rung, temporary rung, reason, population, restoration trigger — in [docs/design-ledgers.md](docs/design-ledgers.md), authority `gunbc.rung_drop`. A drop is retired BY ITS TRIGGER AND BY NOTHING ELSE, so the trigger is the whole check. The ones standing today: +- **Heal job for generated artifacts** — declared 2026-09-01 +- **Six of the seven effect gates (one restored)** — declared 2026-09-01 +- **Rust fmt as a merge-path gate** — declared 2026-09-01 +- **Merge-admission stamping: the receipt has no producer** — declared 2026-09-01 +- **Falsifier cadence: exposure open, disposition NOT decided** — declared 2026-09-01 - **Stable per-claim cost qualification under a shared execution envelope** — declared 2026-09-01 - **Emitted-bytes fixture witnesses in a required lane** — declared 2026-09-01 - **Direct-call argument TYPE-COMPAT judgment inside v2.* modules (one of two arms; inhabitance still runs)** — declared 2026-09-01 @@ -230,6 +235,7 @@ One row per class, each carrying its recognition rule and its receipts, in [docs - `alias_resolution_collides_with_kernel_spelling` - `restored_bytes_reviewed_as_authorship` - `review_summary_inverts_roles_and_affirms_the_join` +- `fabricated_debt` - `yaml_inline_comment_ingested_as_scalar_content` - `accepted_source_emits_uncompilable_target` - `incidental_denominator_as_wall` diff --git a/dag/gunbc/recurring_failure_mode.dag b/dag/gunbc/recurring_failure_mode.dag index 629d20fd582..aef228218f2 100644 --- a/dag/gunbc/recurring_failure_mode.dag +++ b/dag/gunbc/recurring_failure_mode.dag @@ -194,6 +194,7 @@ data admitted_module_without_judged_standing: RecurringFailureMode = RecurringFa evidence: [], } +data fabricated_debt: RecurringFailureMode = RecurringFailureMode { identity: "fabricated_debt" as NonEmptyStr, authored: "**fabricated debt** (a declaration is authored for an exposure that does not exist, or that is already declared elsewhere, so the ledger grows a row whose trigger CANNOT FIRE because there is nothing to restore. It is the exact inverse of the unfiled gap and it is the more comfortable mistake: filing reads as diligence, the row survives review because every reviewer checks whether a declared drop is HONEST about its loss and none checks whether the loss is REAL, and the cost lands on whoever later tries to retire it. **THE HARM IS NOT MERELY CLUTTER, WHICH IS WHY IT IS A CLASS.** A drop is retired BY ITS TRIGGER AND BY NOTHING ELSE, so a row for a non-existent exposure is permanent by construction; it inflates the standing-drops list that DESIGN projects on every turn of every session, and the next reader plans against an exposure nobody has. A row DUPLICATING an existing declaration is worse still: it forks the single authority for one safety fact, so the two can be retired independently and the tree ends up asserting both that the class is dropped and that it is restored. **THE ORIGIN IS ALWAYS THE SAME, and naming it is the recognition rule: the population was read from a PARAGRAPH rather than measured from the tree.** A loss clause enumerates what was unguarded on the day it was written; capabilities return, get re-homed, or acquire their own declarations, and the sentence does not move. So the rule is: before authoring a drop, resolve every named item against the tree -- is this exposure live NOW, and does it already have a row? **TWO RECEIPTS, both caught before authoring, 2026-09-01, while splitting `gunbc.rung_drop` `floor_cut`'s six-capability loss into capability-grain rows.** (1) GENERATED-ARTIFACT DRIFT was on the loss clause's list and is RESTORED -- gunbc#9415 enrolled a required `generated-artifact` phase adjudicating every member of `committed_generated_artifacts`; the same paragraph elsewhere admits the phase took it off the list, so the row contradicted itself and a reader following the enumeration would have declared a drop for a live gate. It is now stated as a FRACTION, 1 of 7 discharged and 6 outstanding, because a population that shrinks silently cannot be checked. (2) THE PER-WITNESS EVAL DEADLINE was on the same list and ALREADY CARRIES ITS OWN DROP at `gunbc.witness_row_cost` `gunbc_ci_fast_lane_rule_note`; a second row would have been the section 3 fork, and it is cited from the sibling rows rather than re-declared. Six items on the paragraph, five real rows. **NEIGHBOURS, and the boundaries are what keep this from absorbing them.** Distinct from `unbacked_execution_claim`: there prose asserts a live relation that no authority backs, and the subject EXISTS while the claim about it is false; here the subject itself is absent and the claim of loss is the fabrication. Distinct from `rung inflation`, which reports a class as SAFER than its evidence supports -- this reports the tree as MORE EXPOSED than it is, and both mislead the same reader in opposite directions. Distinct from `restoration_promise_names_a_route_that_does_not_exist`, which is a REAL exposure with an unsatisfiable trigger; this is an unreal exposure, and the two are found by the same question asked at different ends -- does the trigger name something that exists, and does the LOSS name something that exists. **RUNG: 1 (mitigatable) -- caught by a reader resolving the population, which is exactly what happened here and is not a mechanism. CEILING: 3, since `does this exposure exist` is decidable for any loss expressed as a citation to a mechanism rather than as prose. NEXT-RUNG TRIGGER, a CAPABILITY: a drop row whose lost capability is carried as a resolvable citation to the mechanism that provided it, so a row declaring the loss of something the tree still has -- or something another row already declares -- fails to compile. Enumerating populations more carefully by hand does not retire it; it only executes this row's recognition rule once more.)" as NonEmptyStr, evidence: [] } data alias_resolution_collides_with_kernel_spelling: RecurringFailureMode = RecurringFailureMode { identity: "alias_resolution_collides_with_kernel_spelling" as NonEmptyStr, authored: "**an instrument resolves an alias, lands on a name that COLLIDES with a kernel spelling, and attributes the result to the kernel** (the reference under measurement is authored QUALIFIED and points at a type alias; the reader resolves the alias, arrives at the alias declaration's own name, and that name is also a kernel name -- so the row is attributed to the kernel identity, naming THE EXACT CARRIER THE QUALIFICATION WAS WRITTEN TO MOVE AWAY FROM. **IT DOES NOT FAIL TO ANSWER; IT ANSWERS CONFIDENTLY AND WRONGLY**, and that is the whole severity: a missing answer is visible to its consumer and an inverted one is not, so the two rank completely differently and only the second can be cited as evidence for the opposite of what holds. **Distinct from `instrument_output_read_as_subject_content`, and the boundary is worth stating because they were found in the same instrument in the same hour**: there a report is COMPLETE for the reporter and read as complete for the consumer, so the defect is in the READING; here the report is wrong on a specific row it does examine, so the defect is in the INSTRUMENT and no amount of careful reading recovers it. Also distinct from `hollow_alias`, which is about a second name minted for one concept: the alias here is legitimate modelling, and what fails is a reader of it. **SPECIMEN, with a discriminating probe executed on covered ground (2026-09-01, gunbc#9907 follow-up).** `v1.tests.claim.carrier_realization_census` reports, for two functions appended to `v2.compiler.tokenize` on adjacent lines with identical position kind, differing only in alias-versus-concrete: a param authored `std.determinism.Determinism` keeps its dotted name, while a param authored `v2.std.text.String` comes back as bare `String` attributed to ``. `v2.std.text` declares `type String = FreeMonoid`, so the alias name collides with the kernel spelling. Both probes produced rows (17661 -> 17663), which is what makes the negative half evidence rather than absence -- the positive control is the whole discriminator, and the same census had already produced a null result on an uncovered fixture whose emptiness was indistinguishable from confirmation. **CONSEQUENCE MEASURED, NOT IMAGINED**: read naively, the census contradicted the namespace wall about nine function declarations and would have been read as nine admission rows asserting a binding the carrier lacks, on a merged PR. The wall was right; the contradiction was this bug. **RUNG: MECHANICALLY PREVENTABLE AT BEST TODAY AND CURRENTLY UNENROLLED** -- the wrong answer is produced silently and nothing executes over it. The next-rung trigger is that two-line probe being ENROLLED as a discriminating RED in any covered module, which is cheap; a class whose RED is two lines and still does not execute has no excuse, and naming the cheapness is what makes it rank rather than sit. **Recognition rule**: wherever a reader resolves through an alias, ask whether the resolved name could collide with a name in a DIFFERENT namespace the reader also knows -- kernel, prelude, or ambient -- because at that point the reader cannot tell them apart and will pick one silently.)", evidence: [] } data yaml_inline_comment_ingested_as_scalar_content: RecurringFailureMode = RecurringFailureMode { identity: "yaml_inline_comment_ingested_as_scalar_content" as NonEmptyStr, @@ -261,6 +262,8 @@ data recurring_failure_mode_roster: List = [ alias_resolution_collides_with_kernel_spelling, restored_bytes_reviewed_as_authorship, review_summary_inverts_roles_and_affirms_the_join, + + fabricated_debt, yaml_inline_comment_ingested_as_scalar_content, accepted_source_emits_uncompilable_target, incidental_denominator_as_wall, diff --git a/dag/gunbc/rung_drop.dag b/dag/gunbc/rung_drop.dag index 324c5440640..eb765e1a179 100644 --- a/dag/gunbc/rung_drop.dag +++ b/dag/gunbc/rung_drop.dag @@ -72,7 +72,7 @@ type RungDrop { } -data floor_cut: RungDrop = RungDrop { identity: "floor_cut" as NonEmptyStr, subject: "CI required-run composition", declared: "2026-08-15", standing: Standing, authored: "CI — **RUNG DROP, DECLARED (2026-08-15, the floor cut).** WHAT WAS HERE: one composed floor pass, `claim_executor` with a `--plan-entry` naming `src/v2/workflow/ci_floor_plan.dag`, a v2 scheduler deciding batches from `gunbc.ci_spec`, a compile-clean gate ordered ahead of everything else, per-PR discovery over `CiSpec.discovery_scan_dirs`, and a 4-hourly `affected-set-falsifier` cadence carrying the whole-tree cold controls. **ALL OF IT IS DELETED** — the workflows (`ci.yml`, `falsifier.yml`, `falsifier-alert.yml`), their `.dag` authorities, and ~30 witness modules. This paragraph previously recited that invocation in the present tense; it was false the moment the cut landed, and a knowingly-false recital in the canonical authority is premise contamination — every session reading it plans against a command that does not exist. WHAT RUNS NOW: one emission, `gunbc.witness_floor_workflow` → `.github/workflows/witnesses.yml`, invoking our own binary once PER LANE — `claim_executor --required-ci --source-root dag --source-root src/v2 --required-lane build` and `... --required-lane witnesses`, in TWO PARALLEL JOBS (the 2026-08-25 split described below; the invocation named `--required-floor` until the 2026-08-20 consolidation, also described below, and that flag still exists and still runs the fold alone, it is simply no longer what CI calls) — whose floor phase folds every discovered witness through one prepared subject via `v1_compiler.cli_run` `run_required_floor`, whose admission, cost-line and preparation-safety policy is owned by `v2.workflow.required_floor` (this clause named that module as the symbol home until 2026-08-26; the module is real and the symbol does not resolve there, which is exactly the §3 defect the `--required-cited-symbol` census would have refused before its 2026-08-23 drop). No plan entry, no plan function, no batch id, no worker role, no selection flag: the fold has no such concepts to configure — which PRESERVES the 2026-08-13 operator directive that no SELECTION shrinks the roster, by construction rather than by a flag someone must remember to set. **That directive is about selection, and an earlier revision of this clause stated it as `the whole discovered roster runs unshrunk`, which is false of the DISCOVERED roster and true only of the ROUTED one.** Measured on main run `32553487573` (`967b5bc1b92`, 2026-08-22T05:06Z): `offered=11812 routed=10439 declined_long=543 declined_live=830`. 1373 discovered sites — 11.6% — are declined by HOME POLICY before the fold sees them, so `planned` is the routed roster and never the discovered one. The floor's own line is honest about this (`every discovered site is exactly one of these`); only this document overclaimed, and the overclaim is the load-bearing kind, because a reader who takes `the whole discovered roster runs` literally will conclude that authoring a witness is sufficient for it to execute. It is not: a witness under a long or live home is discovered, counted, and never run. The decline mechanism is not a selection flag and the directive is not violated by it — the two are different questions, and conflating them is what made one true sentence and one false sentence read as the same claim. That directive's own carrier (`corpus_selection_off_note`) died with the floor; `gunbc.ci_spec` retains the history and now points here. **THE FOLD NOW EXECUTES, measured 2026-08-19.** Green on main, the latest measured `32553487573` (`967b5bc1b92`, 2026-08-22T05:06Z): `planned=10439 executed=10439 terminal=10439 passed=10132 known_red_held=206 failed=0 stale_quarantine=0 route_gap_held=101 over_cost_line_diagnostic=35`, ~30 min wall. The counts previously cited here were run `32515441229` of 2026-08-21 (`offered=11615 routed=10253 … passed=9946`) and had gone stale by 197 offered sites in under twelve hours; they are replaced rather than annotated, because two count sets in one clause is two accounts of one fact. That this clause has now been re-pointed twice in three days is itself the measurement: a transcribed receipt line is a *positional* citation of a run's output — §3's rule reaches it, since no edit here invalidates it and it rots anyway — so the standing question is now DECIDED (operator ruling, 2026-08-24): **name the instrument, never transcribe its output.** A measurement is cited by naming the producer that re-derives it — the run, the flag, the committed script — and never by copying its numbers into prose, exactly as §3 requires a citation to name a symbol rather than a line, and for the same reason: a transcribed number is unreachable from the thing that owns it, so it rots without anyone touching either end. The counters above are retained under that rule as a declared exception with their producing run named, because this clause's subject IS the rung drop and a drop is unreadable without the magnitude it dropped by; every other transcription in the corpus is debt. The ruling was priced, not preferred: the parallel measurement corpus it governs was BANKRUPTED the same day — `docs/probes/` deleted whole, 195 files and 50,601 lines, boards and captures and instruments alike, leaving NO `.sh` or `.py` anywhere in the repository outside `.githooks` — after a board asserting a compiler mechanism as a live defect was found to have merged EIGHT SECONDS after the commit that fixed it, and to have named the emitter carrier when the actual repair was two lines in the model. A lane had already selected that mechanism as its next work on the board's authority. **THE INSTRUMENTS WENT WITH THE PROSE, and the reason decides what the rule means (operator ruling, 2026-08-24): an ad-hoc `.sh` or `.py` in this repository is §6 UNMODELED REALIZATION — raw shell implementing semantics already expressible in `.dag` — so if a measurement is worth re-deriving it is worth an entry point, and if it is not worth an entry point it is not an instrument but a one-off.** This was ruled against a live objection, recorded because the objection was correct on its own facts and still lost: a peer had re-run `curated_cargo_probe_one.sh` that same hour to re-derive the emission board's headline from source, so the scripts had real consumers — LANES, which a census of `.dag` consumers cannot see, and which is why an earlier revision of this clause reported them as dead. The ruling does not deny that consumer; it denies that a stray script is the right carrier for it. So `name the instrument` names a `.dag` entry point, and the rule needs no exception for a referent it deleted: what is deleted is everything that cannot be re-derived from the tree, and what re-derives it is modeled or it does not exist. That is the §2 cost of a second representation with no authority, arriving faster than it can be authored, and it is why a measurement document is presumed redundant rather than merely stale. WHAT THIS DOES NOT CLAIM: the cut leaves a named residue it does not repair — gitignore un-ignore rows for deleted paths, prose notes across ~20 modules citing them, and the witnesses above, all still green over dead names. That residue is the next cut, not a gap this one closed. **`executed` answers a narrower question than every reader asks of it: it counts a witness reaching the fold, not its assertion running.** A witness whose subject is a subprocess exit status is planned, discovered, and counted `executed` while it is REFUSED BY CONSTRUCTION at the hermetic boundary — `run_required_floor`'s hermetic envelope rejects the host effect via `shell.Test.IsExecutable` before the subprocess is reached, in about a millisecond, which also rules out a budget refusal on timing. This is CORRECT, not a gap: mocking that refusal to let such a witness run would pass it against a fabricated exit status, the exact fabricated-plausible-output failure the witness exists to catch. It is a boundary of what the hermetic floor can cover, named here beside the counters rather than left for a reader to rediscover. This clause previously read that no witness had executed and that the fold refused during preparation; that was true when written and is now false, and it is corrected in place rather than left standing until the rest of the paragraph can be rewritten — because a knowingly-false recital is premise contamination whichever direction it points, and this one had already cost real work: a session measuring the TestClaim orphan population read it, concluded the floor had never run, and raised a sequencing question about roster growth that does not exist. The rung drop below is unaffected: the fold running green establishes that the replacement executes, not that the re-add queue has closed. WHAT IS UNGUARDED IN THE MEANTIME, named rather than left to be rediscovered (the generated-artifact drift gates were on this list until the `generated-artifact` phase described below took them off it): heal, the seven effect gates, the fmt gate, merge-admission stamping, the falsifier cadence, and the per-witness eval deadline that `gunbc_ci_fast_lane_witness_eval_budget` used to arm (`gunbc.witness_row_cost` `gunbc_ci_fast_lane_rule_note` carries that one's own drop). Each is a separate re-add, each re-derived from its own first principles under its own operator agreement rather than restored from the deleted machinery. RESTORATION TRIGGER: this paragraph is rewritten as an ordinary present-tense description — not amended, rewritten in one pass — when the re-add queue closes. Until then it describes a rung drop, and describing the replacement as finished would be the inflation §4b names as worse than sitting low. **WHAT SURVIVES UNTOUCHED, enumerated rather than swept away with the bullet** — this paragraph replaced a longer one, and a prose row is deleted for one reason and takes everything in it unless its contents are enumerated first (the same rule that governs deleting a witness file whole): the compile-clean scope authority `tools.dag_compile_clean_scope` and its import-closure selection (`entry_file_touched_via_import_closure`) are live and unmodified by the cut — but **live is not reachable, and an earlier revision of this clause said only the first**. It read that what is gone is the CI *job* that invoked them and not the authority; both halves are true and together they license a false inference, because SURVIVING A CUT AND BEING CALLABLE ARE DIFFERENT PROPERTIES and only the first was checked. Measured 2026-08-20: `entry_file_touched_via_import_closure` and `compile_clean_scope_plan_for_ci` are private `fn`s with ZERO references anywhere under `src/v1/stage0/src/bin`, no CLI flag reaches them, and the only `pub` surfaces into that chain — `witness_layer_roots_compile_clean_check` / `_emit_check` — return `Bool`, so they answer *is it clean* and can never answer *which entries would be selected*. A reader planning against the old sentence would budget an afternoon and find no caller; that is premise contamination of the same class this paragraph already corrects itself for twice. The authority survives and the capability does not, until something exposes a counting entry point; the `regen_input_sources` import closure survives and is now read by `v1_compiler.required_regen_host` — but the `regen_stage0` binary that consumed it, and the `RegenVerifyGate` / `SelfHostStalenessGate` pair that invoked it, are DELETED at the root (the regen cut), so the self-host fixed point is answered by `claim_executor --required-regen-fixed-point` and by nothing else. **THAT FLAG IS INVOKED AGAIN AS OF 2026-08-20**, so this is one re-add off the queue below rather than a standing gap. It was re-added as two `witnesses.yml` steps ordered ahead of the floor and CONSOLIDATED the same day (operator directive: the phases belong `within the witnesses step and within the gunbc binary, not at a github actions job level`) into ONE step running the phases in ONE process. **THAT 2026-08-20 DIRECTIVE IS NOW PARTLY SUPERSEDED, BY THE SAME OPERATOR, ON 2026-08-25** — `we can add it as a parallel job in github actions - we can do the same for regen now, we have more runners` / `basically i would put regen + v2 full compile in one job, and witnesses into another one`. The stated reason is a change in supply, not a change of mind about the earlier argument: the phases are mutually independent, so composing them into one process made the required check's wall clock a SUM of things that could have been a MAX, and more runners make the MAX purchasable. **THE DIRECTIVE HAS TWO HALVES AND ONLY ONE IS SUPERSEDED, which is why this clause states both rather than replacing one ruling with another.** SURVIVES — *within the gunbc binary*: the phases still live in `claim_executor`, each job makes ONE invocation and names a LANE, and no step's precondition reads another phase's verdict. The step-ladder defect the consolidation fixed (an `if:` naming a sibling step, silently conjoined with GitHub's implicit `success()`, so a regen red disarmed the whole floor) cannot return, because no step's condition can reach another phase's outcome. SUPERSEDED — *not at a github actions job level*: PARALLELISM IS NOT EXPRESSIBLE IN THE BINARY. Two phases running concurrently means two runners, two checkouts and two toolchains, and one process on one runner can thread but cannot acquire a second machine — nor would we want it to, at the floor's measured ~9.4 GiB peak. So the lane boundary is a job boundary of necessity, and what the directive was protecting against — SEQUENCING and PRECONDITIONS leaking into YAML — is exactly what does not cross it: the two jobs carry no `needs` edge and no condition on each other, which is the whole content of running them in parallel. So the invocation named at the top of this paragraph is superseded three times over and is now, exactly: TWO LANE JOBS, `claim_executor --required-ci --source-root dag --source-root src/v2 --required-lane build` (regen's first-generation comparison, the v2-emission compile, the emitted-closure cargo phase and the partition-crate boundary) and the same command with `--required-lane witnesses` (the `.dag` parse sweep and the witness floor fold), plus a THIRD job that gates on both. **THAT THIRD JOB IS NOT DECORATION AND THE FIRST CUT OF THE SPLIT DID NOT HAVE IT, which is the more useful half of this entry.** A GitHub required status check is produced by the JOB, not by the workflow, and the repository's `passing CI` ruleset is active, carries NO bypass actors, and names exactly ONE required context: `witnesses`. So splitting the phases into a second job made regen and v2-emission NON-BLOCKING -- the required check would have gone green over a regen drift or a v2 emission break and the PR would have been mergeable. That is fail-open (§5), and strictly worse than the serial run it replaced, because the serial job carried every phase into the one context that gates. THE REPAIR IS AN AGGREGATION JOB RATHER THAN A RULESET EDIT: the floor lane is renamed `floor`, and the name `witnesses` moves to a job that `needs` both lanes and whose only step reads both results and exits nonzero unless both are `success`. **THE CONDITION THAT MAKES THAT JOB RUN IS AT THE JOB LEVEL, AND THE FIRST CUT OF THE AGGREGATOR PUT IT ONLY ON THE STEP** -- the same fail-open committed one level in, caught by review 55795 and independently by a peer session within minutes of each other. `needs` carries an implicit job-level condition: a job that declares `needs` and no `if` is SKIPPED when a needed job fails, a skipped job never reaches its steps, and a step-level `always()` cannot rescue a job that never started. The job therefore declares `always()`, and that is the ONE place in the emission that departs from the file's `!cancelled()` house guard, stated here because a reader who knows the convention will otherwise correct it back and reopen the hole. Every other guard decides whether a STEP runs inside a job that is already running; this one decides WHETHER THE REQUIRED CONTEXT EXISTS AT ALL, and under `!cancelled()` a cancelled run leaves it skipped rather than answered. That turns the outcome on a question about GitHub nobody here has executed -- does a skipped or cancelled required check block a merge -- and the right response is not to measure it but to make the answer not matter: under `always()` the job always runs, always reads both results, and always reports on its own terms, so SKIPPED disappears from the required context. Construction over validation (§5), at the cost that a lawfully superseded run now reports this context red rather than cancelled, which is the correct reading rather than a regression. The two lane jobs still carry no `needs` edge on each other and still start together; only the aggregator waits. A ruleset edit would have worked too and was rejected on a boundary this document already records: the ruleset is not a `.dag` fact, so landing a change whose safety depends on someone editing a setting afterwards is a coverage gap with a promise attached and a real unguarded window. **THAT BOUNDARY MOVED, AND THE DECISION IT SUPPORTED DOES NOT.** `gunbc.repo_ruleset` now declares the desired ruleset -- enforcement, target, ref-name condition, the three rules, and the ONE required context, imported from `gunbc.witness_floor_workflow` `witness_floor_workflow_job_id` rather than spelled a second time -- observes the live one through `extdeps.github.rulesets`, reconciles the context roster through `gunbc.membership_reconcile`, applies drift with the whole-ruleset PUT, and READS BACK, claiming convergence only from the second observation and never from the apply's own 200. So the sentence in this bullet stating what the ruleset requires is no longer the only place that fact lives on our side of the boundary: `converge` actuates it and `verify` refuses on any divergence, with a typed reason per way it can diverge. WHAT DID NOT CHANGE, and why the aggregation job stays: convergence is an ACTUATION WITH A READ-BACK, not a wall. Nothing in this repository can constrain what GitHub admits to main, so an in-repo authority still cannot make a required context exist at the moment a merge is attempted -- it can only declare, apply and detect. The first cut's window argument therefore stands on its own terms; what is closed is the invisibility, not the boundary. WHAT IS NOT CLAIMED: NEITHER ENTRY POINT IS ENROLLED IN CI. `verify` is a route somebody runs, and until a required phase invokes it the class sits at *mitigatable* -- a drift is now detectable rather than detected, which is a real climb from unobservable and is not the same as a gate. Its next-rung trigger is that enrolment, which is a separate change under its own operator agreement. Found in review of gunbc#9203, against the live ruleset rather than against the workflow -- which is the only place the fact is visible, since nothing in the emitted YAML says which of its jobs gates. The partition is total by construction — `RequiredCiPhase::lane` is an exhaustive match, so a phase belonging to no job fails to compile rather than going silently unmeasured — and the lane is the ONLY thing the transport names: which phases a lane owns is decided in the binary, never in the YAML. **THE v2-EMISSION PHASE'S SUBJECT WIDENED IN THE SAME CHANGE**, from `dag/std/abi.dag` (the smallest entry in the tree) to `src/v2/compiler/00_compile.dag` (the v2 pipeline root, the widest closure one entry names). The row is `gunbc.ci_layer_roots` `required_v2_emission_entries` and it remains a cost decision rather than a Rust edit; what changed is the denominator, since the build lane's cost is now free up to the floor's duration rather than added to it. **WHAT THE SPLIT DOES NOT DO:** it restores nothing else from the deleted floor machinery — every item on the unguarded list above is still its own re-add under its own operator agreement — and it lands NO ratchet over the v2 compile's advisory-diagnostic population. That population is real and is the natural next subject, but a merge-blocking count pinned to a number measured on the current tree is exactly the oracle §5 forbids; an identity-grain monotone debt contract is a separate construction and is not claimed here. **THE PARSE PHASE STOPPED BEING src/v1-ONLY, 2026-08-23**, and it is stated here because the previous revision named the phase by the one root it walked. It now sweeps `src/v1`, `dag` and `src/v2` from one roster (`v1_compiler.cli_run` `DAG_PARSE_SWEEP_ROOTS`), shared with the standalone bin, and it admits source annotations per file rather than parsing alone -- `tokenize` routes `//` into the annotation channel and `parse` never decides grain, so the old walk returned clean for a file carrying an in-body annotation and the §4c refusal surfaced only at the floor's strict PREPARATION, where no witness executes at all. That is not a widening of the floor's source roots, which `gunbc.ci_layer_roots` `v1_dead_witness_tree_triage_receipt_remainder` rules out on NAME RESOLUTION grounds: this walk resolves nothing across files, so that objection cannot reach it. **THE PHASE ROSTER WAS CUT TO THREE BY OPERATOR RULING, 2026-08-21, WAS FOUR AGAIN AS OF #9035, AND IS FIVE AS OF THE PARTITION-CRATE PHASE, AND IS SIX AS OF THE EMIT-COMPILE PHASE.** The count is stated in the present tense here and it has now been wrong in BOTH directions, which is the reason it is written as a measurement rather than as a recollection: an earlier revision said four while enumerating a determinism pass no required run performed, that was corrected to three, and the three then went stale when #9035 enrolled a v2-emission phase that compiles one v2 entry — landed precisely because an emission break reached main and no gate could see it. The instrument is the required mode itself, which prints its own roster before any phase runs -- one `phase ` line per phase the lane owns and one `ROUTED to lane ` line per phase it does not, then `lane= phases_run=`. Read the roster from that announcement rather than from this sentence: the count moved twice in five days, and a transcribed roster size is exactly the positional citation the ruling above forbids. The fifth phase is `partition-crates`, in the build lane, which compares the derived stage0 partition's committed `lib.rs` and `Cargo.toml` against what `v1.compiler.stage0_crates` renders from the authority -- landed because those seven crates are workspace members nothing in CI builds, so a broken one sat on main while every required lane stayed green. **THAT COUNT IS NOW A PROPERTY OF THE ROSTER AND NOT OF A RUN**, because the 2026-08-25 split partitions the four across two jobs: a lane's own summary line reports `lane= phases_run=`, and each job additionally prints a `ROUTED to lane ` line for every phase it does not own, so one job's log still names the whole roster and where the rest is being measured. Reading a single job's `phases_run` as the roster size is the error that line exists to prevent. **A SIXTH PHASE, `generated-artifact`, IS THE FIRST ITEM TAKEN OFF THE UNGUARDED LIST ABOVE RATHER THAN A NEW SUBJECT.** It adjudicates every member of `gunbc.generated_artifact` `committed_generated_artifacts` against what its own authority generates, through the pure per-path projection `gunbc.generated_artifact_emit` `generated_artifact_body_for_path`, hosted by `v1_compiler.cli_run` `run_generated_artifact_boundary` in the build lane. THE PRODUCER WAS NEVER MISSING AND THE CALLER WAS, which is why this is a re-add and not a construction: `main_wet` on `dag/gunbc/instruments/generated_artifact_gate.dag` has always written these files and the projection has always been able to say what each path ought to hold, but from the floor cut until this phase the only route that ASKED it was `claim_executor`'s behavioural-receipt census, which asks only about paths of the form `src/v1/stage0/src/` because its subject is emitted Rust mirrors. So `DESIGN.md` and `ROADMAP.md` -- projections of `gunbc.design_document` and `gunbc.roadmap_authority` -- were computed by nothing and compared by nothing, and were maintained BY HAND in lockstep with their authorities. That is not a hypothetical: gunbc#9392 found the accumulated result the only way an unguarded artifact is ever found, by accident while doing something else, 2198 characters into the drift, and this document's own §4b(3) clause was among the text standing in the artifact with no authority behind it. **AND THE FIRST THING IT FOUND WAS NOT DRIFT, WHICH IS THE REUSABLE HALF.** Two of its four opening reds were ABSENT rather than drifted, and one of those markdown files had been DELETED ON PURPOSE by a295e17415, whose entire subject is the ruling that the .dag carrier is the authority. Regenerating it would have performed exactly what that commit refused, and the gate would then have gone green over the resurrection -- enforcing, permanently, the reverse of a decision already taken. THE GENERAL SHAPE: **a drift gate makes whatever it adjudicates BINDING**, so an absence that was inert before the gate becomes a line-stop after it, and the cheapest way to move the line is to regenerate. A dormant registry mistake is thereby converted into a standing obligation to recreate deleted files, silently, because the green looks identical either way. The stale half is the REGISTRY ROW and not the missing file, so the repair runs the other way: `gunbc.plan` `PlanProjection` makes a plan declare whether its markdown is a committed artifact at all, `PlanIsAuthorityOnly` carries the ruling that removed the projection, and the plan stays rostered, generated and refusable -- only whether its bytes are expected on disk changes. The rule for the next gate: **before a new adjudicator's first red is closed by producing the thing it says is missing, establish that the thing was ever supposed to exist.** WHAT THE PHASE DOES NOT CLAIM: it is READ-ONLY by construction -- there is no write path in it and no flag that opens one, because a gate that can also write its own subject is a gate whose green proves nothing -- and it restores nothing else from the deleted machinery; heal, the seven effect gates, the fmt gate, merge-admission stamping and the falsifier cadence remain their own re-adds. Its roster is ASKED of the authority, so an artifact added to `generated_artifact_registry` is enrolled with no edit to the host, and a rostered member that reaches NO verdict is counted and reported separately from a drifted one and stops the line on its own -- `0 drifted` over a population nothing asked about is the execution-provenance loss this document names, and the two counts are what keep it unrepresentable. **THAT COUNT IS NOW A PROPERTY OF THE ROSTER AND NOT OF A RUN**, because the 2026-08-25 split partitions the four across two jobs: a lane's own summary line reports `lane= phases_run=`, and each job additionally prints a `ROUTED to lane ` line for every phase it does not own, so one job's log still names the whole roster and where the rest is being measured. Reading a single job's `phases_run` as the roster size is the error that line exists to prevent. The five phases the 2026-08-21 ruling deleted stay deleted and are enumerated below; neither #9035 nor the partition-crate phase restored any of them, each added a new one, so both are roster ADDITIONS and not a reversal of that ruling. Five phases were deleted from the mode: merge-admission-capture, the regen determinism (fixed-point) pass and its in-memory pass-1 digest handoff, the behavioral receipt's controlled-fixture selftest, the behavioral receipt against the authorities a diff changed, and merge-admission-stamp. They were deleted rather than left reporting SKIPPED, because a phase whose only reachable state is a non-verdict has a deficit frequency of zero by construction and still reads as coverage on the ledger (§5, the absorbing fallback). The capabilities survive at their own entry points — `--required-regen-fixed-point`, `//gunbc/instruments:behavioral-receipt-plan`, `//gunbc/instruments:behavioral-receipt-selftest`, `//gunbc/instruments:behavioral-receipt-census` — none of which any workflow invokes; what ended is their enrolment in the required run, and the three measurements they carried (regen determinism, behavioural equivalence of a changed authority against its mirror, and the receipt's own discriminating arms) are simply no longer taken. That is a declared scope narrowing, and it returns merge-admission stamping to the unguarded list above rather than removing it from it. The remaining three phases are independent — the one real data dependency left with the phase that consumed it — so every phase runs even after an earlier failure and the run reports the complete ledger instead of letting the first defect hide the rest. The line still stops on any failed phase. It is recorded here with what made the gap real, because the steps were enrolled, STRIPPED, and re-enrolled inside twelve hours and a reader who finds only the enrolment will re-derive the strip. The strip was correct when made: the admission test is whether every red is closable by the author who caused it at the moment they caused it, and it was not -- the comparator normalized BOTH sides through rustfmt while writing the single-pass form, so after any candidate install the comparison was `normalize(normalize(emitted))` against `normalize(emitted)`, an identity only if rustfmt is idempotent. It is not, so the gate refused a tree byte-identical to its own artifact, permanently, and its only reachable green was the hand-edited mirror the gate exists to refuse -- a gate whose sole closing move is the forbidden action is not strict, it launders. Repairing it by raw-comparing the single-pass bytes then put it in direct contradiction with `cargo fmt --all --check`, which re-formats what is committed and so demands the NEXT pass: two gates consuming different passes of one artifact, each breaking the other. The resolution is that the emitted artifact is now written as a FIXED POINT of the formatter (bounded, exceeding the bound is a typed refusal), which makes the contradiction unrepresentable rather than detected and makes `cargo fmt` a no-op on it by definition -- the §5 construction move, and the general lesson is that any artifact with two consumers that normalize it must be stored in the normalizer's fixed point or the two consumers cannot both be satisfied. This clause previously read that the fixed point and its closure both survived with only their job removed; that was true when written and the regen cut falsified its first half, so it is rewritten here rather than annotated — a second sentence beside it would be two accounts of one fact; and parse remains grammar-owned — `ingest_yaml_source` (`dag/extdeps/languages/yaml/ingest.dag`), no shell or host parser — which was never a floor fact at all and is restated here so that dropping the bullet does not drop it. **TWO OPERATOR RULINGS ALSO LIVED IN THE REPLACED BULLET AND STILL HOLD**, restated because a ruling about what CI does *not* do is invisible once the paragraph describing CI is rewritten, and nothing in the new mechanism would contradict it loudly: the Rust test suite was removed from CI 2026-07-11 (operator ruling, recorded at `gunbc.commit_workflow` `commit_gate_rust_suite_removed_disposition`) and runs locally only; and clippy was removed from CI 2026-07-08, because a crate-wide `#![allow(clippy::all)]` made it zero-signal over ~44 minutes per run, leaving it a local dev check. Neither is reinstated by the replacement, and neither is the floor cut's to reverse." } +data floor_cut: RungDrop = RungDrop { identity: "floor_cut" as NonEmptyStr, subject: "CI required-run composition", declared: "2026-08-15", standing: Standing, authored: "CI — **RUNG DROP, DECLARED (2026-08-15, the floor cut).** WHAT WAS HERE: one composed floor pass, `claim_executor` with a `--plan-entry` naming `src/v2/workflow/ci_floor_plan.dag`, a v2 scheduler deciding batches from `gunbc.ci_spec`, a compile-clean gate ordered ahead of everything else, per-PR discovery over `CiSpec.discovery_scan_dirs`, and a 4-hourly `affected-set-falsifier` cadence carrying the whole-tree cold controls. **ALL OF IT IS DELETED** — the workflows (`ci.yml`, `falsifier.yml`, `falsifier-alert.yml`), their `.dag` authorities, and ~30 witness modules. This paragraph previously recited that invocation in the present tense; it was false the moment the cut landed, and a knowingly-false recital in the canonical authority is premise contamination — every session reading it plans against a command that does not exist. WHAT RUNS NOW: one emission, `gunbc.witness_floor_workflow` → `.github/workflows/witnesses.yml`, invoking our own binary once PER LANE — `claim_executor --required-ci --source-root dag --source-root src/v2 --required-lane build` and `... --required-lane witnesses`, in TWO PARALLEL JOBS (the 2026-08-25 split described below; the invocation named `--required-floor` until the 2026-08-20 consolidation, also described below, and that flag still exists and still runs the fold alone, it is simply no longer what CI calls) — whose floor phase folds every discovered witness through one prepared subject via `v1_compiler.cli_run` `run_required_floor`, whose admission, cost-line and preparation-safety policy is owned by `v2.workflow.required_floor` (this clause named that module as the symbol home until 2026-08-26; the module is real and the symbol does not resolve there, which is exactly the §3 defect the `--required-cited-symbol` census would have refused before its 2026-08-23 drop). No plan entry, no plan function, no batch id, no worker role, no selection flag: the fold has no such concepts to configure — which PRESERVES the 2026-08-13 operator directive that no SELECTION shrinks the roster, by construction rather than by a flag someone must remember to set. **That directive is about selection, and an earlier revision of this clause stated it as `the whole discovered roster runs unshrunk`, which is false of the DISCOVERED roster and true only of the ROUTED one.** Measured on main run `32553487573` (`967b5bc1b92`, 2026-08-22T05:06Z): `offered=11812 routed=10439 declined_long=543 declined_live=830`. 1373 discovered sites — 11.6% — are declined by HOME POLICY before the fold sees them, so `planned` is the routed roster and never the discovered one. The floor's own line is honest about this (`every discovered site is exactly one of these`); only this document overclaimed, and the overclaim is the load-bearing kind, because a reader who takes `the whole discovered roster runs` literally will conclude that authoring a witness is sufficient for it to execute. It is not: a witness under a long or live home is discovered, counted, and never run. The decline mechanism is not a selection flag and the directive is not violated by it — the two are different questions, and conflating them is what made one true sentence and one false sentence read as the same claim. That directive's own carrier (`corpus_selection_off_note`) died with the floor; `gunbc.ci_spec` retains the history and now points here. **THE FOLD NOW EXECUTES, measured 2026-08-19.** Green on main, the latest measured `32553487573` (`967b5bc1b92`, 2026-08-22T05:06Z): `planned=10439 executed=10439 terminal=10439 passed=10132 known_red_held=206 failed=0 stale_quarantine=0 route_gap_held=101 over_cost_line_diagnostic=35`, ~30 min wall. The counts previously cited here were run `32515441229` of 2026-08-21 (`offered=11615 routed=10253 … passed=9946`) and had gone stale by 197 offered sites in under twelve hours; they are replaced rather than annotated, because two count sets in one clause is two accounts of one fact. That this clause has now been re-pointed twice in three days is itself the measurement: a transcribed receipt line is a *positional* citation of a run's output — §3's rule reaches it, since no edit here invalidates it and it rots anyway — so the standing question is now DECIDED (operator ruling, 2026-08-24): **name the instrument, never transcribe its output.** A measurement is cited by naming the producer that re-derives it — the run, the flag, the committed script — and never by copying its numbers into prose, exactly as §3 requires a citation to name a symbol rather than a line, and for the same reason: a transcribed number is unreachable from the thing that owns it, so it rots without anyone touching either end. The counters above are retained under that rule as a declared exception with their producing run named, because this clause's subject IS the rung drop and a drop is unreadable without the magnitude it dropped by; every other transcription in the corpus is debt. The ruling was priced, not preferred: the parallel measurement corpus it governs was BANKRUPTED the same day — `docs/probes/` deleted whole, 195 files and 50,601 lines, boards and captures and instruments alike, leaving NO `.sh` or `.py` anywhere in the repository outside `.githooks` — after a board asserting a compiler mechanism as a live defect was found to have merged EIGHT SECONDS after the commit that fixed it, and to have named the emitter carrier when the actual repair was two lines in the model. A lane had already selected that mechanism as its next work on the board's authority. **THE INSTRUMENTS WENT WITH THE PROSE, and the reason decides what the rule means (operator ruling, 2026-08-24): an ad-hoc `.sh` or `.py` in this repository is §6 UNMODELED REALIZATION — raw shell implementing semantics already expressible in `.dag` — so if a measurement is worth re-deriving it is worth an entry point, and if it is not worth an entry point it is not an instrument but a one-off.** This was ruled against a live objection, recorded because the objection was correct on its own facts and still lost: a peer had re-run `curated_cargo_probe_one.sh` that same hour to re-derive the emission board's headline from source, so the scripts had real consumers — LANES, which a census of `.dag` consumers cannot see, and which is why an earlier revision of this clause reported them as dead. The ruling does not deny that consumer; it denies that a stray script is the right carrier for it. So `name the instrument` names a `.dag` entry point, and the rule needs no exception for a referent it deleted: what is deleted is everything that cannot be re-derived from the tree, and what re-derives it is modeled or it does not exist. That is the §2 cost of a second representation with no authority, arriving faster than it can be authored, and it is why a measurement document is presumed redundant rather than merely stale. WHAT THIS DOES NOT CLAIM: the cut leaves a named residue it does not repair — gitignore un-ignore rows for deleted paths, prose notes across ~20 modules citing them, and the witnesses above, all still green over dead names. That residue is the next cut, not a gap this one closed. **`executed` answers a narrower question than every reader asks of it: it counts a witness reaching the fold, not its assertion running.** A witness whose subject is a subprocess exit status is planned, discovered, and counted `executed` while it is REFUSED BY CONSTRUCTION at the hermetic boundary — `run_required_floor`'s hermetic envelope rejects the host effect via `shell.Test.IsExecutable` before the subprocess is reached, in about a millisecond, which also rules out a budget refusal on timing. This is CORRECT, not a gap: mocking that refusal to let such a witness run would pass it against a fabricated exit status, the exact fabricated-plausible-output failure the witness exists to catch. It is a boundary of what the hermetic floor can cover, named here beside the counters rather than left for a reader to rediscover. This clause previously read that no witness had executed and that the fold refused during preparation; that was true when written and is now false, and it is corrected in place rather than left standing until the rest of the paragraph can be rewritten — because a knowingly-false recital is premise contamination whichever direction it points, and this one had already cost real work: a session measuring the TestClaim orphan population read it, concluded the floor had never run, and raised a sequencing question about roster growth that does not exist. The rung drop below is unaffected: the fold running green establishes that the replacement executes, not that the re-add queue has closed. WHAT IS UNGUARDED IN THE MEANTIME, named rather than left to be rediscovered (the generated-artifact drift gates were on this list until the `generated-artifact` phase described below took them off it): heal, the seven effect gates, the fmt gate, merge-admission stamping, the falsifier cadence, and the per-witness eval deadline that `gunbc_ci_fast_lane_witness_eval_budget` used to arm (`gunbc.witness_row_cost` `gunbc_ci_fast_lane_rule_note` carries that one's own drop). Each is a separate re-add, each re-derived from its own first principles under its own operator agreement rather than restored from the deleted machinery. RESTORATION TRIGGER, REPLACED 2026-09-01 BECAUSE THE ORIGINAL NAMED AN OBJECT THAT DOES NOT EXIST: this row's exposure is declared at CAPABILITY GRAIN in five sibling rows -- `floor_cut_heal`, `floor_cut_effect_gates`, `floor_cut_fmt_gate`, `floor_cut_merge_admission_stamping` and `floor_cut_falsifier_cadence` -- and THIS ROW RETIRES WHEN ALL FIVE RETIRE, BY THAT AND BY NOTHING ELSE. Rewriting this paragraph retires nothing; neither does any subset. WHAT THE ORIGINAL SAID AND WHY IT COULD NOT WORK, kept because a trigger replaced silently teaches nobody: it read `this paragraph is rewritten as an ordinary present-tense description -- not amended, rewritten in one pass -- when the re-add queue closes`. That is a PROSE EDIT actuating against a six-capability loss, which is 4b(3)'s grain mismatch in its plainest form -- a plural loss with a singular trigger -- and it is worse than vague: it is a predicate with NO TRUTH CONDITIONS. `the re-add queue` has exactly one referent in this repository, a numbered list under Step 3 of `docs/plans/floor-cut-replacement-plan.md`, which `gunbc.doc_graph_roots` registers as a HandAuthoredDocBind -- a hand-authored document, so no `.dag` authority carries its contents. There is no membership object, no per-item disposition field and no closure predicate anywhere in the tree (searched 2026-09-01 across `.dag`, `.rs` and `.md`). Its own item 8 proposes that the falsifier cadence NEVER RETURNS, and an item that never returns cannot close by returning, so closure would require a per-item disposition nothing records. A row that cannot be retired by its trigger gets retired instead by someone judging the paragraph stale, which is retirement of a live safety regression by editorial judgement. Until then it describes a rung drop, and describing the replacement as finished would be the inflation §4b names as worse than sitting low. **WHAT SURVIVES UNTOUCHED, enumerated rather than swept away with the bullet** — this paragraph replaced a longer one, and a prose row is deleted for one reason and takes everything in it unless its contents are enumerated first (the same rule that governs deleting a witness file whole): the compile-clean scope authority `tools.dag_compile_clean_scope` and its import-closure selection (`entry_file_touched_via_import_closure`) are live and unmodified by the cut — but **live is not reachable, and an earlier revision of this clause said only the first**. It read that what is gone is the CI *job* that invoked them and not the authority; both halves are true and together they license a false inference, because SURVIVING A CUT AND BEING CALLABLE ARE DIFFERENT PROPERTIES and only the first was checked. Measured 2026-08-20: `entry_file_touched_via_import_closure` and `compile_clean_scope_plan_for_ci` are private `fn`s with ZERO references anywhere under `src/v1/stage0/src/bin`, no CLI flag reaches them, and the only `pub` surfaces into that chain — `witness_layer_roots_compile_clean_check` / `_emit_check` — return `Bool`, so they answer *is it clean* and can never answer *which entries would be selected*. A reader planning against the old sentence would budget an afternoon and find no caller; that is premise contamination of the same class this paragraph already corrects itself for twice. The authority survives and the capability does not, until something exposes a counting entry point; the `regen_input_sources` import closure survives and is now read by `v1_compiler.required_regen_host` — but the `regen_stage0` binary that consumed it, and the `RegenVerifyGate` / `SelfHostStalenessGate` pair that invoked it, are DELETED at the root (the regen cut), so the self-host fixed point is answered by `claim_executor --required-regen-fixed-point` and by nothing else. **THAT FLAG IS INVOKED AGAIN AS OF 2026-08-20**, so this is one re-add off the queue below rather than a standing gap. It was re-added as two `witnesses.yml` steps ordered ahead of the floor and CONSOLIDATED the same day (operator directive: the phases belong `within the witnesses step and within the gunbc binary, not at a github actions job level`) into ONE step running the phases in ONE process. **THAT 2026-08-20 DIRECTIVE IS NOW PARTLY SUPERSEDED, BY THE SAME OPERATOR, ON 2026-08-25** — `we can add it as a parallel job in github actions - we can do the same for regen now, we have more runners` / `basically i would put regen + v2 full compile in one job, and witnesses into another one`. The stated reason is a change in supply, not a change of mind about the earlier argument: the phases are mutually independent, so composing them into one process made the required check's wall clock a SUM of things that could have been a MAX, and more runners make the MAX purchasable. **THE DIRECTIVE HAS TWO HALVES AND ONLY ONE IS SUPERSEDED, which is why this clause states both rather than replacing one ruling with another.** SURVIVES — *within the gunbc binary*: the phases still live in `claim_executor`, each job makes ONE invocation and names a LANE, and no step's precondition reads another phase's verdict. The step-ladder defect the consolidation fixed (an `if:` naming a sibling step, silently conjoined with GitHub's implicit `success()`, so a regen red disarmed the whole floor) cannot return, because no step's condition can reach another phase's outcome. SUPERSEDED — *not at a github actions job level*: PARALLELISM IS NOT EXPRESSIBLE IN THE BINARY. Two phases running concurrently means two runners, two checkouts and two toolchains, and one process on one runner can thread but cannot acquire a second machine — nor would we want it to, at the floor's measured ~9.4 GiB peak. So the lane boundary is a job boundary of necessity, and what the directive was protecting against — SEQUENCING and PRECONDITIONS leaking into YAML — is exactly what does not cross it: the two jobs carry no `needs` edge and no condition on each other, which is the whole content of running them in parallel. So the invocation named at the top of this paragraph is superseded three times over and is now, exactly: TWO LANE JOBS, `claim_executor --required-ci --source-root dag --source-root src/v2 --required-lane build` (regen's first-generation comparison, the v2-emission compile, the emitted-closure cargo phase and the partition-crate boundary) and the same command with `--required-lane witnesses` (the `.dag` parse sweep and the witness floor fold), plus a THIRD job that gates on both. **THAT THIRD JOB IS NOT DECORATION AND THE FIRST CUT OF THE SPLIT DID NOT HAVE IT, which is the more useful half of this entry.** A GitHub required status check is produced by the JOB, not by the workflow, and the repository's `passing CI` ruleset is active, carries NO bypass actors, and names exactly ONE required context: `witnesses`. So splitting the phases into a second job made regen and v2-emission NON-BLOCKING -- the required check would have gone green over a regen drift or a v2 emission break and the PR would have been mergeable. That is fail-open (§5), and strictly worse than the serial run it replaced, because the serial job carried every phase into the one context that gates. THE REPAIR IS AN AGGREGATION JOB RATHER THAN A RULESET EDIT: the floor lane is renamed `floor`, and the name `witnesses` moves to a job that `needs` both lanes and whose only step reads both results and exits nonzero unless both are `success`. **THE CONDITION THAT MAKES THAT JOB RUN IS AT THE JOB LEVEL, AND THE FIRST CUT OF THE AGGREGATOR PUT IT ONLY ON THE STEP** -- the same fail-open committed one level in, caught by review 55795 and independently by a peer session within minutes of each other. `needs` carries an implicit job-level condition: a job that declares `needs` and no `if` is SKIPPED when a needed job fails, a skipped job never reaches its steps, and a step-level `always()` cannot rescue a job that never started. The job therefore declares `always()`, and that is the ONE place in the emission that departs from the file's `!cancelled()` house guard, stated here because a reader who knows the convention will otherwise correct it back and reopen the hole. Every other guard decides whether a STEP runs inside a job that is already running; this one decides WHETHER THE REQUIRED CONTEXT EXISTS AT ALL, and under `!cancelled()` a cancelled run leaves it skipped rather than answered. That turns the outcome on a question about GitHub nobody here has executed -- does a skipped or cancelled required check block a merge -- and the right response is not to measure it but to make the answer not matter: under `always()` the job always runs, always reads both results, and always reports on its own terms, so SKIPPED disappears from the required context. Construction over validation (§5), at the cost that a lawfully superseded run now reports this context red rather than cancelled, which is the correct reading rather than a regression. The two lane jobs still carry no `needs` edge on each other and still start together; only the aggregator waits. A ruleset edit would have worked too and was rejected on a boundary this document already records: the ruleset is not a `.dag` fact, so landing a change whose safety depends on someone editing a setting afterwards is a coverage gap with a promise attached and a real unguarded window. **THAT BOUNDARY MOVED, AND THE DECISION IT SUPPORTED DOES NOT.** `gunbc.repo_ruleset` now declares the desired ruleset -- enforcement, target, ref-name condition, the three rules, and the ONE required context, imported from `gunbc.witness_floor_workflow` `witness_floor_workflow_job_id` rather than spelled a second time -- observes the live one through `extdeps.github.rulesets`, reconciles the context roster through `gunbc.membership_reconcile`, applies drift with the whole-ruleset PUT, and READS BACK, claiming convergence only from the second observation and never from the apply's own 200. So the sentence in this bullet stating what the ruleset requires is no longer the only place that fact lives on our side of the boundary: `converge` actuates it and `verify` refuses on any divergence, with a typed reason per way it can diverge. WHAT DID NOT CHANGE, and why the aggregation job stays: convergence is an ACTUATION WITH A READ-BACK, not a wall. Nothing in this repository can constrain what GitHub admits to main, so an in-repo authority still cannot make a required context exist at the moment a merge is attempted -- it can only declare, apply and detect. The first cut's window argument therefore stands on its own terms; what is closed is the invisibility, not the boundary. WHAT IS NOT CLAIMED: NEITHER ENTRY POINT IS ENROLLED IN CI. `verify` is a route somebody runs, and until a required phase invokes it the class sits at *mitigatable* -- a drift is now detectable rather than detected, which is a real climb from unobservable and is not the same as a gate. Its next-rung trigger is that enrolment, which is a separate change under its own operator agreement. Found in review of gunbc#9203, against the live ruleset rather than against the workflow -- which is the only place the fact is visible, since nothing in the emitted YAML says which of its jobs gates. The partition is total by construction — `RequiredCiPhase::lane` is an exhaustive match, so a phase belonging to no job fails to compile rather than going silently unmeasured — and the lane is the ONLY thing the transport names: which phases a lane owns is decided in the binary, never in the YAML. **THE v2-EMISSION PHASE'S SUBJECT WIDENED IN THE SAME CHANGE**, from `dag/std/abi.dag` (the smallest entry in the tree) to `src/v2/compiler/00_compile.dag` (the v2 pipeline root, the widest closure one entry names). The row is `gunbc.ci_layer_roots` `required_v2_emission_entries` and it remains a cost decision rather than a Rust edit; what changed is the denominator, since the build lane's cost is now free up to the floor's duration rather than added to it. **WHAT THE SPLIT DOES NOT DO:** it restores nothing else from the deleted floor machinery — every item on the unguarded list above is still its own re-add under its own operator agreement — and it lands NO ratchet over the v2 compile's advisory-diagnostic population. That population is real and is the natural next subject, but a merge-blocking count pinned to a number measured on the current tree is exactly the oracle §5 forbids; an identity-grain monotone debt contract is a separate construction and is not claimed here. **THE PARSE PHASE STOPPED BEING src/v1-ONLY, 2026-08-23**, and it is stated here because the previous revision named the phase by the one root it walked. It now sweeps `src/v1`, `dag` and `src/v2` from one roster (`v1_compiler.cli_run` `DAG_PARSE_SWEEP_ROOTS`), shared with the standalone bin, and it admits source annotations per file rather than parsing alone -- `tokenize` routes `//` into the annotation channel and `parse` never decides grain, so the old walk returned clean for a file carrying an in-body annotation and the §4c refusal surfaced only at the floor's strict PREPARATION, where no witness executes at all. That is not a widening of the floor's source roots, which `gunbc.ci_layer_roots` `v1_dead_witness_tree_triage_receipt_remainder` rules out on NAME RESOLUTION grounds: this walk resolves nothing across files, so that objection cannot reach it. **THE PHASE ROSTER WAS CUT TO THREE BY OPERATOR RULING, 2026-08-21, WAS FOUR AGAIN AS OF #9035, AND IS FIVE AS OF THE PARTITION-CRATE PHASE, AND IS SIX AS OF THE EMIT-COMPILE PHASE.** The count is stated in the present tense here and it has now been wrong in BOTH directions, which is the reason it is written as a measurement rather than as a recollection: an earlier revision said four while enumerating a determinism pass no required run performed, that was corrected to three, and the three then went stale when #9035 enrolled a v2-emission phase that compiles one v2 entry — landed precisely because an emission break reached main and no gate could see it. The instrument is the required mode itself, which prints its own roster before any phase runs -- one `phase ` line per phase the lane owns and one `ROUTED to lane ` line per phase it does not, then `lane= phases_run=`. Read the roster from that announcement rather than from this sentence: the count moved twice in five days, and a transcribed roster size is exactly the positional citation the ruling above forbids. The fifth phase is `partition-crates`, in the build lane, which compares the derived stage0 partition's committed `lib.rs` and `Cargo.toml` against what `v1.compiler.stage0_crates` renders from the authority -- landed because those seven crates are workspace members nothing in CI builds, so a broken one sat on main while every required lane stayed green. **THAT COUNT IS NOW A PROPERTY OF THE ROSTER AND NOT OF A RUN**, because the 2026-08-25 split partitions the four across two jobs: a lane's own summary line reports `lane= phases_run=`, and each job additionally prints a `ROUTED to lane ` line for every phase it does not own, so one job's log still names the whole roster and where the rest is being measured. Reading a single job's `phases_run` as the roster size is the error that line exists to prevent. **A SIXTH PHASE, `generated-artifact`, IS THE FIRST ITEM TAKEN OFF THE UNGUARDED LIST ABOVE RATHER THAN A NEW SUBJECT.** It adjudicates every member of `gunbc.generated_artifact` `committed_generated_artifacts` against what its own authority generates, through the pure per-path projection `gunbc.generated_artifact_emit` `generated_artifact_body_for_path`, hosted by `v1_compiler.cli_run` `run_generated_artifact_boundary` in the build lane. THE PRODUCER WAS NEVER MISSING AND THE CALLER WAS, which is why this is a re-add and not a construction: `main_wet` on `dag/gunbc/instruments/generated_artifact_gate.dag` has always written these files and the projection has always been able to say what each path ought to hold, but from the floor cut until this phase the only route that ASKED it was `claim_executor`'s behavioural-receipt census, which asks only about paths of the form `src/v1/stage0/src/` because its subject is emitted Rust mirrors. So `DESIGN.md` and `ROADMAP.md` -- projections of `gunbc.design_document` and `gunbc.roadmap_authority` -- were computed by nothing and compared by nothing, and were maintained BY HAND in lockstep with their authorities. That is not a hypothetical: gunbc#9392 found the accumulated result the only way an unguarded artifact is ever found, by accident while doing something else, 2198 characters into the drift, and this document's own §4b(3) clause was among the text standing in the artifact with no authority behind it. **AND THE FIRST THING IT FOUND WAS NOT DRIFT, WHICH IS THE REUSABLE HALF.** Two of its four opening reds were ABSENT rather than drifted, and one of those markdown files had been DELETED ON PURPOSE by a295e17415, whose entire subject is the ruling that the .dag carrier is the authority. Regenerating it would have performed exactly what that commit refused, and the gate would then have gone green over the resurrection -- enforcing, permanently, the reverse of a decision already taken. THE GENERAL SHAPE: **a drift gate makes whatever it adjudicates BINDING**, so an absence that was inert before the gate becomes a line-stop after it, and the cheapest way to move the line is to regenerate. A dormant registry mistake is thereby converted into a standing obligation to recreate deleted files, silently, because the green looks identical either way. The stale half is the REGISTRY ROW and not the missing file, so the repair runs the other way: `gunbc.plan` `PlanProjection` makes a plan declare whether its markdown is a committed artifact at all, `PlanIsAuthorityOnly` carries the ruling that removed the projection, and the plan stays rostered, generated and refusable -- only whether its bytes are expected on disk changes. The rule for the next gate: **before a new adjudicator's first red is closed by producing the thing it says is missing, establish that the thing was ever supposed to exist.** WHAT THE PHASE DOES NOT CLAIM: it is READ-ONLY by construction -- there is no write path in it and no flag that opens one, because a gate that can also write its own subject is a gate whose green proves nothing -- and it restores nothing else from the deleted machinery; heal, the seven effect gates, the fmt gate, merge-admission stamping and the falsifier cadence remain their own re-adds. Its roster is ASKED of the authority, so an artifact added to `generated_artifact_registry` is enrolled with no edit to the host, and a rostered member that reaches NO verdict is counted and reported separately from a drifted one and stops the line on its own -- `0 drifted` over a population nothing asked about is the execution-provenance loss this document names, and the two counts are what keep it unrepresentable. **THAT COUNT IS NOW A PROPERTY OF THE ROSTER AND NOT OF A RUN**, because the 2026-08-25 split partitions the four across two jobs: a lane's own summary line reports `lane= phases_run=`, and each job additionally prints a `ROUTED to lane ` line for every phase it does not own, so one job's log still names the whole roster and where the rest is being measured. Reading a single job's `phases_run` as the roster size is the error that line exists to prevent. The five phases the 2026-08-21 ruling deleted stay deleted and are enumerated below; neither #9035 nor the partition-crate phase restored any of them, each added a new one, so both are roster ADDITIONS and not a reversal of that ruling. Five phases were deleted from the mode: merge-admission-capture, the regen determinism (fixed-point) pass and its in-memory pass-1 digest handoff, the behavioral receipt's controlled-fixture selftest, the behavioral receipt against the authorities a diff changed, and merge-admission-stamp. They were deleted rather than left reporting SKIPPED, because a phase whose only reachable state is a non-verdict has a deficit frequency of zero by construction and still reads as coverage on the ledger (§5, the absorbing fallback). The capabilities survive at their own entry points — `--required-regen-fixed-point`, `//gunbc/instruments:behavioral-receipt-plan`, `//gunbc/instruments:behavioral-receipt-selftest`, `//gunbc/instruments:behavioral-receipt-census` — none of which any workflow invokes; what ended is their enrolment in the required run, and the three measurements they carried (regen determinism, behavioural equivalence of a changed authority against its mirror, and the receipt's own discriminating arms) are simply no longer taken. That is a declared scope narrowing, and it returns merge-admission stamping to the unguarded list above rather than removing it from it. The remaining three phases are independent — the one real data dependency left with the phase that consumed it — so every phase runs even after an earlier failure and the run reports the complete ledger instead of letting the first defect hide the rest. The line still stops on any failed phase. It is recorded here with what made the gap real, because the steps were enrolled, STRIPPED, and re-enrolled inside twelve hours and a reader who finds only the enrolment will re-derive the strip. The strip was correct when made: the admission test is whether every red is closable by the author who caused it at the moment they caused it, and it was not -- the comparator normalized BOTH sides through rustfmt while writing the single-pass form, so after any candidate install the comparison was `normalize(normalize(emitted))` against `normalize(emitted)`, an identity only if rustfmt is idempotent. It is not, so the gate refused a tree byte-identical to its own artifact, permanently, and its only reachable green was the hand-edited mirror the gate exists to refuse -- a gate whose sole closing move is the forbidden action is not strict, it launders. Repairing it by raw-comparing the single-pass bytes then put it in direct contradiction with `cargo fmt --all --check`, which re-formats what is committed and so demands the NEXT pass: two gates consuming different passes of one artifact, each breaking the other. The resolution is that the emitted artifact is now written as a FIXED POINT of the formatter (bounded, exceeding the bound is a typed refusal), which makes the contradiction unrepresentable rather than detected and makes `cargo fmt` a no-op on it by definition -- the §5 construction move, and the general lesson is that any artifact with two consumers that normalize it must be stored in the normalizer's fixed point or the two consumers cannot both be satisfied. This clause previously read that the fixed point and its closure both survived with only their job removed; that was true when written and the regen cut falsified its first half, so it is rewritten here rather than annotated — a second sentence beside it would be two accounts of one fact; and parse remains grammar-owned — `ingest_yaml_source` (`dag/extdeps/languages/yaml/ingest.dag`), no shell or host parser — which was never a floor fact at all and is restated here so that dropping the bullet does not drop it. **TWO OPERATOR RULINGS ALSO LIVED IN THE REPLACED BULLET AND STILL HOLD**, restated because a ruling about what CI does *not* do is invisible once the paragraph describing CI is rewritten, and nothing in the new mechanism would contradict it loudly: the Rust test suite was removed from CI 2026-07-11 (operator ruling, recorded at `gunbc.commit_workflow` `commit_gate_rust_suite_removed_disposition`) and runs locally only; and clippy was removed from CI 2026-07-08, because a crate-wide `#![allow(clippy::all)]` made it zero-signal over ~44 minutes per run, leaving it a local dev check. Neither is reinstated by the replacement, and neither is the floor cut's to reverse." } data measurement_bankruptcy: RungDrop = RungDrop { identity: "measurement_bankruptcy" as NonEmptyStr, subject: "Self-host emission board measurement", declared: "2026-08-24", standing: Standing, authored: "**THE MEASUREMENT BANKRUPTCY DELETED A CAPABILITY, NOT ONLY ARTIFACTS, AND THIS ROW IS THAT DECLARATION (2026-08-24).** The bankruptcy above removed `docs/probes/` whole. Deleting the boards removes TRANSCRIPTIONS, which is the point; deleting the instruments removes a ROUTE, which is a different fact and is the one §4b(3) obliges a cut to declare. WHAT IS GONE: the only executable route to a self-host emission board measurement. PREVIOUS STATE — any lane could re-derive a per-entry board by running the committed probe script, last exercised 2026-08-24 against the then-current main, and that reading is what answered the operator when they asked what the emission trajectory was doing. TEMPORARY STATE — no route exists; the emission trajectory is not measurable from the tree, and a board figure quoted from here on names nothing that can produce it. BOUNDED POPULATION: one capability, the per-entry emission board. RESTORATION TRIGGER: a `.dag` entry point that emits, assembles and compiles one entry and returns the coded-diagnostic population, cited by name wherever a board figure is quoted — at which point the same figures become legitimate again unchanged, because the rule forbids transcribing output INSTEAD OF naming an instrument, and the defect today is that there is no instrument to name. **WHY THIS ROW EXISTS AT ALL, and it is the same reason the regen row beneath it does:** no dependent could refuse. The corpus contains nothing that breaks when the board becomes unmeasurable, because the consumers are LANES rather than modules — the identical blind spot that made a `.dag`-consumer census report the instruments as dead a few hours before this cut. So delete-first's census, which is normally the thing that surfaces a load-bearing deletion loudly, is structurally silent here, and a declared row is the only mechanism left. **THE TRIGGER HAS FIRED, AND THE ROW STAYS AS HISTORICAL EVIDENCE OF THE LOST PER-ENTRY ROUTE.** The restored route is `tools.emission_entry_instrument` `measure_entry_emission`, invoked as `gunbc run --source-root dag --source-root src/v2 --entry dag/gunbc/instruments/emission_entry_instrument.dag --function measure --arg entry= --arg report=`. It emits one entry's closure, assembles it with `cssl_assemble`, compiles the assembled crate under cargo's JSON message format, and returns typed emit-stage and coded rustc diagnostic populations. `EmissionMeasurement` has no spelling in which an unreached stage renders as an empty reached stage, and its decode refuses inconsistent populations. **THE WHOLE-CORPUS PERSISTENCE THAT NOW CITES THIS HISTORY IS SEPARATE:** `gunbc.self_host_compile_phase_frontier` derives the compile-phase board from that instrument's `00_compile` closure observation, persists the linked identity-grain receipt series, and executes the phase/identity ratchet over its latest validated pair. Board standings quoted by the program status and design-ledger projection cite that frontier rather than this historical row. This does not turn the historical per-entry drop into the live board, and every figure copied into prose without naming its producer remains debt." } @@ -101,11 +101,25 @@ data direct_call_arg_seam_v2_exemption: RungDrop = RungDrop { } data floor_cost_contention_verdict: RungDrop = RungDrop { identity: "floor_cost_contention_verdict" as NonEmptyStr, subject: "Stable per-claim cost qualification under a shared execution envelope", declared: "2026-09-01", standing: Standing, authored: "Required floor cost — **RUNG DROP, DECLARED (2026-09-01).** SUBJECT: stable per-claim cost qualification under a shared execution envelope. WHAT IS LOST: an attempt's CPU duration cannot be read as an invariant property of the witness, nor as proof of a witness-owned regression. `required_floor_claim_cpu_safety_limit_ms` is a cpu-ms literal compared against a measurement taken on a shared runner, so a row that exceeds it may have done nothing but run beside somebody else's build. THE MEASUREMENT IS NOT WRONG AND THIS ROW DOES NOT SAY SO: it is a VALID observation of THIS EXECUTION ATTEMPT. What it is not is a stable observation of the claim as an isolated subject, and only the second reading is what a cost verdict needs. WHAT REMAINS, AND STAYS REQUIRED: the 500ms attempt-safety stop, and fail-closed treatment of a required claim that produced no verdict. Contention disqualifies the deadline as an INTRINSIC CLAIM-COST VERDICT; it does not disqualify it as a REQUIRED ATTEMPT-SAFETY AND VERDICT-AVAILABILITY criterion. Both terminal arms stay required reds and are distinct: an interrupted attempt means the required claim never produced a semantic verdict, and a completed-past-limit attempt means it crossed the declared safety envelope. Neither proves the witness intrinsically costs more than the limit, that it regressed, that it owns the observed excess, or that it belongs in permanent cost debt. A shared runner producing false refusals is an AVAILABILITY loss that fails closed, and removing the deadline would let genuinely runaway evaluation consume the executor without bound. PREVIOUS RUNG: none for environment-independent claim-cost qualification -- that guarantee was never held, and saying it was would be inventing a rung to drop from. Mechanically preventable remains TRUE and undropped for attempt safety. TEMPORARY RUNG: claim-cost qualification UNAVAILABLE; verdict availability environment-sensitive; acceptance still fail-closed. REASON, and the three negative results that make this a capability claim rather than a shrug. (1) THE BASIS IS ALREADY CPU BY DECLARATION: `required_floor_cost_basis` returns `CpuCost` because these claims execute Hermetic, so 'judge cpu rather than wall' is DONE and what remains is cpu-time variance itself. (2) THE OBVIOUS CALIBRATOR IS REFUTED BY MEASUREMENT, and this is the sentence that stops the trigger being discharged by pointing at what we already measure: THE PREPARATION WARM PHASES ARE NOT A CALIBRATOR. Across main and two attempts of one identical tree, `pool-root-index-warm` measured 693 / 727 / 596 cpu-ms and `languages-consumer-census-warm` measured 858 / 606 / 531, so on the attempt whose CLAIMS ran hottest the census phase ran COLDER than main's. They do not track claim inflation. (3) NO CALIBRATION CONCEPT EXISTS IN THE REPOSITORY AT ALL. Normalizing by a quantity that does not track the machine would produce a threshold that LOOKS principled and is not, which is strictly worse than the honest literal. POPULATION -- THE CLOSED SUBJECT UNIVERSE IS NOT A THRESHOLD-SELECTED SET, AND THIS ROW SAID OTHERWISE FOR TWO REVISIONS. The universe is EVERY REQUIRED IDENTITY FOR WHICH THE CPU DEADLINE IS ARMED WHILE IT EXECUTES UNDER THE UNCONTROLLED SHARED-RUNNER ENVELOPE. That is closed, decidable from the run's own plan, and it does not move with anyone's measurement. WHY THE THRESHOLD SET IS NOT THAT UNIVERSE: the contention term is unbounded, so NO lower threshold can prove the rows beneath it unaffected. A set selected by 'measured cpu at or above N' is a VIEW whose membership is a property of the MEASUREMENT rather than of the subject, and letting a decidable admission predicate's output stand in for the class's population joins two different objects by an assumption. The predicate was the right answer to a censored-parameter refusal and the wrong answer to 'what is the population'. THE THRESHOLD SET SURVIVES AS AN EXPOSED ATTENTION SUBSET, which is what it is good for: prioritising optimisation and isolation work. Admission is measured cpu at or above the attention constant -- 280ms against the 500ms ceiling, the ceiling over the largest inflation floor observed to date -- and the constant is spelled ONCE here, with every later reference in this row naming it rather than repeating the digits, because a constant that has already moved twice in one day reforks the row on its next revision if it is spelled in three places. THAT SINGLE-SPELLING DISCIPLINE IS PROSE AND NOT STRUCTURE: `RungDrop` carries no numeric field, so nothing refuses a future revision that updates one mention and not another. That missing field is this discipline's next rung. THE ATTENTION CONSTANT'S OWN DERIVATION AND REVISION CONDITION: it is the ceiling over an inflation FLOOR of 1.777, measured by identity join -- `v2.test.execution.emit_host_meet_join_equals_eval.emit_host_meet_wrong_fixture_refuses_holds` measured 501 cpu-ms on one attempt and 282 on a re-run of THE SAME TREE with nothing changed. A floor is not the inflation, so the constant MUST BE RE-DERIVED THE MOMENT A LARGER FLOOR IS MEASURED. Its predecessor was falsified within the hour for exactly this reason: sized at 400 against a floor of 1.196, it EXCLUDED the one row this class has been observed to trip on the completed-past-limit arm, and an admission rule that omits a known member is wrong at its own grain. TWO OBJECTS, ONE MONOTONE AND ONE NOT, AND THIS ROW PREVIOUSLY CONFLATED THEM: the EVIDENCE FLOOR is monotone -- the largest observed inflation floor can only rise, so the constant derived from it can only fall. THE MEMBERSHIP SET IS NOT MONOTONE: individual identities enter and leave the attention subset as their measured attempt costs vary, which is exactly what makes it a view rather than a population. Monotonicity of the first gives nothing about the second. ON THE NAMED RUN (gunbc#9840 head 85c4a307, required-witnesses-floor, second attempt, 3381 executed rows) the attention subset holds 53 identities across 21 modules, the largest groups being `test.claim.compiler_frontend_program_status_witness` (9), `v2.test.execution.emit_host_meet_join_equals_eval` (4), `v2.test.emit.rust_body_add_emit` (4) and `v2.test.emit.rust_binop_emit` (4). THE SUBSET IS A MANUAL DERIVATION AND NOT AN EXPOSED RUN PRODUCT, AND AN EARLIER REVISION OF THIS ROW OVERCLAIMED IT. The enumeration above was computed BY HAND by reading a run's uploaded `required_floor_claim_cost.tsv` and filtering on the attention constant. NO MODELED FIELD, FUNCTION OR REPORT PRODUCES IT: the constant lives only in this prose, `RungDrop` carries no numeric field to hold it, and nothing consumes it -- so saying the artifact 'reports the subset' asserted an executable relationship that does not exist. WHAT WOULD MAKE IT A PRODUCER, and it is a carrier gap rather than a missing script: the constant modeled as a declaration, and the per-claim cost artifact modeled as data a function can read, at which point the subset is a fold and this paragraph becomes its projection. Neither exists today, and a hand-run filter described as a run product is the specification-without-execution DESIGN section 5 names -- which is why this row now says which of the two it is. THE CONSTANT SITS ON THE STEEPEST PART OF THE COST CURVE and must not be read as a measured threshold: 12 rows reach 400, 16 reach 350, 43 reach 300, 50 reach 290 and 53 reach 280 -- seven rows arrive in a 10ms interval, and 1388 rows measure zero. RESTORATION TRIGGER, A CAPABILITY AND NOTHING SHORT OF IT: A CLAIM-OWNED COST BASIS WHOSE VALUE IS INVARIANT, OR BOUNDED BY CONSTRUCTION, ACROSS THE ADMITTED EXECUTION ENVELOPES. Three arms satisfy it: an adequately isolated envelope; a deterministic work measure such as evaluator steps; or a calibrated relative basis WHOSE TRACKING HAS ITSELF BEEN PROVEN over the relevant workload classes. It is deliberately wider than 'one in-run reference workload': the warm phases already failed to track claim inflation, and heterogeneous claims respond differently to cache, memory, frequency and co-tenant pressure, so a single reference workload is one candidate arm and not the capability. A SEPARATE CAPABILITY BOUND, RECORDED HERE AND EXPLICITLY NOT THIS ROW'S CAUSE: a shared artifact fill paid inside a claim's measured window before preemption bounds what any deadline mechanism can promise about attribution. PAYER TRANSFER IS REFUTED FOR THIS INCIDENT -- the red run's own `[floor-shared-fill]` ledger carries no `paid_by` line naming the module that tripped, the whole module shifted uniformly by 8 to 11 percent rather than one row taking a lump, and the rows that crossed sat mid-pack on the green attempt. It is a bound on the mechanism, not an explanation of these observations, and it is not this row's population producer. RAISING THE CEILING DOES NOT RETIRE THIS ROW AND IS NOT PROPOSED: 'the comparison does not qualify the claim' and 'the threshold is too low' are different claims, and only the first is recorded here. NOT PROPOSED EITHER: re-running an undecided row until it answers is retry-until-green -- fail-open wearing a fail-closed label -- admissible only as a counted, visible mitigation carrying this row's trigger as its dissolution condition." } +data floor_cut_heal: RungDrop = RungDrop { identity: "floor_cut_heal" as NonEmptyStr, subject: "Heal job for generated artifacts", declared: "2026-09-01", standing: Standing, authored: "**HEAL IS GONE AND ITS AUTHORITY MODULE IS GONE WITH IT, AND THIS ROW DECLARES THAT RUNG (2026-09-01).** Split out of `floor_cut`, whose single trigger could not retire it. PREVIOUS RUNG: 2 (mechanically preventable) -- a required job regenerated drifted generated artifacts and pushed the repair onto the branch head, so the class `a committed generated artifact diverges from its authority` was caught and CORRECTED without an author. TEMPORARY RUNG: 1 (mitigatable) -- drift is still CAUGHT, by the `generated-artifact` required phase, but nothing repairs it, so every divergence is now a human round trip. REASON: the 2026-08-15 floor cut deleted the job with the workflow authority that carried it. BOUNDED POPULATION: one capability -- automatic repair of drifted generated artifacts on a branch head. MEASURED FROM THE TREE RATHER THAN FROM THE PARAGRAPH UNDER SUSPICION (2026-09-01): `gunbc.ci_heal_credential` survives in full and still carries `ci_heal_job_ref` and `ci_heal_workflow_ref` as DeclarationRefs to `gunbc.ci_workflow` `ci_heal_generated_artifacts_job` and `gunbc.ci_workflow` `ci_workflow` -- and `gunbc.ci_workflow` DOES NOT EXIST in this tree; the only module of that stem is `gunbc.ci_workflow_expressions`, and the decl name resolves nowhere. So heal's credential model is live and its job and workflow are deleted, which also means a typed citation to a deleted module is sitting unrefused; that second fact is recorded here as an observation and is NOT this row's subject. RESTORATION TRIGGER, A CAPABILITY: a required-run consumer that, on a branch head whose committed generated artifacts diverge from their authorities, WRITES the regenerated bytes back and pushes them under a credential the repository already models -- observed doing so on a real divergence, not merely emitted. WHAT DOES NOT RETIRE THIS ROW: restoring `gunbc.ci_workflow` or re-pointing `ci_heal_credential`'s dangling citations, which repairs the MODEL and heals nothing; nor a job that only reports drift, which is the phase we already have. **`floor_cut` CANNOT RETIRE WHILE THIS ROW STANDS**, and this sentence is on every one of the five so the constraint is readable from either end: that row's trigger is the conjunction of these five, so retiring it on a reading of any single sibling -- including this one -- is the reading its own trigger forbids." } + +data floor_cut_effect_gates: RungDrop = RungDrop { identity: "floor_cut_effect_gates" as NonEmptyStr, subject: "Six of the seven effect gates (one restored)", declared: "2026-09-01", standing: Standing, authored: "**SIX OF THE SEVEN EFFECT GATES ARE UNGUARDED AND THE SEVENTH IS BACK, AND THE FRACTION IS STATED BECAUSE SAYING `THE EFFECT GATES` WHERE ONE OF SEVEN IS LIVE IS THE OVERSTATEMENT THIS LEDGER KEEPS PAYING FOR (2026-09-01).** Split out of `floor_cut`. THE SEVEN, from that row's own loss clause: compile-clean, generated-artifact drift, emit-host, extdeps citation, extdeps placement, prose-row, cheap-claim pool. DISCHARGED, 1 of 7: generated-artifact drift, restored by gunbc#9415 as the required `generated-artifact` phase adjudicating every member of `committed_generated_artifacts` through `gunbc.generated_artifact_emit` `generated_artifact_body_for_path`. It is named here as DONE rather than deleted from the list, because a population that shrinks silently cannot be checked. OUTSTANDING, 6 of 7: compile-clean, emit-host, extdeps citation, extdeps placement, prose-row, cheap-claim pool. PREVIOUS RUNG: 2 (mechanically preventable) for each -- a required gate blocked the merge. TEMPORARY RUNG: 0 for the six; not `1`, because these are not mitigated failures but UNOBSERVED ones -- the class is outside the modeled guarantee at the merge boundary until its gate returns. REASON: the 2026-08-15 floor cut deleted the wrapper carrying all seven obligations. BOUNDED POPULATION: the six named gates, enumerated above; the roster is closed and is not `whatever the plan lists`. RESTORATION TRIGGER, PER GATE AND NOT FOR THE SET: this row retires only when EACH of the six has a required-run consumer that refuses a merge on its own violation, each with a discriminating RED executed on the real acceptance path. Six retirements, one row, and the row states its own remaining fraction whenever it is read. WHAT DOES NOT RETIRE THIS ROW: the `generated-artifact` phase being live, which is the one already discharged; a lens that computes any of the six without gating, which is the inert tier DESIGN section 6 names; or a gate landed with no authored RED, which is a wall nobody has seen fire. **`floor_cut` CANNOT RETIRE WHILE THIS ROW STANDS**, and this sentence is on every one of the five so the constraint is readable from either end: that row's trigger is the conjunction of these five, so retiring it on a reading of any single sibling -- including this one -- is the reading its own trigger forbids." } + +data floor_cut_fmt_gate: RungDrop = RungDrop { identity: "floor_cut_fmt_gate" as NonEmptyStr, subject: "Rust fmt as a merge-path gate", declared: "2026-09-01", standing: Standing, authored: "**NO REQUIRED LANE RUNS `cargo fmt`, AND THIS ROW DECLARES THAT RUNG (2026-09-01).** Split out of `floor_cut`. PREVIOUS RUNG: 2 (mechanically preventable) -- fmt ran as a required CI step on the merge path. TEMPORARY RUNG: 1 (mitigatable) and generously so: what remains is the generated pre-commit hook, which is opt-in per clone (`core.hooksPath`), bypassable with `--no-verify`, and absent in container worktrees. REASON: the 2026-08-15 floor cut deleted the build job that carried the step. BOUNDED POPULATION: one capability -- refusal of unformatted Rust at the merge boundary. MEASURED FROM THE TREE (2026-09-01): the emitted `.github/workflows/witnesses.yml` runs fmt in neither required lane. This is not a new reading -- `gunbc.commit_workflow` already carries it at check grain as an UNCOVERED residual in `check_removal_roster`, and records the sharper fact that the hook's own slimming was argued FROM fmt remaining a required-path CI step, which the cut then falsified. `gunbc.repo_self_build` names the command; nothing required executes it. PRIOR EVIDENCE THE HOOK IS NOT AN AUTHORITY, from that same carrier: gunbc#6658 -- an unformatted `.rs` landed on main and no hook caught it. RESTORATION TRIGGER, A CAPABILITY: `cargo fmt --all --check` executing inside a required lane such that a merge with unformatted Rust is REFUSED, demonstrated by a red on an unformatted fixture. WHAT DOES NOT RETIRE THIS ROW: any strengthening of the pre-commit or pre-push hook -- that surface was proven non-enforcing before this drop was declared, and re-heavying it re-imports the pressure `commit_workflow` records as converting honest reds into workaround greens. **`floor_cut` CANNOT RETIRE WHILE THIS ROW STANDS**, and this sentence is on every one of the five so the constraint is readable from either end: that row's trigger is the conjunction of these five, so retiring it on a reading of any single sibling -- including this one -- is the reading its own trigger forbids." } + +data floor_cut_merge_admission_stamping: RungDrop = RungDrop { identity: "floor_cut_merge_admission_stamping" as NonEmptyStr, subject: "Merge-admission stamping: the receipt has no producer", declared: "2026-09-01", standing: Standing, authored: "**THE MERGE-ADMISSION RECEIPT HAS A CONSUMER AND NO PRODUCER, AND THIS ROW DECLARES THAT RUNG (2026-09-01).** Split out of `floor_cut`. PREVIOUS RUNG: 2 (mechanically preventable) -- the floor run STAMPED a receipt and `tools.merge_admission_gate` read it, so admission was a fact a machine produced and a machine checked. TEMPORARY RUNG: 0 -- with no producer the gate cannot answer, so what it once decided is now decided by nobody. A consumer whose input never arrives is not a weakened check; it is an absent one wearing a check's name, which is the `diagnostic_name_mechanism_silent` shape this repository already files. REASON: the 2026-08-15 floor cut deleted `tools.merge_admission_gate.dag` together with the floor plan that stamped its receipt. BOUNDED POPULATION: one capability -- a machine-produced admission receipt joined to the merge decision. MEASURED FROM THE TREE (2026-09-01): `gunbc.commit_workflow` records, in two separate removal dispositions, that this receipt is deleted and on the unguarded list -- and that from 2026-08-15 one of those dispositions justified a removed check by naming two authorities that no longer existed, with nothing able to say so because a citation inside a String resolves against nothing. That is the cost of this gap already realized once. RESTORATION TRIGGER, A CAPABILITY: a required run that PRODUCES an admission receipt bound to the head under judgment, and a consumer that refuses a merge whose head has no such receipt -- both executing, with a red on a head that lacks one. WHAT DOES NOT RETIRE THIS ROW: re-adding a `merge_admission_gate` module that reads a receipt nobody writes, which reproduces exactly today's state with more code; nor a human check-list step, which is not a producer. **`floor_cut` CANNOT RETIRE WHILE THIS ROW STANDS**, and this sentence is on every one of the five so the constraint is readable from either end: that row's trigger is the conjunction of these five, so retiring it on a reading of any single sibling -- including this one -- is the reading its own trigger forbids." } + +data floor_cut_falsifier_cadence: RungDrop = RungDrop { identity: "floor_cut_falsifier_cadence" as NonEmptyStr, subject: "Falsifier cadence: exposure open, disposition NOT decided", declared: "2026-09-01", standing: Standing, authored: "**THE FALSIFIER CADENCE IS GONE AND WHETHER IT SHOULD RETURN IS AN OPEN OPERATOR QUESTION, WHICH IS WHY THIS ROW IS NEITHER A RESTORATION NOR A RETIREMENT (2026-09-01).** Split out of `floor_cut`. PREVIOUS RUNG: 2 (mechanically preventable) -- a scheduled cadence ran a predict-only cold comparison over the whole corpus, so a wrong affected-set prediction and a lying `SubstrateInputsOnly` disposition surfaced as a counted divergence within one window. TEMPORARY RUNG: 0 -- `falsifier.yml` was deleted by the cut and the repository carries three workflows, none of which runs a cold comparison. `v2.std.live_tree` records the consequence in its own words: two carriers named that cadence as their enforcement, the sentences were true when written and became false when the workflow died, and nothing could notice. BOUNDED POPULATION: one capability -- a scheduled whole-corpus cold control against the selected run. WHY THE DISPOSITION IS OPEN AND STATED AS OPEN. `docs/plans/floor-cut-replacement-plan.md` item 8 says `proposed: never returns`. That is a PROPOSAL in a hand-authored plan, not a ruling, and a capability deliberately not returning is a SCOPE REMOVAL, which is the operator's call and not an author's. Writing this row as a restoration that will wait forever would be a trigger that cannot fire; writing it as retired would be an author retiring an operator's exposure. RESTORATION TRIGGER, TWO ARMS AND NO OTHERS: this row retires EITHER when a scheduled consumer executes a predict-only cold comparison over the whole corpus and reports divergences as a counted, located population, OR when an OPERATOR RULES the capability withdrawn -- at which point the row is retired citing that ruling, and the carriers that named the cadence as their enforcement must be corrected in the same change, because a withdrawn capability still leaves them asserting a route that does not exist. WHAT DOES NOT RETIRE THIS ROW: an author, a lane or a plan concluding it should never return. **`floor_cut` CANNOT RETIRE WHILE THIS ROW STANDS**, and this sentence is on every one of the five so the constraint is readable from either end: that row's trigger is the conjunction of these five, so retiring it on a reading of any single sibling -- including this one -- is the reading its own trigger forbids." } data builtin_signature_arity_pairing_fabricates: RungDrop = RungDrop { identity: "builtin_signature_arity_pairing_fabricates" as NonEmptyStr, subject: "Arity agreement between a declared builtin parameter name and its derived algebra template", declared: "2026-09-01", standing: Standing, authored: "Builtin signature grounding -- **RUNG DROP, DECLARED (2026-09-01).** PREVIOUS RUNG: none to lower -- this declares that a class created by this change lands below its attainable ceiling rather than at it. v1.compiler.infer_method pairs each row's DECLARED parameter names with the parameter TYPES derived from std.algebra. When the two lists disagree in length, pair_declared_names yields AlgebraTypeVariable { id: \"unpaired_declared_parameter\" } for the unpaired position instead of refusing. That is a value standing where a refusal belongs -- DESIGN section 5's fabricated-plausible-output arm -- and it is declared here rather than left as a marker that reads like a wall. TEMPORARY RUNG: mitigatable. The marker is distinctive, greppable, and reaches src/v1/stage0/src/v1_compiler_infer_method.rs, so a mismatch is DISCOVERABLE by inspection of a generated artifact. It is not mechanically preventable, because NO CONSUMER ASSERTS ITS ABSENCE: an unchecked marker is an inert lens, and DESIGN is explicit that the tier where the machinery exists and nothing gates on it is itself a lie. REASON: builtin_function_registry is a `data` initializer and a .dag data initializer has no refusal channel -- there is nowhere at construction for a typed, located diagnostic to go, so the only arms available were a fabricated value or a silently shorter list, and a marked fabrication is the more honest of the two. POPULATION: bounded and closed at 20 rows -- exactly the registry names that std.algebra also declares and that therefore pair at all (count, to_int, substring, to_string, concat, map_insert, map_merge, with, map_contains_key, map_has, lookup, map_get, map_keys, map_values, get, reverse, list_push, length, starts_with, replace). The other 112 rows author their types directly and cannot reach this arm. Zero occurrences of the marker in the tree today, which is the state this row exists to keep observable. RESTORATION TRIGGER: construction-time refusal available inside a `data` initializer -- SUFFICIENT FOR a declared/derived arity disagreement to stop the line with a typed, located diagnostic at the row that causes it, rather than to produce a marked value that construction accepts. The trigger names that capability and not any artifact that would contribute to one; a witness asserting the marker's absence would raise this to mechanically preventable but would NOT retire the row, because the invalid state would still be writable." } data concat_binary_signature_exempt_from_arg_binding: RungDrop = RungDrop { identity: "concat_binary_signature_exempt_from_arg_binding" as NonEmptyStr, subject: "n-ary concat call sites judged against concat's binary declared signature", declared: "2026-09-01", standing: Standing, authored: "Builtin signature grounding -- **RUNG DROP, DECLARED (2026-09-01).** PREVIOUS RUNG: none to lower -- nothing binds builtin arguments today, so this declares a class that the arm flip would otherwise create. concat's declared signature is BINARY, and it is binary correctly: std.algebra declares param_types [ReceiverSelf, ReceiverSelf], and src/v1/runtime_rust.dag emits `pub fn concat(a: T, b: T) -> T`. The algebra and the emitted runtime agree; only the CORPUS calls concat at other arities. TEMPORARY RUNG: mitigatable. concat is exempted from the direct-call argument-shape judgement when decide_callable_candidates begins answering FuncSigResolved for a BuiltinCallable; every other builtin is judged. REASON: concat(a, b, c) is a FOLD of the binary associative operation, and what licenses folding an n-ary application into nested binary applications is ASSOCIATIVITY, which is not modeled. std.algebra declares Magma as { op: fn(T, T) -> T } and Semigroup as { op: fn(T, T) -> T } -- structurally identical, differing by a blank line where the law would sit. The type whose entire content is the associativity law carries no law, so nothing in the tree can say an operation is associative, and the missing capability is one level below the signature rather than in it. Widening AlgebraTypeTemplate with a variadic arm was refused because variadicity is not a property of a parameter's TYPE -- that vocabulary answers what type a position has, not how many positions there are -- and DESIGN section 4 puts surface arity in the sugar layer that adds no power. Declaring concat's signature absent was refused because the signature is expressible and true; erasing a fact that holds is a different failure from asserting one that does not. POPULATION: measured over dag, src/v1 and src/v2 with a scanner that skips string literals -- 12 free-call sites at arity 1, 8297 at 2, 507 at 3, 200 at 4, 178 at 5, and a tail to 262, across 64 distinct arities, roughly 1200 sites above binary. Closes by re-measurement, not by opinion. RESTORATION TRIGGER: n-ary application of a binary operation DECLARED ASSOCIATIVE folds to nested binary application -- SUFFICIENT FOR accepting concat's 64 measured arities against its unchanged binary declared signature, with no exemption and no widened vocabulary. Its own prerequisite is that associativity be declarable at all, which today it is not; that grounding is a DESIGN section 5 wall-after-grounding rather than a ratchet, since associativity of a declared operation is a modeled fact and not an undecidable one." } data rung_drop_roster: List = [ + floor_cut_heal, + floor_cut_effect_gates, + floor_cut_fmt_gate, + floor_cut_merge_admission_stamping, + floor_cut_falsifier_cadence, floor_cost_contention_verdict, emitted_bytes_witness_required_lane, direct_call_arg_seam_v2_exemption, diff --git a/docs/design-ledgers.md b/docs/design-ledgers.md index c1e72c14c69..9f2bedb10d1 100644 --- a/docs/design-ledgers.md +++ b/docs/design-ledgers.md @@ -56,6 +56,7 @@ The landing measurement partitions the 31 parser-visible identities into **2 cit - **an instrument resolves an alias, lands on a name that COLLIDES with a kernel spelling, and attributes the result to the kernel** (the reference under measurement is authored QUALIFIED and points at a type alias; the reader resolves the alias, arrives at the alias declaration's own name, and that name is also a kernel name -- so the row is attributed to the kernel identity, naming THE EXACT CARRIER THE QUALIFICATION WAS WRITTEN TO MOVE AWAY FROM. **IT DOES NOT FAIL TO ANSWER; IT ANSWERS CONFIDENTLY AND WRONGLY**, and that is the whole severity: a missing answer is visible to its consumer and an inverted one is not, so the two rank completely differently and only the second can be cited as evidence for the opposite of what holds. **Distinct from `instrument_output_read_as_subject_content`, and the boundary is worth stating because they were found in the same instrument in the same hour**: there a report is COMPLETE for the reporter and read as complete for the consumer, so the defect is in the READING; here the report is wrong on a specific row it does examine, so the defect is in the INSTRUMENT and no amount of careful reading recovers it. Also distinct from `hollow_alias`, which is about a second name minted for one concept: the alias here is legitimate modelling, and what fails is a reader of it. **SPECIMEN, with a discriminating probe executed on covered ground (2026-09-01, gunbc#9907 follow-up).** `v1.tests.claim.carrier_realization_census` reports, for two functions appended to `v2.compiler.tokenize` on adjacent lines with identical position kind, differing only in alias-versus-concrete: a param authored `std.determinism.Determinism` keeps its dotted name, while a param authored `v2.std.text.String` comes back as bare `String` attributed to ``. `v2.std.text` declares `type String = FreeMonoid`, so the alias name collides with the kernel spelling. Both probes produced rows (17661 -> 17663), which is what makes the negative half evidence rather than absence -- the positive control is the whole discriminator, and the same census had already produced a null result on an uncovered fixture whose emptiness was indistinguishable from confirmation. **CONSEQUENCE MEASURED, NOT IMAGINED**: read naively, the census contradicted the namespace wall about nine function declarations and would have been read as nine admission rows asserting a binding the carrier lacks, on a merged PR. The wall was right; the contradiction was this bug. **RUNG: MECHANICALLY PREVENTABLE AT BEST TODAY AND CURRENTLY UNENROLLED** -- the wrong answer is produced silently and nothing executes over it. The next-rung trigger is that two-line probe being ENROLLED as a discriminating RED in any covered module, which is cheap; a class whose RED is two lines and still does not execute has no excuse, and naming the cheapness is what makes it rank rather than sit. **Recognition rule**: wherever a reader resolves through an alias, ask whether the resolved name could collide with a name in a DIFFERENT namespace the reader also knows -- kernel, prelude, or ambient -- because at that point the reader cannot tell them apart and will pick one silently.) - **restored bytes reviewed as authorship** (a clobber repair returns content a prior PR already merged and a prior reviewer already accepted, but a diff has no way to say so: the restored lines are ADDED LINES, so a reviewer attributes them to the repairing PR and reviews them as new work. Specimen: gunbc#9937 restored two rows that gunbc#9868 had reverted off a stale base, and review 58203 filed REQUEST_CHANGES against a DESIGN section 6 transcribed-count defect in bytes that are character-for-character gunbc#9888's merged row -- a finding correct on its merits and misaddressed by one PR. **THE SECOND-ORDER EFFECT IS WHY THIS IS A CLASS AND NOT AN ANECDOTE: it makes clobber repairs EXPENSIVE TO LAND, which biases the fleet toward leaving clobbers standing.** The repairing lane inherits review debt for content it did not write, and the only way to discharge it inside the repair is to edit another lane's cells from a base lacking their context -- which is precisely the failure the repair exists to undo, committed a second time with better manners. RECOGNITION RULE: a diff whose added lines are byte-identical to a prior merged blob. It is DECIDABLE rather than a judgement call -- `cmp` against `git show :` answers it, and provenance for the whole region comes from `git log -S` naming the commit that added the text and the commit that removed it. THE REMEDY IS THE AUTHOR'S AND IT IS CHEAP: state the restoration ahead of the diff and carry the byte-identity receipt, so a reviewer meets provenance before content; without it the same finding is re-filed against the same bytes on every re-review, and the loop is paid for twice. A finding against restored bytes is well-formed and BINDS THE DESTINATION: provenance decides who answers it and in which diff, and never whether it is answered. **THE WRONG READING OF THIS ROW WAS AUTHORED AND REFUSED IN ITS OWN FILING** (review 58220): an earlier revision said such a finding 'belongs in its own diff', which reads as licence to merge a known defect behind an authorship argument -- DESIGN section 5's hard reject, and inverted, since a restoration is exactly the motion that puts the bytes back on main. What actually happened on the specimen is the rule: the reviewer's section 6 finding was correct, the repairing lane argued for routing it elsewhere, the owning manager OVERRULED that, and the defect was repaired inside the restoration under a ruling -- which is what made the edit a decision rather than one lane rewriting another's cells. Routing is a question about AUTHORITY and context, decided by whoever owns both lanes; the bytes are reviewed at their destination either way. **Rung: mitigatable** -- the author states the restoration and carries a byte-identity receipt, and a reviewer may still miss it. **Ceiling: mechanically preventable**, because the recognition rule is decidable: a tool that joins each added line against the merged blobs of the commits git log -S names can annotate a diff as restored before a human reads it. It is not structural -- nothing can make a restoration unwritable, nor should it. **Next-rung trigger, at capability grain: the review surface distinguishes restored bytes from authored bytes without the author asserting it**, since an author-supplied notice is exactly the evidence a tired or adversarial diff will omit. **THE RECEIPT MUST BE TAKEN AT THE DESTINATION AND NOT AT THE SOURCE, and that is the transferable half.** `cmp` decides the git case because it reads the bytes where they LANDED, not the bytes an author meant to send; the general shape is ANY step between assertion and delivery altering content while the delivery reports success -- and the step is not always the one a reader would blame first. Measured the same day in three places, and the THIRD one is a caution about naming the culprit too early: git's merge region dropped a row outside the conflict markers; a review read merged bytes as authored ones; and two sessions' messages arrived with a backticked identifier deleted and a dollar-variable replaced by a plausible shell path, which BOTH of them first attributed to the message transport. That attribution was wrong, and it was settled by measurement rather than by reasoning: a third session kept the local source of a sent message, read the delivered body back out of the store, and diffed them -- identical but for a trailing newline, with backticks, a backslash continuation and a dollar-brace token all intact. The corruption was in the SENDER'S OWN SHELL, expanding an inline double-quoted argument before the tool ever saw it, and the proposed remedy of banning backticks would have cost a real notation to avoid a hazard that lives in a construction nobody has to use. A deletion leaves a gap a reader might notice; a substitution leaves a syntactically fine claim that is simply false, which is why source-side confidence is not evidence at all.) - **a review summary that inverts real roles and then affirms the join** (a review names files that all exist, assigns each the wrong role, and closes by asserting the one property it was uniquely positioned to test. Specimen: review 58215 approved gunbc#9937 at `fafd2adc7e1` with *'restoration of two ledger rows to recurring_failure_mode.dag ... plus an accompanying prose update in the gap-analysis doc ... Diff is narrow and matches the PR title.'* The carrier held ONE added row, not two; that row was a NEW class row, not a restoration of anything; the actual restoration was the docs file it demoted to 'accompanying'; and the diff did NOT match the title, because the `.dag` file had been swept in by a staged-change leak the PR body never declared. **DISTINGUISH IT FROM A HALLUCINATED SUBJECT, which is the neighbouring failure and a much easier one:** review 58070 described a `match` arm that appeared nowhere in its diff, and an invention is refutable by grep. Here EVERY NOUN IS PRESENT IN THE TREE and only the relations between them are wrong, so the usual defence -- check that the cited things exist -- returns all-clear. **THE AFFIRMATION IS THE HARM AND NOT THE MISDESCRIPTION.** A lane cannot audit its own title-versus-diff agreement with fresh eyes; a reviewer can, and this one asserted that agreement in the exact PR where it failed. A review that stays silent on a property leaves the check undone; a review that affirms it wrongly marks the check DONE, which is worse and is why this is not merely a low-quality summary. RECOGNITION RULE, and it is decidable rather than a matter of reading care: join the changed-FILE set against what the title and body claim to change, at file grain, and refuse any file the body does not account for. That join is mechanical, needs no understanding of the diff, and would have fired here. **THE BACKSTOP QUESTION IS THE SECOND HALF OF THE ROW, and its answer is honest rather than comforting:** the leaked roster row carried no regenerated `DESIGN.md` or `docs/design-ledgers.md`, and by construction the required build lane's generated-artifact phase compares every `CommitRequired` projection against its authority, so it WOULD have refused. It did not get the chance -- that lane was CANCELLED on the leaked sha when the next push superseded it, and the leak was caught by the author re-reading the diff. So the backstop is real and was not what caught it, and a row claiming the gate held here would be asserting an execution that never ran. **Rung: mitigatable** -- the harm is contained only by a second reader noticing, and on the specimen the second reader was the author. **Ceiling: mechanically preventable**, and no higher: whether a summary DESCRIBES a diff correctly is not decidable, so no construction forbids the bad summary -- but the one clause that did the damage is decidable, because a changed-file set and a body are both machine-readable. **Next-rung trigger, at capability grain: no review verdict is admissible unless a changed-FILE-set join against the declared scope has executed and passed** -- not a reviewer instructed to check it, which is the same assertion that failed here, and not a lint on summary wording, which would ratchet the prose while leaving the join undone.) +- **fabricated debt** (a declaration is authored for an exposure that does not exist, or that is already declared elsewhere, so the ledger grows a row whose trigger CANNOT FIRE because there is nothing to restore. It is the exact inverse of the unfiled gap and it is the more comfortable mistake: filing reads as diligence, the row survives review because every reviewer checks whether a declared drop is HONEST about its loss and none checks whether the loss is REAL, and the cost lands on whoever later tries to retire it. **THE HARM IS NOT MERELY CLUTTER, WHICH IS WHY IT IS A CLASS.** A drop is retired BY ITS TRIGGER AND BY NOTHING ELSE, so a row for a non-existent exposure is permanent by construction; it inflates the standing-drops list that DESIGN projects on every turn of every session, and the next reader plans against an exposure nobody has. A row DUPLICATING an existing declaration is worse still: it forks the single authority for one safety fact, so the two can be retired independently and the tree ends up asserting both that the class is dropped and that it is restored. **THE ORIGIN IS ALWAYS THE SAME, and naming it is the recognition rule: the population was read from a PARAGRAPH rather than measured from the tree.** A loss clause enumerates what was unguarded on the day it was written; capabilities return, get re-homed, or acquire their own declarations, and the sentence does not move. So the rule is: before authoring a drop, resolve every named item against the tree -- is this exposure live NOW, and does it already have a row? **TWO RECEIPTS, both caught before authoring, 2026-09-01, while splitting `gunbc.rung_drop` `floor_cut`'s six-capability loss into capability-grain rows.** (1) GENERATED-ARTIFACT DRIFT was on the loss clause's list and is RESTORED -- gunbc#9415 enrolled a required `generated-artifact` phase adjudicating every member of `committed_generated_artifacts`; the same paragraph elsewhere admits the phase took it off the list, so the row contradicted itself and a reader following the enumeration would have declared a drop for a live gate. It is now stated as a FRACTION, 1 of 7 discharged and 6 outstanding, because a population that shrinks silently cannot be checked. (2) THE PER-WITNESS EVAL DEADLINE was on the same list and ALREADY CARRIES ITS OWN DROP at `gunbc.witness_row_cost` `gunbc_ci_fast_lane_rule_note`; a second row would have been the section 3 fork, and it is cited from the sibling rows rather than re-declared. Six items on the paragraph, five real rows. **NEIGHBOURS, and the boundaries are what keep this from absorbing them.** Distinct from `unbacked_execution_claim`: there prose asserts a live relation that no authority backs, and the subject EXISTS while the claim about it is false; here the subject itself is absent and the claim of loss is the fabrication. Distinct from `rung inflation`, which reports a class as SAFER than its evidence supports -- this reports the tree as MORE EXPOSED than it is, and both mislead the same reader in opposite directions. Distinct from `restoration_promise_names_a_route_that_does_not_exist`, which is a REAL exposure with an unsatisfiable trigger; this is an unreal exposure, and the two are found by the same question asked at different ends -- does the trigger name something that exists, and does the LOSS name something that exists. **RUNG: 1 (mitigatable) -- caught by a reader resolving the population, which is exactly what happened here and is not a mechanism. CEILING: 3, since `does this exposure exist` is decidable for any loss expressed as a citation to a mechanism rather than as prose. NEXT-RUNG TRIGGER, a CAPABILITY: a drop row whose lost capability is carried as a resolvable citation to the mechanism that provided it, so a row declaring the loss of something the tree still has -- or something another row already declares -- fails to compile. Enumerating populations more carefully by hand does not retire it; it only executes this row's recognition rule once more.) - **a YAML inline comment is ingested as scalar content** (a bounded YAML reader that does not model comment separation accepts `key: value # comment` and stores `value # comment` as the value, so a syntactically valid document is silently assigned the wrong tree. Measured 2026-09-01 against `extdeps.languages.yaml.ingest` `ingest_yaml_source`: a column-zero full-line comment and an indented full-line comment both refused loudly as malformed mapping entries; an inline trailing comment was accepted and reserialized as a quoted scalar containing the comment; a hash-leading line inside a block literal was accepted and preserved as content. The last arm is the discriminating control because generated workflow run blocks contain shell comments and issue references such as `#5828`; a line-wide hash filter would reject or delete real scalar content. Repair: full-line comments are skipped only at parser block boundaries, never in literal collection, while recognizable unquoted inline comments now produce `YamlIngestRejected` until lexical inline separation is modeled. **APPROXIMATION DIRECTION:** the temporary predicate intentionally over-refuses richer unquoted scalar forms containing separation-whitespace (space or tab) followed by hash that this bounded parser does not model, excludes double-quoted scalars, and never examines block-literal content; it does not claim full YAML comment lexing. Rung: mitigatable -- the silent wrong tree becomes a typed refusal. Ceiling: structurally guaranteed once comment separation is a lexical production in the YAML grammar, so comment bytes cannot enter scalar content except through quoted or block scalar productions. Next-rung trigger: inline YAML 1.2.2 comment separation modeled lexically rather than recognized by the temporary value-text refusal. - **accepted source emits uncompilable target** (INVALID STATE: a .dag construction the front end accepts with zero blocking diagnostics, whose emission is a target program the target compiler refuses. The instance filed here is a coproduct's UNIT VARIANT standing in a NON-APPLIED TYPE POSITION -- a field, parameter or return type spelled with a constructor rather than a type. HARM: section 5 silent wrongness on the source-to-target path. gunbc says Accepted and hands over a program that cannot build, so the only wall that fires belongs to the target's compiler; where a target has no such wall, or where the emitted artifact is never compiled, nothing fires at all. Section 7 makes this the seed's floor and not the target's problem: the .dag graph is the authority and Rust is one realization, so 'rustc catches it' is exactly the outsourcing this project exists to end. THE SPECIMEN IS CARRIED IN THIS ROW RATHER THAN CITED, because the fixture that produced it was never committed to this repository (neat-otter-332, 2026-09-01). Its emitted artifacts are held by that lane's own receipts; no path is given here, since a path outside this repository is not a citation a later reader can resolve. Authored source, two modules: `scope.provider` declares `type Quantity = Time | Memory`; `scope.consumer` does `import scope.provider { Quantity, Time }`, `type NonApplied { value: Time }`, `fn field_as_quantity(subject: NonApplied) -> Quantity { subject.value }`. gunbc accepts it. DISTINGUISHING FACT, and the reason this class must not be read off the target's error code: WHAT rustc says is decided by what else the emitter minted, not by the source defect. Under the NARROW emitter classifier the consumer emits `pub use crate::scope_provider::{Quantity};` then `use crate::scope_provider::Quantity::{Time};` with no marker binding, and `pub struct NonApplied { pub value: Time }` refuses `error[E0573]: expected type, found variant Time` at `src/scope_consumer.rs:15:16` on `pub value: Time,`, label `not a type`, help `consider importing this struct instead`. Under the BROAD classifier the consumer instead emits `pub use crate::scope_provider::{Time};` beside `{Quantity}` -- the provider having emitted `pub enum Quantity { Time, Memory }` AND `pub struct Time;` -- so the field declaration COMPILES, and the refusal moves to the function: `error[E0308]: mismatched types` at `src/scope_consumer.rs:20:5` on `subject.value.clone()`, `expected Quantity, found Time`, against `expected Quantity because of return type`. INDEPENDENTLY REPRODUCED AT PARAMETER POSITION on this branch, 2026-09-01 on gunbc baeabbbf80, by a single-file source handed to the compiler: `type StampMode = StampClass | StampOther` with `fn take(stamp: StampClass) -> StampMode { stamp }`. `gunbc compile --target rust` exits 0 with 0 blocking errors, emits `pub fn take(stamp: StampClass) -> StampMode` beside `pub struct StampClass;`, and `cargo check` on the emitted crate refuses `E0308 expected StampMode, found StampClass`. One source defect; E0573, E0308-at-the-parent, and E0308-at-the-body depending on emission. THE MASK IS THE SHARP HALF, and it is fabricated plausible output rather than a lucky green: the broad classifier's marker import made the FIELD-ONLY source compile by substituting a distinct struct for a variant. It never preserved the modelled meaning, and extending the SAME accepted source across its declared parent boundary -- the function returning `Quantity` -- is what exposes it. So the narrow classifier's E0573 is this class becoming VISIBLE, not a regression the narrowing introduced. GENERAL FORM: a green obtained because the emitter manufactured a target-only entity for a source name is not evidence the source is well-typed, and the discriminator is to extend the source past the boundary the manufactured entity does not model. THE ONE .dag-SIDE SIGNAL IS ABOUT THE WRONG QUESTION: on the parameter reproduction the compile printed the ADVISORY `unlisted import use 'StampClass' (referenced but not in any import's name list)`. It fires because the name was not found among types -- the front end reached the exact fact that decides this case and reported it as import hygiene. It is not a partial wall: it is advisory, it names listing rather than type position, and the field specimen above IMPORTS `Time` explicitly, so it does not fire there at all (see `diagnostic_name_mechanism_silent`). RUNG FOUND AT: below the ladder, established by execution at the emission boundary -- the compile accepts and the emitted crate refuses. Section 4b's rung-1 mitigations are absent: nothing at the .dag boundary is typed, located or countable about this construction. CEILING: 4, structurally impossible, and the reason is that constructor identity and type identity are two distinct modelled facts whose membership is decidable from the coproduct declaration -- a variant name is reachable from that declaration as an ARM and never as a type, so the type-position slot has no constructor that admits it. No undecidable predicate is involved, so this is a wall now and not a ratchet. NEXT-RUNG TRIGGER, phrased as the capability that retires the row rather than an artifact that would contribute to one: type-position name resolution that consults the TYPE namespace alone and refuses a name resolving to a constructor with a located diagnostic, sufficient that NO Accepted program contains a variant name in any non-applied type position -- field, parameter or return. Repairing either specimen, narrowing the emitter classifier, or adding a fixture satisfies less than that and does not retire this row. RECOGNITION RULE: when the target compiler names a symbol at a type position, check whether that symbol is declared as an ARM of a coproduct in the source; if it is, the defect is in accepted .dag and the target compiler is the only wall that fired. SCOPE STATED RATHER THAN GENERALISED: executed for a unit arm at a field type and at a parameter type, Rust target only. Record-shaped arms, applied positions such as `List