From e9516f62cdd112a801fe1f353286e620c48c3ef7 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Thu, 27 Aug 2026 04:52:46 +0000 Subject: [PATCH 1/9] A required CI phase that compiles an emitted closure, with its red established by mutation Closes the executing half of DESIGN's declared rung drop "A BLOCKING EMIT-STAGE DIAGNOSTIC CAN SIT ON MAIN INDEFINITELY WITH NO REQUIRED PHASE THAT FAILS": the v2-emission phase emits and stops, and nothing downstream compiles what it emitted. This is the missing conjunct -- same producer, the emitted files written as a crate, cargo run over it. The red is manufactured every run rather than found. A green baseline alone is not a pass: the phase injects one type error into one emitted closure member, requires cargo to fail alone on it, restores the bytes byte-exactly and requires the green back. NotAttempted, NotDiscriminating and RestoreFailed each fail the phase, and a failed restore is terminal for the run rather than a per-entry finding siblings continue past. Membership is declared, admission measured, degradation red. The remainder is reported as retained identities with counts and digests, never as a percentage, and the phase's success means the selected observation was taken and persisted -- never that the corpus is clean. Co-Authored-By: Claude Opus 5 (1M context) --- .gitattributes | 1 + DESIGN.md | 4 +- dag/gunbc/ci_layer_roots.dag | 96 ++ .../emitted_closure_compile_seed_growth.dag | 53 + dag/gunbc/seed_growth_admission.dag | 4 +- dag/gunbc/stage0_crate_layout_generated.dag | 1 + dag/gunbc/witness_floor_workflow.dag | 14 +- src/v1/stage0/src/bin/claim_executor.rs | 152 ++- ...bootstrap_stage0_crate_layout_generated.rs | 1 + src/v1/stage0/src/cli_run.rs | 38 +- .../src/emitted_closure_compile_host.rs | 1073 +++++++++++++++++ .../gunbc_stage0_crate_layout_generated.rs | 2 +- .../self_host/stage0_crate_layout.dag | 1 + 13 files changed, 1424 insertions(+), 16 deletions(-) create mode 100644 dag/gunbc/emitted_closure_compile_seed_growth.dag create mode 100644 src/v1/stage0/src/emitted_closure_compile_host.rs diff --git a/.gitattributes b/.gitattributes index e46959ff478..e815c2e5600 100644 --- a/.gitattributes +++ b/.gitattributes @@ -91,6 +91,7 @@ src/v1/stage0/src/cssl_seed_linked_closure_assembly.rs !merge src/v1/stage0/src/data_initializer_identity.rs !merge src/v1/stage0/src/declaration_index.rs !merge src/v1/stage0/src/derived_realization_schedule.rs !merge +src/v1/stage0/src/emitted_closure_compile_host.rs !merge src/v1/stage0/src/main.rs !merge src/v1/stage0/src/memory_governor.rs !merge src/v1/stage0/src/partition_crate_boundary_host.rs !merge diff --git a/DESIGN.md b/DESIGN.md index 5d2e4d31236..75d1c0de20c 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -144,8 +144,8 @@ hollow alias (minimality ≠ grounding) · state-space conflation (an `Option`/` - `cargo test --workspace` · `cargo clippy --all-targets -- -D warnings` · `cargo fmt --all --check` - one-time per clone: `git config core.hooksPath .githooks` — the only documented manual seed; generated pre-commit/pre-push hooks then idempotently converge `merge.generated-artifact.driver` and re-assert `core.hooksPath` via argv derived from `gunbc.repo_local_git_config` (clones that skip hooksPath degrade to vanilla text-merge for generated-artifact paths; drift gate still guards at CI). The driver REFUSES rather than answering `true`: git reaches a low-level merge driver only when both sides changed the path since the merge base — measured on a four-case matrix, one-sided and identical changes never reach it — and taking the ours side there dropped the other side's authority-derived bytes with no conflict, twice on #7836 against the stage0 seed. It now leaves the ours side in the worktree with no conflict markers, marks the path unmerged, and prints the regeneration recipe; the class is mechanically preventable, not structural, and its next-rung trigger is the commit-writer binding rows in `gunbc.commit_workflow` - explicit actuator (CI / tooling): `gunbc run --source-root dag --source-root src/v2 --entry dag/gunbc/repo_local_git_config.dag --function converge` -- 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 `v2.workflow.required_floor` `run_required_floor`. 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, 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 and the v2-emission compile) 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. 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.** 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. 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`, `--behavioral-receipt-plan`, `--behavioral-receipt-selftest`, `--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. +- 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 `v2.workflow.required_floor` `run_required_floor`. 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, 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. 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. 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`, `--behavioral-receipt-plan`, `--behavioral-receipt-selftest`, `--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. - **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 RATHER THAN RETIRING ON ITS AUTHOR'S SAY-SO.** The instrument is `tools.emission_entry_instrument` `measure_entry_emission`, invoked as `gunbc run --source-root dag --source-root src/v2 --entry dag/tools/emission_entry_instrument.dag --function measure --arg entry= --arg report=`. It runs the same spine the deleted probe script ran — emit one entry's closure, assemble it with `cssl_assemble`, build the assembled crate under cargo's JSON message format — and returns a TYPED measurement rather than a row of text: the emit-stage population from `gunbc.emit_diagnostic_observation` and the rustc coded-diagnostic population from `extdeps.cargo_diagnostic`, each member carrying its own identity and location, so two runs can be JOINED rather than only differenced. **WHAT THE CARRIER FIXES THAT THE SCRIPT DID NOT:** `EmissionMeasurement` has no spelling in which a stage that never ran renders as a stage that ran and found nothing — an unreached stage is its own variant naming the stage — and the emit decode REFUSES when the population it recovered disagrees with the compiler's own declared total, so an unrecognised diagnostic shape stops the line instead of quietly shrinking the answer. That is the execution-provenance-loss row applied to the instrument that most needed it. **WHAT IS NOT CLAIMED.** It is a measurement route and NOT a gate: no workflow invokes it, no phase enrols it, and its exit status reports whether the INSTRUMENT completed, never whether the subject was clean. The whole-corpus route is still refused by `gunbc.whole_corpus_compile_admission` and this does not change that; it is the per-entry route that module's own scope note says fits. Every other clause of the bankruptcy above stands unchanged, including that a figure copied into prose is debt whether or not a producer exists for it. - **THE REGEN CUT DELETED A PRODUCER ALONG WITH ITS BINARY, DECLARED NOTHING, AND THIS ROW IS THAT DECLARATION (2026-08-20).** It sits beside the CI entry above rather than inside it, because the two are different facts on different clocks — that paragraph narrates what the floor and regen cuts removed, this row declares one capability the regen cut removed in silence — and because a declaration wedged into the repository's most-edited paragraph collides with every unrelated edit to it (three merge conflicts in two hours, each one re-resolving prose neither side had touched). The regen cut re-derived the deleted binary's VERIFIER half — `claim_executor --required-regen`, which compares the committed stage0 mirror against a fresh emit — and did not re-derive its PRODUCER half: writing the emitted tree to disk unconditionally, whatever the comparison then says about it. `run_required_regen` did write a candidate tree, but only on the path where the emitted and committed populations already agreed; every refusal arm returned ahead of the write. The one population asymmetry an author can actually cause is adding a module to the v1 seed closure — its mirror is emitted-not-committed by construction on the first commit that introduces it — so from the cut until this entry, that change refused while naming a file no sanctioned route in the repository produced, and its only reachable green was a hand-authored mirror. That is the same laundering the fixed-point repair above closed one gate over, arrived at from the other direction: there, the gate's only closing move was forbidden; here, the gate's only closing move did not exist. WHAT THE RUNG DROP IS, stated at the honest grain: the class is not a compiler guarantee that fell a rung, it is an OPERATION that lost its only route, so it sat outside the ladder entirely — nothing to mitigate, because nothing could be attempted. Naming it as a declared drop rather than a defect is the point of the entry: the regen cut owed one under §4b(3) and filed none, and a capability deleted in silence is exactly what §3's delete-first doctrine says the census is supposed to surface loudly. It did not surface because no dependent could refuse — the author who needed the producer was outside the tree. THE RESTORATION, and its rung: production now precedes adjudication. `v2.workflow.required_regen` `required_regen_run` is the authority, and it holds the ordering by construction rather than by check — every arm that reports a verdict carries the `CandidateTree` the verdict was computed against, so refused-with-no-tree has no spelling once emit succeeded, and the one tree-less arm is reachable only where emit produced nothing at all (*structurally guaranteed*, §4b). The host `v1_compiler.required_regen_host` `run_required_regen` mirrors that ordering by hand and is therefore only *mitigatable*; its next-rung trigger is the host being derived from the carrier rather than written beside it. The gate did not weaken: it refuses the same populations with the same typed causes, and the refusal now names the directory holding the first mirror the author must install. - **THE CITED-SYMBOL CENSUS IS NO LONGER A REQUIRED CHECK, AND THIS ROW DECLARES THE RUNG IT DROPS (2026-08-23).** It sits beside the CI entry above rather than inside it, for the reason the regen row already gives: that paragraph narrates the floor and regen cuts, this is a third drop on its own clock, and a declaration wedged into the repository's most-edited prose collides with every unrelated edit to it. WHAT WAS HERE: a second `witnesses.yml` job, `cited-symbol`, running `claim_executor --required-cited-symbol --source-root dag --source-root src/v2` and stopping the line when any authored `DeclarationRef` named a symbol that does not resolve — the executing half of §3's cite-the-symbol-not-the-position rule. **IT IS DELETED** — the job, its command authority (`gunbc.fabric_witness_run` `cited_symbol_run_command`), the job row and capability wiring in `gunbc.witness_floor_workflow`, and the closure witness that covered it. REASON: operator directive, 2026-08-23. This is not a defect finding and the mechanism was not failing; it was executing and green, and the directive is that it does not belong in CI as a separate corpus-wide job. PREVIOUS RUNG: *mechanically preventable* — a real wall, armed on every push, measured green at `checked=390` on run `32664434197` (`f49886339a5`, 2026-08-23T20:26Z). TEMPORARY RUNG: *mitigatable* — the rule survives as review diligence, which is strictly weaker in the exact way §6 already records for the deleted inert-lens census: a newly authored citation naming a symbol that does not exist is writable again, and nothing detects it. MEASURED POPULATION AT THE CUT: 390 authored references, on the last green run of the job. FUTURE EXPOSURE, STATED AS A SECOND FACT BECAUSE JOINING THE TWO IS THE DENOMINATOR ERROR THIS DOCUMENT KEEPS FINDING: unbounded. Nothing counts a citation authored after the cut and nothing refuses one, so §4b(3)'s BOUNDED-POPULATION REQUIREMENT IS NOT SATISFIED HERE, and this row does not pretend otherwise — the drop is an operator-approved exception to that clause rather than an instance of it, and saying so is the whole point of writing the row down. An earlier revision of this row read *the 390 references, plus every citation authored after it* and called that the bounded population; an exact measurement joined to an open future set is not bounded, and calling it so is the same move §5 forbids when a count copied from the current tree is asked to serve as an oracle. The measured half also rots the way §3 says positional citations do: it is the population's size AT THE MOMENT OF THE DROP, never a standing figure. WHAT WAS NOT CLAIMED WHILE THE DROP STOOD: the capability survived at its own entry point — `--required-cited-symbol` was still a flag on `claim_executor` — but a mode no workflow invokes guards nothing, and calling the surviving flag a mitigation would have been exactly the inflation §4b(1) forbids. **THE RESTORATION TRIGGER FIRED ON 2026-08-25 AND THIS ROW IS RETIRED AS A DROP, WITH ITS EXPOSURE CLOSED RATHER THAN RE-DECLARED.** The trigger read: this row retires when the citation wall is re-derived where the operator's own framing puts it — *you would just make them a normal compiler error* — checked at ingestion, on the module whose source carries the citation, from that module's own text, rather than reconstructed corpus-wide by a second job; and it named §6's module-authorship trigger as the same rung, to be landed together rather than each rebuilding a corpus walk. Both landed on one construction, `v1_compiler.declaration_index`, inside the `parse` phase of `claim_executor --required-ci`: the sweep that already parses every authored module now derives one record per module and resolves every authored `DeclarationRef` against it by keyed lookup. `--required-cited-symbol` is DELETED with the same change, so there is one route and not two. RUNG: back to *mechanically preventable*, and STRICTLY WIDER than what was dropped — the enrolled population is every authored citation in a non-fixture module (measured 1441 authored, 161 in fixture carriers, 79 naming namespaces no `.dag` module declares), not the five carriers the deleted lens's population named, and test modules are INDEXED, so the outside-index disposition those exclusions forced is not needed. WHAT THE FIRST EXECUTION FOUND, because a wall that lands green over a corpus nobody checked for two days would be the more suspicious result: 46 sites over 38 distinct targets, every one a citation naming a declaration that does not exist — the exact class this rule names, accumulated in the unguarded window this row declared unbounded. They are NOT repaired here and NOT silently excluded: they are enumerated at identity grain in `PRE_EXISTING_CITATION_DEBT` as a §5 monotone debt contract whose universe is discovered by the index itself and whose rows REFUSE once their citation stops refusing, so the roster can only shrink. WHAT IS STILL OPEN, stated so this retirement is not read as wider than it is: `v2.lens.cited_symbol_resolution` is DELETED as of 2026-08-26, and the disposition was three-way rather than the two this row admitted. The count was stale on arrival — sixteen was the file's size at #7707 and it had grown to 27 `test fn` identities by the time this sentence was written — and "dead" was true of the lens and false of a third of its witnesses. Measured against the seven symbols that file imported FROM the lens, only 6 of the 27 touch one; those 6 died with it. Six more call `resolve_declaration_ref`, which lives in `v2.std.decl_ref_resolution` and SURVIVES with four other consumers, so they are the only executing evidence for a live authority's five-arm refusal and §4b(4) rehomed them to `test.claim.long.decl_ref_resolution_witness_test` rather than deleting them with the machinery that climbed. The remaining 15 are population and projection claims about the carriers that PROJECT `DeclarationRef`s and moved to `test.claim.long.carrier_reference_integrity_witness_test`. What the corpus-wide census subsumes is TYPED-LITERAL citations specifically — `DeclarationRef` record literals and the `decl_ref`/`decl_field_ref` constructors — not "citations" in general; a prose reference inside a `String` is covered by nothing, before or after. The per-PR witness that survives was renamed `test.claim.doc_graph_reference_partition_witness_test`, because its subject is a bucket partition over `gunbc.doc_graph_roots` and never was resolution, and under the old name it would have been the only cited-symbol-named thing left in the tree — a misreading two readers made independently from exactly that surface; and the wall is host Rust rather than a modeled ingestion operation, declared as seed growth in `gunbc.declaration_index_seed_growth`. -- **A BLOCKING EMIT-STAGE DIAGNOSTIC CAN SIT ON MAIN INDEFINITELY WITH NO REQUIRED PHASE THAT FAILS, AND THIS ROW DECLARES THAT RUNG (2026-08-25).** It sits beside the CI entry above for the reason the regen and cited-symbol rows already give: that paragraph narrates the floor and regen cuts, this is a fourth drop on its own clock, and a declaration wedged into the repository's most-edited prose collides with every unrelated edit to it. **THE CLASS IS NOT ONE OPERATION.** It is any BLOCKING diagnostic produced at the EMIT stage, and the escape surface is Rust-target emission specifically: `v1.05_emit` `file_binding_refusal` returns a `FileEmissionRefusal`, and `file_emission_target_is_modeled` answers `Rust => true` with Python, Go and Dag all false, so the refusal exists only on the path that emits Rust. A parse phase cannot reach it and a typecheck cannot reach it; only a phase that EMITS over a closure containing the offending CALL SITE can. **HALF OF THIS IS ALREADY ON THE RECORD AND IS NOT CLAIMED AS NEW.** The CI entry above already declares, measured 2026-08-20, that `entry_file_touched_via_import_closure` and `compile_clean_scope_plan_for_ci` have zero references under `src/v1/stage0/src/bin`, that no CLI flag reaches them, and that the only `pub` surfaces into that chain return `Bool` — the authority survives and the capability does not. That is the missing compile capability, and it was declared five days before this row. **WHAT IS NEW IS THE SECOND HALF, AND IT IS WORSE: THE WITNESS FAMILY THAT APPEARS TO COMPENSATE IS ALSO INERT.** Measured on main run `32778026868` (`08488aee2`), nine identities named for compile-clean, and not one of them compiles anything. `compile_clean_shard_a_exemplar_compile_green`, `cross_shard_seam_preservation_holds_on_live_tree`, `perturb_fixture_green_holds`, `perturb_optional_skew_fixture_red_holds` and `perturb_unresolved_import_fixture_red_holds` are all NO-ROUTE — refused at the hermetic boundary, discovered and counted and answering nothing. `dag_compile_clean_scope_witness` and `dag_compile_clean_shard_totality_witness` declare `ReadsLiveTree`, so they are DeclinedLiveTree and never run. `compile_clean_shard_entry_paths_fast_hand_rust_witness` declares no disposition at all, so the fail-closed default makes it ReadsLiveTree and it is declined too. The single member that PASSES is `dag_compile_clean_cli_floor_agreement`, and it is `SubstrateInputsOnly`: it checks that two realizations AGREE ABOUT A POLICY ROW, never that anything is clean. **AND THE COVERAGE WOULD NOT HAVE HELPED EVEN HAD IT ROUTED**, which is what makes the pair a stronger claim than either half: `tools.dag_compile_clean_shard_transport` `shard_a_exemplar_entry_path` is `dag/std/logic.dag`. At full strength the family compiles ONE MODULE. So a reader counting witnesses named compile-clean concludes the corpus is compile-checked, and the corpus is not compile-checked and would not have been. That is §4b's worse-than-absent decoration, arrived at not by a check whose RED is unauthorable but by a family whose every member is routed away from its subject. PREVIOUS RUNG: *mechanically preventable* — the compile-clean gate ran ahead of everything else in the required run until the 2026-08-15 floor cut deleted it. TEMPORARY RUNG: **outside the ladder, not mitigatable.** This is the shape the regen row names: an operation that lost its only route has nothing to mitigate, because nothing can be attempted. Review diligence is not a fallback here in the way it is for the cited-symbol drop — a reviewer reads a diff and does not run an emitter, so no human process substitutes for the missing phase. **POPULATION: UNCOUNTED AND UNBOUNDED.** §4b(3) requires a bounded population and this row does not have one and does not pretend to. Two specimens are named below, escaping by three distinct modes; how many other blocking diagnostics stand on main today is unmeasured, and it is unmeasured by a deliberate scope decision rather than because the census is hard — the finding is the missing phase, and a specimen count would have been mistaken for the bound. Anyone who takes the named specimens as the population has made the denominator error this document keeps recording. **AND THIS ROW CLAIMS NO OPERATOR APPROVAL FOR THAT, WHICH IS WHERE IT DIFFERS FROM THE CITED-SYMBOL ROW ABOVE AND MUST NOT BE READ AS MATCHING IT.** That row's unbounded exposure is an operator-approved exception to §4b(3); this row's is simply an unmet requirement, declared as unmet. The distinction is the difference between a clause someone with the authority to waive it waived, and a clause this row does not satisfy — and reading the second as the first would manufacture an approval nobody gave, which is the authority-substitution failure this document names. THE NAMED SPECIMEN, WITH ITS PROVENANCE STATED HONESTLY BECAUSE THE TWO HALVES WERE MEASURED BY DIFFERENT PEOPLE ON DIFFERENT INSTRUMENTS: `extdeps.cloud.gcp.gcp` `ReadADC` DECLARED three structured output keys — `client_id`, `client_secret`, `refresh_token` — over a `transport file` that carries bytes, with nothing stating how a JSON document became those fields, and the compiler said so (`file transport output key client_id has no modeled channel`). **THAT SPECIMEN IS REPAIRED AS OF 2026-08-25 AND THE OPERATION NO LONGER EXISTS**, repaired ALONG THE LINE THIS ROW PRESCRIBED: `extdeps.cloud.gcp.adc_document` reads the document and decodes it through `extdeps.languages.json.parse`, so the read-then-decode seam this row ruled for is the seam that landed, and the `Secret`/`String` distinction a bytes channel could not carry is carried by a typed record. A row whose prescribed fix was implemented is evidence the prescription was right. The specimen is kept in the past tense rather than deleted because the CLASS claim below does not depend on it — and because nothing re-derives this sentence, which is why it stood stale until a session tripped over it. It was found cold and measured as the SOLE blocking diagnostic of a whole-census entry compile at `63501ff7e0`, from `--entry dag/gunbc/systemctl_show_read.dag` — a measurement this row's author did not take and does not restate as their own. **A SECOND COMPILE FROM A DIFFERENT ENTRY IS NOT A FAILED REPRODUCTION OF IT, AND THE DIFFERENCE IS THE CLASS DEFINITION DOING WORK.** Compiling `gunbc.auth.credentials` — the module that CONTAINS the call site — as its own entry refuses earlier, at typecheck, with four unrelated hard diagnostics, so that compile never reaches the stage where the channel refusal is produced. Nothing is contradicted: the two entries have different closures and stop at different phases. What the pair establishes is sharper than either alone — **the refusal is reachable from an entry whose closure INCLUDES the call site and unreachable from the file that HOLDS it**, so an emit-stage diagnostic is a property of a CLOSURE, not of a file. A per-file or per-module check would therefore not have caught this either, which is why the restoration trigger below names a phase over closures and not a linter. **A SECOND AND INDEPENDENT ESCAPE MODE, FOUND BY ACCIDENT WHILE MEASURING THE FIRST.** Those four typecheck diagnostics are not an incidental specimen of the same route — they escape a different way. `gunbc.auth.credentials` has ZERO IMPORT EDGES anywhere in `dag/` or `src/v2/`: it is an orphan, so no closure reaches it and nothing typechecks it, and its four hard errors (two `undefined variable shell`, two unresolved `AuthPrintAccessToken`) stand on main for a reason that has nothing to do with which phases emit. The first mode is *no required phase emits over this closure*; the second is *no closure reaches this module at all*. **AND A THIRD, WHICH IS THE WORST OF THEM, because it is the only one that misleads a reader rather than merely hiding from a checker.** The orphan is NOT unreferenced: `gunbc.tailscale_acl_phase2_credential` carries two `DeclarationRef` rows naming `gunbc.auth.credentials` as its credential authority — `gcp_secret_credential` and `gcp_oauth_access_token_via_adc_refresh`. So the module is CLAIMED AS AN AUTHORITY by a carrier that depends on it being correct, while no import edge reaches it and nothing typechecks it. An unreferenced orphan misleads nobody; a cited one asserts that a fact has a home, and the home does not compile. **THE THIRD MODE IS WHERE TWO DECLARED DROPS COMPOSE, AND NEITHER ROW ALONE PREDICTS IT.** The cited-symbol row above declares, from 2026-08-23, that nothing checks whether an authored citation resolves; this row declares that nothing emits over the closure a citation names. These two `DeclarationRef` rows were authored into exactly that window. A citation to a module that typechecks nowhere is invisible to both mechanisms at once — the first stopped asking *does this symbol exist*, the second stopped asking *does this module compile* — and the composition is not a complaint about either operator decision, it is what makes the population claim below concrete rather than rhetorical. Neither of the three modes was found by searching. All three were tripped over while measuring something else, which is the strongest available argument that the population below is not two or three. ONE MEASUREMENT THAT CORRECTS THE OBVIOUS ASSUMPTION, recorded so the next reader does not repeat it: compiling `extdeps/cloud/gcp/gcp.dag` AS AN ENTRY returns **0 blocking, 79 advisory**. The declaration alone does not refuse. The operation looks self-evidently broken and compiles clean in isolation, so an entry-grain check over extdeps would not have caught it either — it takes an entry whose closure reaches the call site. RESTORATION TRIGGER: this row retires when a required phase EMITS over a closure that reaches call sites — the compile re-add on the queue the floor cut created — and not when the gcp operation is repaired. Fixing the specimen closes the specimen; only the phase closes the class. The gcp repair is separately ruled: `extdeps.filesystem.filesystem_io` `Read` already models file-read with a `content` channel and `extdeps.languages.json` already models decode, so the seam is read-then-decode over two authorities that exist, and minting a gcp-specific channel would be the §3 nicknaming violation — it would additionally flatten the distinction that `client_secret` and `refresh_token` are `Secret` while `client_id` is `String`, which a bytes channel cannot carry and a typed record can. +- **A BLOCKING EMIT-STAGE DIAGNOSTIC CAN SIT ON MAIN INDEFINITELY WITH NO REQUIRED PHASE THAT FAILS, AND THIS ROW DECLARES THAT RUNG (2026-08-25).** It sits beside the CI entry above for the reason the regen and cited-symbol rows already give: that paragraph narrates the floor and regen cuts, this is a fourth drop on its own clock, and a declaration wedged into the repository's most-edited prose collides with every unrelated edit to it. **THE CLASS IS NOT ONE OPERATION.** It is any BLOCKING diagnostic produced at the EMIT stage, and the escape surface is Rust-target emission specifically: `v1.05_emit` `file_binding_refusal` returns a `FileEmissionRefusal`, and `file_emission_target_is_modeled` answers `Rust => true` with Python, Go and Dag all false, so the refusal exists only on the path that emits Rust. A parse phase cannot reach it and a typecheck cannot reach it; only a phase that EMITS over a closure containing the offending CALL SITE can. **HALF OF THIS IS ALREADY ON THE RECORD AND IS NOT CLAIMED AS NEW.** The CI entry above already declares, measured 2026-08-20, that `entry_file_touched_via_import_closure` and `compile_clean_scope_plan_for_ci` have zero references under `src/v1/stage0/src/bin`, that no CLI flag reaches them, and that the only `pub` surfaces into that chain return `Bool` — the authority survives and the capability does not. That is the missing compile capability, and it was declared five days before this row. **WHAT IS NEW IS THE SECOND HALF, AND IT IS WORSE: THE WITNESS FAMILY THAT APPEARS TO COMPENSATE IS ALSO INERT.** Measured on main run `32778026868` (`08488aee2`), nine identities named for compile-clean, and not one of them compiles anything. `compile_clean_shard_a_exemplar_compile_green`, `cross_shard_seam_preservation_holds_on_live_tree`, `perturb_fixture_green_holds`, `perturb_optional_skew_fixture_red_holds` and `perturb_unresolved_import_fixture_red_holds` are all NO-ROUTE — refused at the hermetic boundary, discovered and counted and answering nothing. `dag_compile_clean_scope_witness` and `dag_compile_clean_shard_totality_witness` declare `ReadsLiveTree`, so they are DeclinedLiveTree and never run. `compile_clean_shard_entry_paths_fast_hand_rust_witness` declares no disposition at all, so the fail-closed default makes it ReadsLiveTree and it is declined too. The single member that PASSES is `dag_compile_clean_cli_floor_agreement`, and it is `SubstrateInputsOnly`: it checks that two realizations AGREE ABOUT A POLICY ROW, never that anything is clean. **AND THE COVERAGE WOULD NOT HAVE HELPED EVEN HAD IT ROUTED**, which is what makes the pair a stronger claim than either half: `tools.dag_compile_clean_shard_transport` `shard_a_exemplar_entry_path` is `dag/std/logic.dag`. At full strength the family compiles ONE MODULE. So a reader counting witnesses named compile-clean concludes the corpus is compile-checked, and the corpus is not compile-checked and would not have been. That is §4b's worse-than-absent decoration, arrived at not by a check whose RED is unauthorable but by a family whose every member is routed away from its subject. PREVIOUS RUNG: *mechanically preventable* — the compile-clean gate ran ahead of everything else in the required run until the 2026-08-15 floor cut deleted it. TEMPORARY RUNG: **outside the ladder, not mitigatable.** This is the shape the regen row names: an operation that lost its only route has nothing to mitigate, because nothing can be attempted. Review diligence is not a fallback here in the way it is for the cited-symbol drop — a reviewer reads a diff and does not run an emitter, so no human process substitutes for the missing phase. **POPULATION: UNCOUNTED AND UNBOUNDED.** §4b(3) requires a bounded population and this row does not have one and does not pretend to. Two specimens are named below, escaping by three distinct modes; how many other blocking diagnostics stand on main today is unmeasured, and it is unmeasured by a deliberate scope decision rather than because the census is hard — the finding is the missing phase, and a specimen count would have been mistaken for the bound. Anyone who takes the named specimens as the population has made the denominator error this document keeps recording. **AND THIS ROW CLAIMS NO OPERATOR APPROVAL FOR THAT, WHICH IS WHERE IT DIFFERS FROM THE CITED-SYMBOL ROW ABOVE AND MUST NOT BE READ AS MATCHING IT.** That row's unbounded exposure is an operator-approved exception to §4b(3); this row's is simply an unmet requirement, declared as unmet. The distinction is the difference between a clause someone with the authority to waive it waived, and a clause this row does not satisfy — and reading the second as the first would manufacture an approval nobody gave, which is the authority-substitution failure this document names. THE NAMED SPECIMEN, WITH ITS PROVENANCE STATED HONESTLY BECAUSE THE TWO HALVES WERE MEASURED BY DIFFERENT PEOPLE ON DIFFERENT INSTRUMENTS: `extdeps.cloud.gcp.gcp` `ReadADC` DECLARED three structured output keys — `client_id`, `client_secret`, `refresh_token` — over a `transport file` that carries bytes, with nothing stating how a JSON document became those fields, and the compiler said so (`file transport output key client_id has no modeled channel`). **THAT SPECIMEN IS REPAIRED AS OF 2026-08-25 AND THE OPERATION NO LONGER EXISTS**, repaired ALONG THE LINE THIS ROW PRESCRIBED: `extdeps.cloud.gcp.adc_document` reads the document and decodes it through `extdeps.languages.json.parse`, so the read-then-decode seam this row ruled for is the seam that landed, and the `Secret`/`String` distinction a bytes channel could not carry is carried by a typed record. A row whose prescribed fix was implemented is evidence the prescription was right. The specimen is kept in the past tense rather than deleted because the CLASS claim below does not depend on it — and because nothing re-derives this sentence, which is why it stood stale until a session tripped over it. It was found cold and measured as the SOLE blocking diagnostic of a whole-census entry compile at `63501ff7e0`, from `--entry dag/gunbc/systemctl_show_read.dag` — a measurement this row's author did not take and does not restate as their own. **A SECOND COMPILE FROM A DIFFERENT ENTRY IS NOT A FAILED REPRODUCTION OF IT, AND THE DIFFERENCE IS THE CLASS DEFINITION DOING WORK.** Compiling `gunbc.auth.credentials` — the module that CONTAINS the call site — as its own entry refuses earlier, at typecheck, with four unrelated hard diagnostics, so that compile never reaches the stage where the channel refusal is produced. Nothing is contradicted: the two entries have different closures and stop at different phases. What the pair establishes is sharper than either alone — **the refusal is reachable from an entry whose closure INCLUDES the call site and unreachable from the file that HOLDS it**, so an emit-stage diagnostic is a property of a CLOSURE, not of a file. A per-file or per-module check would therefore not have caught this either, which is why the restoration trigger below names a phase over closures and not a linter. **A SECOND AND INDEPENDENT ESCAPE MODE, FOUND BY ACCIDENT WHILE MEASURING THE FIRST.** Those four typecheck diagnostics are not an incidental specimen of the same route — they escape a different way. `gunbc.auth.credentials` has ZERO IMPORT EDGES anywhere in `dag/` or `src/v2/`: it is an orphan, so no closure reaches it and nothing typechecks it, and its four hard errors (two `undefined variable shell`, two unresolved `AuthPrintAccessToken`) stand on main for a reason that has nothing to do with which phases emit. The first mode is *no required phase emits over this closure*; the second is *no closure reaches this module at all*. **AND A THIRD, WHICH IS THE WORST OF THEM, because it is the only one that misleads a reader rather than merely hiding from a checker.** The orphan is NOT unreferenced: `gunbc.tailscale_acl_phase2_credential` carries two `DeclarationRef` rows naming `gunbc.auth.credentials` as its credential authority — `gcp_secret_credential` and `gcp_oauth_access_token_via_adc_refresh`. So the module is CLAIMED AS AN AUTHORITY by a carrier that depends on it being correct, while no import edge reaches it and nothing typechecks it. An unreferenced orphan misleads nobody; a cited one asserts that a fact has a home, and the home does not compile. **THE THIRD MODE IS WHERE TWO DECLARED DROPS COMPOSE, AND NEITHER ROW ALONE PREDICTS IT.** The cited-symbol row above declares, from 2026-08-23, that nothing checks whether an authored citation resolves; this row declares that nothing emits over the closure a citation names. These two `DeclarationRef` rows were authored into exactly that window. A citation to a module that typechecks nowhere is invisible to both mechanisms at once — the first stopped asking *does this symbol exist*, the second stopped asking *does this module compile* — and the composition is not a complaint about either operator decision, it is what makes the population claim below concrete rather than rhetorical. Neither of the three modes was found by searching. All three were tripped over while measuring something else, which is the strongest available argument that the population below is not two or three. ONE MEASUREMENT THAT CORRECTS THE OBVIOUS ASSUMPTION, recorded so the next reader does not repeat it: compiling `extdeps/cloud/gcp/gcp.dag` AS AN ENTRY returns **0 blocking, 79 advisory**. The declaration alone does not refuse. The operation looks self-evidently broken and compiles clean in isolation, so an entry-grain check over extdeps would not have caught it either — it takes an entry whose closure reaches the call site. RESTORATION TRIGGER: this row retires when a required phase EMITS over a closure that reaches call sites — the compile re-add on the queue the floor cut created — and not when the gcp operation is repaired. Fixing the specimen closes the specimen; only the phase closes the class. The gcp repair is separately ruled: `extdeps.filesystem.filesystem_io` `Read` already models file-read with a `content` channel and `extdeps.languages.json` already models decode, so the seam is read-then-decode over two authorities that exist, and minting a gcp-specific channel would be the §3 nicknaming violation — it would additionally flatten the distinction that `client_secret` and `refresh_token` are `Secret` while `client_id` is `String`, which a bytes channel cannot carry and a typed record can. **A REQUIRED PHASE NOW COMPILES AN EMITTED CLOSURE, AND THIS ROW IS NARROWED RATHER THAN RETIRED (2026-08-26).** The trigger above says the row retires when a required phase emits over a closure that reaches call sites; a phase that emits and compiles one now exists, and it does not reach every closure, so what changes is the SIZE of the exposure and not its existence. WHAT LANDED: a fifth required phase, `emit-compile`, in the `build` lane — the same producer the `v2-emission` phase calls (`compile_entry_emission`), its emitted files written as a crate whose manifest is RENDERED from the modeled cargo authorities rather than authored as markup, and `cargo` run over it. Its subject is `gunbc.ci_layer_roots` `required_emit_compile_entries`, a bounded roster, bounded deliberately: `gunbc.whole_corpus_compile_admission` refuses a whole-bundle compile on the default runner and carries two `EXIT=137` kills behind that refusal, so a whole-corpus required compile is the one form measurement already rules out. **THE PHASE ESTABLISHES ITS OWN RED BY MUTATION, ON EVERY RUN, AND THAT IS THE POINT OF IT RATHER THAN A FLOURISH.** A cargo phase that is green because nothing was measured is exactly the decoration §4b calls worse than absent, and the compile-clean family this row already indicts is what that looks like at nine identities. So a green baseline alone is NOT a pass: `v1_compiler.emitted_closure_compile_host` `establish_discriminating_red` injects ONE type error into ONE emitted file, requires cargo to fail ALONE on it, restores the bytes byte-exactly and requires the green back — and every non-discriminating arm (`NotAttempted`, `NotDiscriminating`, `RestoreFailed`) stops the line with its own typed cause. The restore is as much of the evidence as the failure: without it a red could be residue from the emission rather than from the fault. **WHAT IS STILL OPEN, AND THE ROW STAYS FOR IT.** Escape mode one is narrowed, not closed — a blocking emit-stage diagnostic in a closure no rostered entry reaches still fails no phase, and the population of such closures remains uncounted. Escape modes two and three are UNTOUCHED: an orphan module no closure reaches is still typechecked by nothing, and a `DeclarationRef` naming it still asserts a home that does not compile. The phase carries no diagnostic count, no baseline and no ratchet — a merge-blocking comparison against a population measured on the current tree is the tree-copied oracle §5 rejects — so it answers *does the emitted tree compile*, never *how clean is it*. **THE COVER IS NOT THE CORPUS, AND THE PHASE'S OWN OUTPUT SAYS SO**, because the failure this row already indicts is exactly a reader counting compile-clean-named things and concluding the tree is compile-checked. The summary line reports the covered entries beside the count of authored `.dag` modules under the source roots, so the misreading is unavailable from the log rather than merely avoidable by anyone who goes and reads the roster. **WHAT THE COVER'S SIZE IS ACTUALLY BOUNDED BY, MEASURED RATHER THAN ASSUMED:** an entry costs ~40–50s wall and ~85% of that is `compile.reconcile`, paid INDEPENDENTLY PER ENTRY over closures that overlap heavily — most of `dag/std` sits in nearly every closure. That is a §2 cost-shape defect, not a budget fact: the same modules are reconciled tens of times in one run, and §6's bare-minimum-cost rule says a proven cost-shape defect is fixed regardless of the realized n. So the honest reading is not *the ceiling is forty entries* but *the per-entry cover is the wrong unit, and forty is what the wrong unit buys*. THE ROW RETIRES on the CAPABILITY, not on the cover's size: when required emission coverage reaches every closure the corpus has, by whatever construction, AND THAT INSTRUMENT IS SUFFICIENT TO COMPLETE AND PERSIST THE WHOLE-ROSTER TRANSACTION WITHIN THE ADMITTED RUNNER ENVELOPE. The sufficiency clause is not belt-and-braces: without it the trigger fires the moment a phase named for whole-roster coverage is ENROLLED, which a partial phase satisfies while the capability is still absent — the same defect one level in from the roster-size version, since the roster can be whole while the run that walks it cannot finish or cannot keep what it observed. AND THE NAME CARRIES THE SAME BURDEN: this phase's required context is a SELECTED emission observation, never a whole one, and its success means THE SELECTED OBSERVATION WAS TAKEN AND PERSISTED — never THE CORPUS IS CLEAN. A partial phase is a legitimate wall for an exact selected subject and zero wall for its complement; it becomes decoration only when its name, its trigger, or its consumers let the selected proposition stand in for the exhaustive one, which is why the remainder is reported as RETAINED IDENTITIES rather than as a percentage. A fraction says how much is unobserved and never which, so it is not the bounded population §4b(3) asks for; it may stand as context and may never be the gap's identity or its dissolution trigger. A trigger reading *grow the roster* would be satisfied at forty-one while the corpus stayed unmeasured, which is why it is not written that way. Its named dependency is the reconcile sharing above — a cover whose unit is the entry cannot reach the corpus at any budget, so the unblocking work is making one run reconcile a shared closure once, and that is a separate lane this row does not claim. diff --git a/dag/gunbc/ci_layer_roots.dag b/dag/gunbc/ci_layer_roots.dag index b3cfeedde97..4f0b6ff22cd 100644 --- a/dag/gunbc/ci_layer_roots.dag +++ b/dag/gunbc/ci_layer_roots.dag @@ -123,6 +123,102 @@ data required_v2_emission_entries: List = ["src/v2/compiler/00_compile.d // self-host probe, product receipt and cargo census become four answers to one question. data required_v2_emission_dissolution: DissolutionCondition = unbound_dissolution(description: "the authentic self-host product receipt is required on every admitted candidate and carries this emission boundary (same producer, stopping before cargo); then the standalone --required-v2-emission phase, required_v2_emission_entries and their host reader delete together") +// THE ENTRIES WHOSE EMITTED CLOSURE A REQUIRED PHASE COMPILES. +// +// WHY THIS ROW IS SEPARATE FROM required_v2_emission_entries ABOVE, rather than the same list +// read twice: the two phases answer different questions and have different cost shapes. The +// emission phase asks whether the emitter produced a tree at all, and its subject is the widest +// closure one entry names because emission is cheap. This phase asks whether the tree rustc +// accepts it, and cargo over a closure is not cheap, so its subject is chosen for what it +// compiles rather than for how wide it is. Sharing one row would have forced one answer to both +// questions and, in practice, would have pinned the emission phase's subject to whatever the +// compile phase could afford. +// +// THE SAME NARROW ARRIVES THROUGH THE BUDGET, AND IT IS THE ONE MORE LIKELY TO BE WRITTEN. +// A cover computed as "the N entries that fit the window" looks like a cost decision rather +// than an observation, so it does not read as a derived cover at all -- but it drops a member +// exactly when that member becomes slow, and an entry becomes slow when it breaks. The verdict +// is then a function of the budget rather than of the emitted bytes, which is the same +// empty-observation narrow one level out. Membership is a row; cost decides whether a row is +// ADDED, and never whether a declared row is MEASURED. +// +// MEMBERSHIP IS DECLARED HERE; IT IS NEVER DERIVED AT RUN TIME. A cover computed each run as +// "whatever currently compiles" is SELF-DISARMING: it drops a member at precisely the moment +// that member becomes the defect this phase exists to catch, and reports green over a quietly +// smaller subject. That is DESIGN's empty-observation narrow -- an observation that could not +// express what changed rendered as the verdict nothing is affected -- and it is strictly worse +// than the absorbing fallback, because a widen is merely expensive and a narrow is silently +// uncovered. Measured against today's corpus rather than argued: dag/std/interval.dag does not +// compile right now, so a derived cover would exclude it and be green, while a declared cover +// containing it is RED, which is the correct answer. +// +// SO THE MEASUREMENT SITS AT THE DECISION, NOT AT THE VERDICT, and the two must not be fused: +// MEMBERSHIP is DECLARED -- this row. Adding or removing an entry is a decision a reviewer sees. +// ADMISSION is MEASURED -- an entry may not be ADDED until its emitted closure has been +// measured clean, because a member that is red on main makes the phase permanently red +// rather than discriminating. +// DEGRADATION is RED -- once declared, a member that stops compiling FAILS THE PHASE. It is +// never dropped, never skipped, never reported as not-applicable. +// THE COUNT is REPORTED EVERY RUN -- declared members with their per-entry verdicts, never a +// count of survivors. +// +// DELETING A ROW TO GET GREEN IS NOT THE REMEDY, and this sentence is here because the first +// person to hit a red member will be able to argue that it looks like maintenance. It is not: +// the red IS the finding, and removing the member deletes the finding rather than resolving it. +// The remedy is to repair the emission, or -- if the entry is genuinely no longer worth +// covering -- to remove it as a declared COVERAGE decision argued on its own terms, never as a +// way to turn a failing run green. +// +// THE ROSTER IS BOUNDED AND MUST STAY BOUNDED. gunbc.whole_corpus_compile_admission refuses a +// whole-bundle compile on the default runner and records two EXIT=137 kills behind that +// refusal, and the required path is already the fleet's dominant serialized cost. So widening +// this list is a COST DECISION taken deliberately, exactly as the row above is, and never a +// reflex -- but it is still a row, not a Rust edit. +// +// WHAT A READER MUST NOT CONCLUDE FROM IT. This is not corpus compile coverage and does not +// claim to be. A blocking emit-stage diagnostic in a closure no entry here reaches still +// escapes every required phase, which is the narrowed remainder DESIGN's emit-stage row carries. +// +// WHY THESE ENTRIES. Every one was MEASURED CLEAN before being written here -- emitted, and its +// emitted closure compiled -- which is the admission rule this row states below. They are not a +// cover in any principled sense: they are the entries whose closures were measured and found +// admissible, ordered widest first, and the list exists to be grown. +// +// WHAT BOUNDS IT IS ADMISSIBILITY, NOT COST, and that is the opposite of what the cost figures +// suggest. A warm entry costs seconds, so budget would permit hundreds. What it may not permit +// is MEMBERSHIP: entries exist today whose emitted closure does not compile -- the v2 compiler +// root, the emission phase's own subject one row up, is one of them -- and admissibility does +// NOT fail entry by entry, because closures SHARE defects. One uncompilable site in a +// widely-imported module disqualifies every entry whose closure reaches it, so the admissible +// set is a property of where broken sites sit in the import graph rather than of how many +// entries anyone can afford. This roster is therefore a BEACHHEAD on a live frontier, and it is +// sized against a TEMPORARY CONDITION: emitter repairs that clear a widely-reached site return +// many entries to admissibility at once. +// +// A FAILED RESTORE IS TERMINAL FOR THE RUN. If the mutation arm's byte-exact restore does not +// hold, the phase stops at that entry and reports every later one as NotExecuted; it is not a +// per-entry finding the siblings continue past, and it is not recoverable by re-running the +// phase. The reason is mechanical rather than procedural -- the arms share one cargo target +// directory, so after a failed restore no later baseline taken through it is attributable -- +// and the effect is that a head whose restore arm did not hold has no green from this phase at +// all, rather than a green whose restore was never established (operator ruling relayed +// 2026-08-26). +// +// THE INSTRUMENT, not its output (DESIGN, the 2026-08-24 measurement ruling): the phase prints +// one `required-ci: emit-compile` line per entry carrying its own file count, baseline verdict +// and mutation verdict, and `claim_executor --required-ci --required-lane build` re-derives +// them. No figure from a run is transcribed here. +data required_emit_compile_entries: List = [ + "dag/gunbc/ci_layer_roots.dag", + "dag/gunbc/scm/load_standing.dag", + "dag/extdeps/uri.dag", + "dag/std/measure.dag", + "dag/std/node.dag", + "dag/std/content_hash.dag", + "dag/std/abi.dag", + "dag/std/logic.dag" +] + data frontier_probe_witness_measure_receipt_note: String = "Measured durations cited on commit_gate SpanEnrolled cost_basis rows are WallClock: claim_batch performance receipts use wall_nanos (performance_receipt_from_witness), not the thread-CPU nanos that budget_completion_outcome gates on (operator msg_e24f4cab). Do not compare these figures to the per-witness eval CPU budget without stating the clock. The arm is named in std.measure ClockBasis, which is the single clock-basis authority; this sentence said WitnessCostWallEval until 2026-08-05, naming a second carrier that std.realization_schedule declared for one day and that witness_cost_clock_note records the dissolution of. The advice the sentence gives is exactly what the surviving carrier now enforces rather than advises: witness_row_cost_verdict answers BasisClockMismatch instead of comparing across clocks." data frontier_probe_witness_measure_receipt_read_failure: String = "target/frontier-probe-survey/matrix_readthrough_claim_batch_receipt.log" diff --git a/dag/gunbc/emitted_closure_compile_seed_growth.dag b/dag/gunbc/emitted_closure_compile_seed_growth.dag new file mode 100644 index 00000000000..a5e8a8e1845 --- /dev/null +++ b/dag/gunbc/emitted_closure_compile_seed_growth.dag @@ -0,0 +1,53 @@ +module gunbc.emitted_closure_compile_seed_growth + +import std.decl_ref { DeclarationRef, WholeDeclaration } +import std.types { String } +import gunbc.roadmap_model { RoadmapNodeId } +import gunbc.seed_growth { SeedGrowthJustification } + +// Seed-growth obligation for the required `emit-compile` phase's host. It is homed here, beside +// the obligation it declares, rather than inside gunbc.seed_growth_admission, which owns the +// ROSTER and the join and would otherwise accumulate every lane's rows in the module that +// adjudicates them. +data emitted_closure_compile_seed_growth_note: String = "Seed-growth obligation for the host behind the required emit-compile phase.\n\nWHAT THE CHANGE IS. The v2-emission phase emits one entry's closure and stops at the emitter. Its own header in cli_run.rs enumerates what it therefore cannot see, and the first item is 'a rustc error in the emitted tree (nothing here compiles the emission)'. DESIGN's Building-&-checks section carries a declared rung drop headed 'A BLOCKING EMIT-STAGE DIAGNOSTIC CAN SIT ON MAIN INDEFINITELY WITH NO REQUIRED PHASE THAT FAILS', whose restoration trigger reads: this row retires when a required phase EMITS over a closure that reaches call sites -- the compile re-add on the queue the floor cut created. This host is that phase: same producer (compile_entry_emission), the emitted files written as a crate, cargo run over it.\n\nWHY IT IS NOT A SECOND EMITTER. The phase calls the SAME transaction the emission phase calls and adds one stage after it. A green there and a green here cannot be two facts about two emissions, which is exactly the property a separately-authored probe would have given up.\n\nWHY THE MANIFEST IS DERIVED AND NOT AUTHORED. The corpus already carries a hand-concatenated probe manifest (tools.self_host_curated_seed_linked_harness cssl_v1_compiled_probe_lib_cargo_toml), marked scaffold debt in its own module for being concat-authored TOML. Consuming it from a merge-blocking gate would have pinned that debt open on the required path, and authoring a second one would have been new scaffolding the operator declined on 2026-08-25. The manifest here is rendered from the modeled cargo authorities instead -- extdeps.rust.version render_cargo_package_header_prefix for the package header, v1.compiler.stage0_crates stage0_foundation_runtime_dependencies for the seed's own runtime dependency set, and render_stage0_crate_dep per row -- so no new markup is authored at all.\n\nNO IMPL BLOCK, AND THAT IS DELIBERATE. Every item in the file is a free function or a type, because an impl method has no DeclarationRef spelling -- std.decl_ref offers WholeDeclaration or NamedField and neither names a method on an impl block -- so methods would have grown the class gunbc.seed_growth_admission reports as seed_growth_uncitable_item_keys. v1_compiler.declaration_index took the same route for the same reason. Uncitable items added by this change: ZERO.\n\nHAND-ITEM DELTA: enumerated below rather than counted. src/v1/stage0/src/cli_run.rs adds no declaration -- one #[path] mod line and one re-export list -- and src/v1/stage0/src/bin/claim_executor.rs adds one variant to an existing exhaustive enum and one phase body inside an existing function; both dispositions are ExistingSeedItemModified, and listing them would net a modification into an addition census.\n\nWHAT THE EXECUTED EVIDENCE IS, because the seed's own unit tests are not it. The Rust suite was removed from CI on 2026-07-11, so nothing under #[cfg(test)] executes on the merge path and none of it may be cited as coverage. The executed evidence is the phase itself: establish_discriminating_red injects one type error into one emitted file on EVERY required run, requires it to fail alone, restores the bytes and requires the green back -- and a mutation that fails to go red is a PHASE FAILURE, not a note. That is DESIGN 4b's authorable-RED question answered by execution rather than by inspection, and it is why a green from this phase carries information that a bare cargo-exit-status phase would not." + +data emitted_closure_compile_seed_growth_justification: SeedGrowthJustification = SeedGrowthJustification { + hand_authored_declarations: [ + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "REQUIRED_EMIT_COMPILE_ENTRIES_DATA_NAME", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "PROBE_PACKAGE_NAME", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "MUTATION_ITEM", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "CargoVerdict", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "MutationSubject", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "MutationVerdict", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "EmitCompileOutcome", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "cargo_verdict_compiled", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "cargo_verdict_summary", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "cargo_verdict_stderr_tail", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "mutation_subject_rust_module", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "mutation_subject_name", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "mutation_verdict_discriminated", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "mutation_verdict_summary", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "emit_compile_outcome_passed", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "emit_compile_outcome_summary", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "required_emit_compile_entries", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "probe_manifest", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "probe_crate_dir", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "write_probe_crate", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "run_cargo", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "closure_modules", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "mutation_subject", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "establish_discriminating_red", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "entry_rust_module", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "run_emit_compile_entry", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "run_required_emit_compile", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "manifest_carries_the_modeled_dependency_rows", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "mutation_prefers_a_closure_member_over_the_entry", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "mutation_falls_back_to_the_entry_and_names_it", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "a_green_baseline_does_not_pass_without_the_discrimination", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "an_unreached_entry_is_not_a_pass", field: WholeDeclaration } + ], + reason: "WHY RUST IS STILL NEEDED, and it is a REACHABILITY limit rather than a modeling gap. The subject is a required CI phase: it must run inside claim_executor, which is the only witness-executing consumer in the tree, and its stages are host effects -- writing an emitted tree to disk and spawning cargo over it. The required floor's hermetic envelope REFUSES host effects during preparation, so a .dag witness whose subject is a subprocess exit status is counted executed while its assertion never runs; DESIGN's Building-&-checks section records that boundary in as many words, and records that mocking the refusal would pass the witness against a fabricated exit status. So the phase has to live where the effects do, exactly as required_regen_host and partition_crate_boundary_host do.\n\nWHY IT IS ADMITTED AGAINST THE v1 FREEZE, ON PRECEDENT RATHER THAN ANALOGY. gunbc.v1_maintenance_standing v1_seed_standing admits a change by PURPOSE -- does it serve the v2 self-host program -- and the purpose test reaches the INSTRUMENT that measures that program, not only the program. This is that instrument in the most direct available sense: the self-host claim IS that the emitted tree compiles and behaves, and until now nothing on the merge path compiled an emitted tree at all. gunbc.floor_non_verdict_enrollment and gunbc.declaration_index_seed_growth are both admitted on that same footing. Classified against the five refused classes: NewLanguageBehavior -- no, the compile pipeline is byte-untouched, no diagnostic is added, moved or removed. NewCompatibilityObligation -- no, nothing is kept working for an old caller. NewEscapeHatchOrAdmissionRow -- no, and the direction is opposite: this adds a wall and adds no flag, env var or mode that skips it. SeedFeatureCompletion -- no, the seed compiler gains no capability; it compiles exactly what it compiled before. PublicSurfaceGrowth -- the nearest, and the test is a diff over THE EMITTED SEED'S EXPORTED DECLARATIONS: the file is wired by #[path] mod inside cli_run.rs exactly as declaration_index.rs, phase_profile.rs and partition_crate_boundary_host.rs are, so it contributes no pub mod line to the emitted lib.rs and its SeedRetainedIntrinsicRegistration carries has_pub_mod: false.\n\nWHAT IS NOT CLAIMED. This phase is not a compile of the corpus and must not be read as one: gunbc.whole_corpus_compile_admission refuses a whole-bundle compile on the default runner and records two EXIT=137 kills behind that refusal, so the subject is a bounded roster of entries in gunbc.ci_layer_roots required_emit_compile_entries. It carries no diagnostic count, no baseline and no ratchet -- a merge-blocking comparison against a population measured on the current tree is the tree-copied oracle DESIGN 5 rejects.", + owning_dissolution_lane: "v1-hand-queue-drain" as RoadmapNodeId, + trigger: "Delete this host when the phase's two host effects are modeled and a modeled actuator can perform them: writing an emitted file set to a directory, and invoking cargo over a manifest with a typed outcome. extdeps.cargo already models the manifest, the dependency rows and the target kinds, and extdeps.filesystem.filesystem_io models the write, so what is missing is the ACTUATION -- a modeled operation the required run can execute without the hermetic envelope refusing it. When that exists, run_emit_compile_entry becomes a .dag fold over those two operations and every item here is deleted, not re-homed. A PARTIAL migration is admissible and is the expected shape: the moment the cargo invocation is a modeled transport, run_cargo and the CargoVerdict vocabulary go first and the emission-to-disk half stays behind. What does NOT dissolve these items is the phase merely changing its roster, and what does NOT dissolve them is a hermetic witness asserting a fabricated exit status -- that would retire the evidence while retiring nothing it guards.", + current_boundary: "src/v1/stage0/src/emitted_closure_compile_host.rs; src/v1/stage0/src/cli_run.rs (the #[path] mod line and the re-export); src/v1/stage0/src/bin/claim_executor.rs (RequiredCiPhase::EmitCompile and its phase body); dag/gunbc/ci_layer_roots.dag required_emit_compile_entries; src/v2/compiler/self_host/stage0_crate_layout.dag; dag/gunbc/emitted_closure_compile_seed_growth.dag" +} diff --git a/dag/gunbc/seed_growth_admission.dag b/dag/gunbc/seed_growth_admission.dag index 636f691a3d0..777dc46783d 100644 --- a/dag/gunbc/seed_growth_admission.dag +++ b/dag/gunbc/seed_growth_admission.dag @@ -5,6 +5,7 @@ import gunbc.reference_closure_binder_seed_growth { reference_closure_binder_see import gunbc.bare_reference_scanner_admission { bare_reference_scanner_seed_growth_justification } import gunbc.claim_unwind_seed_growth { claim_unwind_seed_growth_justification } import gunbc.declaration_index_seed_growth { declaration_index_seed_growth_justification } +import gunbc.emitted_closure_compile_seed_growth { emitted_closure_compile_seed_growth_justification } import gunbc.parse_refusal_location_seed_growth { parse_refusal_location_seed_growth_justification } import gunbc.qualified_pipe_callee_seed_growth { qualified_pipe_callee_seed_growth_justification } import gunbc.roadmap_authority { observation_scoped_run_seed_growth_justification } @@ -87,7 +88,8 @@ fn seed_growth_justification_roster() -> List { parse_refusal_location_seed_growth_justification, claim_unwind_seed_growth_justification, declaration_index_seed_growth_justification, - qualified_pipe_callee_seed_growth_justification + qualified_pipe_callee_seed_growth_justification, + emitted_closure_compile_seed_growth_justification ] } diff --git a/dag/gunbc/stage0_crate_layout_generated.dag b/dag/gunbc/stage0_crate_layout_generated.dag index c169c94d90a..3ac048b8741 100644 --- a/dag/gunbc/stage0_crate_layout_generated.dag +++ b/dag/gunbc/stage0_crate_layout_generated.dag @@ -62,6 +62,7 @@ data generated_stage0_filenames: List = [ "cssl_seed_linked_closure_assembly.rs", "required_regen_host.rs", "partition_crate_boundary_host.rs", + "emitted_closure_compile_host.rs", "v2_compiler_compile.rs", "v2_compiler_program_assembly.rs", "v2_compiler_source_authority.rs", diff --git a/dag/gunbc/witness_floor_workflow.dag b/dag/gunbc/witness_floor_workflow.dag index 566e577a6ec..33168b35def 100644 --- a/dag/gunbc/witness_floor_workflow.dag +++ b/dag/gunbc/witness_floor_workflow.dag @@ -190,8 +190,9 @@ data witness_floor_concurrency_group: String = "witness-floor-${{ github.event.p // WHAT "FULL COMPILE" DOES AND DOES NOT MEAN, named here because the 2026-08-25 split puts a // job called `build` beside a phase called `v2-emission` and the pair invites exactly one wrong // inference. The v2 emission phase compiles a `.dag` ENTRY TO RUST SOURCE and stops before -// cargo; this step cargo-builds exactly the two bins named below, because they are the two the -// jobs run. NEITHER COMPILES THE REST OF THE RUST WORKSPACE. A declared `[[bin]]` outside this +// cargo; the emit-compile phase beside it takes that source the rest of the way and cargo-builds +// it, over its own bounded entry roster and never over the corpus; this step cargo-builds +// exactly the two bins named below, because they are the two the jobs run. NEITHER COMPILES THE REST OF THE RUST WORKSPACE. A declared `[[bin]]` outside this // list is not built by any required phase, so a hand-authored Rust bin can fall behind a // generated struct and sit on main indefinitely -- which is not hypothetical: measured // 2026-08-25, `infer_semantics_witness` fails to compile on main with six `E0063`s against @@ -370,9 +371,12 @@ fn witness_floor_build_step(build_script: String) -> Step { // phase -- and a phase that could not run reports SKIPPED as its own state, never as silence // and never as a pass. // -// THE ROSTER IS FOUR PHASES ACROSS TWO LANES. The paragraph below records the 2026-08-21 cut -// to three; #9035 then added v2-emission, and the 2026-08-25 split partitioned the four into -// `build` (regen, v2-emission) and `witnesses` (parse, floor). The cut phases that paragraph +// THE ROSTER IS READ FROM THE RUN, NOT FROM THIS COMMENT. Each lane announces every phase -- +// one `phase ` line for the phases it owns and one `ROUTED to lane ` line for the +// phases it does not -- so one job's log names the whole roster. The paragraph below records the +// 2026-08-21 cut to three; #9035 then added v2-emission, and the 2026-08-25 split partitioned +// the roster into `build` (regen, v2-emission, partition-crates, emit-compile) and `witnesses` +// (parse, floor). A count transcribed here has already gone stale twice. The cut phases that paragraph // enumerates stay cut -- neither the addition nor the split restored any of them. // // THE ROSTER WAS THREE PHASES, NOT FOUR (operator ruling, 2026-08-21): the src/v1 .dag parse diff --git a/src/v1/stage0/src/bin/claim_executor.rs b/src/v1/stage0/src/bin/claim_executor.rs index 9e29ecbf041..3b23de7f027 100644 --- a/src/v1/stage0/src/bin/claim_executor.rs +++ b/src/v1/stage0/src/bin/claim_executor.rs @@ -318,6 +318,7 @@ fn run() -> Result { let mut required_ci_mode = false; let mut required_ci_lane: Option = None; let mut required_v2_emission_mode = false; + let mut required_emit_compile_mode = false; let mut required_v2_emission_selftest_mode = false; let mut required_regen_mode = false; let mut emit_partition_crates_mode = false; @@ -370,6 +371,12 @@ fn run() -> Result { "--required-v2-emission" => { required_v2_emission_mode = true; } + // THE PHASE AS ITS OWN ENTRY POINT, for the reason `--required-v2-emission` is one: + // running this alone is a real local action, and it runs the SAME producer the + // required phase runs, so a green here and a green there cannot be two facts. + "--required-emit-compile" => { + required_emit_compile_mode = true; + } "--required-v2-emission-selftest" => { required_v2_emission_selftest_mode = true; } @@ -786,6 +793,90 @@ fn run() -> Result { ran.push("v2-emission"); } + // PHASE — the emitted closure, COMPILED. + // + // WHAT IT ANSWERS THAT THE PHASE ABOVE DOES NOT. `v2-emission` stops at the emitter: + // its own header names what it cannot see, and the first item is "a rustc error in the + // emitted tree (nothing here compiles the emission)". DESIGN's declared rung drop -- + // "A BLOCKING EMIT-STAGE DIAGNOSTIC CAN SIT ON MAIN INDEFINITELY WITH NO REQUIRED + // PHASE THAT FAILS" -- names a required phase that emits over a closure and compiles it + // as its restoration trigger. This is that phase. + // + // THE PHASE ESTABLISHES ITS OWN DISCRIMINATING RED, EVERY RUN. A cargo verdict that is + // green because nothing was measured is the decoration DESIGN 4b calls worse than + // absent, so a green baseline alone is NOT a pass here: the run injects one fault into + // one emitted file, requires it to fail alone, restores the bytes and requires the + // green back. `emit_compile_outcome_passed` is that conjunction, and every + // non-discriminating mutation arm stops the line with its own typed cause. + if required_ci_phase_selected(RequiredCiPhase::EmitCompile, required_ci_lane) { + eprintln!( + "required-ci: phase emit-compile (one entry's emitted closure, compiled, \ + with its own mutation-established red)" + ); + match v1_compiler::cli_run::run_required_emit_compile(&source_roots) { + Ok(outcomes) => { + let mut not_passed = 0usize; + for outcome in &outcomes { + eprintln!( + "required-ci: emit-compile {}", + v1_compiler::cli_run::emit_compile_outcome_summary(outcome) + ); + if !v1_compiler::cli_run::emit_compile_outcome_passed(outcome) { + not_passed += 1; + if let v1_compiler::cli_run::EmitCompileOutcome::Measured { + baseline, + .. + } = outcome + { + for line in + v1_compiler::cli_run::cargo_verdict_stderr_tail(baseline) + .lines() + { + eprintln!("required-ci: emit-compile cargo| {line}"); + } + } + } + } + // THE COUNT IS OF DECLARED MEMBERS, NOT OF SURVIVORS. A phase that reported + // how many entries passed would read identically whether the roster held + // ten members or one, which is the coverage-moves-unnoticed failure the + // roster row refuses by construction. + eprintln!( + "required-ci: emit-compile declared={} passed={} not_clean={not_passed}", + outcomes.len(), + outcomes.len() - not_passed + ); + // ONE REPORT, BOTH SURFACES. See `emit_compile_report`: the remainder is + // identities rather than a percentage, and a remainder that could not be + // persisted stops the line. + let (report, retention_error) = v1_compiler::cli_run::emit_compile_report( + &outcomes, + &source_roots, + "required-ci: emit-compile", + ); + for line in report { + eprintln!("{line}"); + } + if let Some(err) = retention_error { + phase_failures + .push(format!("emit-compile (remainder not retained: {err})")); + } + if not_passed > 0 { + phase_failures.push(format!( + "emit-compile ({not_passed} entry/entries not clean)" + )); + } + } + // A ROSTER THAT NAMES NOTHING IS NOT A CLEAN RUN. Reporting zero entries + // compiled as a pass is the empty-observation narrow. + Err(e) => { + eprintln!("required-ci: emit-compile roster refused: {e}"); + phase_failures.push(format!("emit-compile roster: {e}")); + } + } + ran.push("emit-compile"); + } + // PHASE — the derived stage0 partition's crate boundary. // // WHAT IT ANSWERS, and it is deliberately not what a reader assumes from the name: the @@ -933,6 +1024,55 @@ fn run() -> Result { }; } + if required_emit_compile_mode { + let roots = if source_roots.is_empty() { + v1_compiler::cli_run::witness_layer_roots() + } else { + source_roots.clone() + }; + match v1_compiler::cli_run::run_required_emit_compile(&roots) { + Ok(outcomes) => { + let mut not_passed = 0usize; + for outcome in &outcomes { + eprintln!( + "required-emit-compile: {}", + v1_compiler::cli_run::emit_compile_outcome_summary(outcome) + ); + if !v1_compiler::cli_run::emit_compile_outcome_passed(outcome) { + not_passed += 1; + if let v1_compiler::cli_run::EmitCompileOutcome::Measured { + baseline, .. + } = outcome + { + for line in + v1_compiler::cli_run::cargo_verdict_stderr_tail(baseline).lines() + { + eprintln!("required-emit-compile: cargo| {line}"); + } + } + } + } + let (report, retention_error) = v1_compiler::cli_run::emit_compile_report( + &outcomes, + &roots, + "required-emit-compile:", + ); + for line in report { + eprintln!("{line}"); + } + return if not_passed == 0 && retention_error.is_none() { + Ok(ExitCode::SUCCESS) + } else { + Err(ExitCode::from(1)) + }; + } + Err(e) => { + eprintln!("required-emit-compile: roster refused: {e}"); + return Err(ExitCode::from(1)); + } + } + } + if required_v2_emission_mode { let roots = if source_roots.is_empty() { v1_compiler::cli_run::witness_layer_roots() @@ -1302,6 +1442,7 @@ enum RequiredCiPhase { Parse, Regen, V2Emission, + EmitCompile, PartitionCrates, Floor, } @@ -1312,6 +1453,7 @@ impl RequiredCiPhase { RequiredCiPhase::Parse => "parse", RequiredCiPhase::Regen => "regen", RequiredCiPhase::V2Emission => "v2-emission", + RequiredCiPhase::EmitCompile => "emit-compile", RequiredCiPhase::PartitionCrates => "partition-crates", RequiredCiPhase::Floor => "floor", } @@ -1328,6 +1470,13 @@ impl RequiredCiPhase { RequiredCiPhase::Parse => RequiredCiLane::Witnesses, RequiredCiPhase::Regen => RequiredCiLane::Build, RequiredCiPhase::V2Emission => RequiredCiLane::Build, + // THE SECOND HALF OF THE SAME QUESTION, so it rides beside the emission it + // extends: v2-emission asks whether the emitter produced a tree, this asks + // whether the tree it produced compiles. Its cost is a cargo build over one + // emitted closure against the dependency graph this lane's own first step has + // already compiled -- it shares that target directory and that profile + // deliberately, so the arm compiles the emitted crate and nothing else. + RequiredCiPhase::EmitCompile => RequiredCiLane::Build, // A DRIFT COMPARISON OVER DERIVED RUST, so it belongs beside regen and // v2-emission rather than beside the witness corpus. The two lanes carry no // `needs` edge, so this costs nothing until the build lane exceeds the floor's @@ -1338,10 +1487,11 @@ impl RequiredCiPhase { } } -const REQUIRED_CI_PHASES: [RequiredCiPhase; 5] = [ +const REQUIRED_CI_PHASES: [RequiredCiPhase; 6] = [ RequiredCiPhase::Parse, RequiredCiPhase::Regen, RequiredCiPhase::V2Emission, + RequiredCiPhase::EmitCompile, RequiredCiPhase::PartitionCrates, RequiredCiPhase::Floor, ]; diff --git a/src/v1/stage0/src/bootstrap_stage0_crate_layout_generated.rs b/src/v1/stage0/src/bootstrap_stage0_crate_layout_generated.rs index b2f6194d846..7ceb9e9b0cb 100644 --- a/src/v1/stage0/src/bootstrap_stage0_crate_layout_generated.rs +++ b/src/v1/stage0/src/bootstrap_stage0_crate_layout_generated.rs @@ -28,6 +28,7 @@ pub const HAND_MAINTAINED_STAGE0_FILES: &[&str] = &[ "cssl_seed_linked_closure_assembly.rs", "required_regen_host.rs", "partition_crate_boundary_host.rs", + "emitted_closure_compile_host.rs", "v2_compiler_compile.rs", "v2_compiler_program_assembly.rs", "v2_compiler_source_authority.rs", diff --git a/src/v1/stage0/src/cli_run.rs b/src/v1/stage0/src/cli_run.rs index 47cdc4c1730..64ed0b8096b 100644 --- a/src/v1/stage0/src/cli_run.rs +++ b/src/v1/stage0/src/cli_run.rs @@ -58,6 +58,9 @@ mod required_regen_host; #[path = "partition_crate_boundary_host.rs"] mod partition_crate_boundary_host; + +#[path = "emitted_closure_compile_host.rs"] +mod emitted_closure_compile_host; pub(crate) mod shared_fill; pub(crate) mod terminal_ledger_publish; pub(crate) mod test_module_hygiene_bridge; @@ -32446,6 +32449,20 @@ fn emit_source_root_entry_admission_data(admission: &SourceRootEntryAdmission) - ) } +/// The fnv1a64 digest of one NUL-delimited material string, rendered as `fnv1a64:`. +/// +/// Extracted from `source_root_ingest_content_hash_fnv1a64` rather than copied beside it: a second +/// site spelling out the same two constants would be one concept with two authorities, and the +/// two would then be free to disagree about a digest two carriers are expected to compare. +pub fn fnv1a64_digest_of_material(material: &str) -> String { + let mut hash = 0xcbf29ce484222325u64; + for byte in material.as_bytes() { + hash ^= u64::from(*byte); + hash = hash.wrapping_mul(0x100000001b3); + } + format!("fnv1a64:{hash:016x}") +} + pub fn source_root_ingest_content_hash_fnv1a64(records: &[SourceRootReadRecord]) -> String { let mut material = String::new(); for rec in records { @@ -32454,12 +32471,7 @@ pub fn source_root_ingest_content_hash_fnv1a64(records: &[SourceRootReadRecord]) material.push_str(&rec.source); material.push('\0'); } - let mut hash = 0xcbf29ce484222325u64; - for byte in material.as_bytes() { - hash ^= u64::from(*byte); - hash = hash.wrapping_mul(0x100000001b3); - } - format!("fnv1a64:{hash:016x}") + fnv1a64_digest_of_material(&material) } fn path_matches_any_subpath(path: &str, subpaths: &[String]) -> bool { @@ -48593,6 +48605,20 @@ pub use partition_crate_boundary_host::{ RenderedBoundaryFile, PARTITION_CRATE_PRODUCING_COMMAND, }; +/// The emitted-closure compile phase: one entry's closure emitted, written as a crate, and +/// compiled — with the discriminating red the phase establishes on itself every run. +/// +/// Re-exported here for the same reason the two above are: every required phase addresses its +/// producer through one surface. +pub use emitted_closure_compile_host::{ + cargo_verdict_stderr_tail, emit_compile_cover_denominator, emit_compile_modules_reached, + emit_compile_outcome_passed, emit_compile_outcome_summary, emit_compile_report, + emit_compile_selection, emit_compile_selection_not_selected_digest, + emit_compile_selection_selected_digest, emit_compile_selection_universe_digest, + required_emit_compile_entries, retain_not_selected_identities, run_required_emit_compile, + CargoVerdict, EmitCompileOutcome, EmitCompileSelection, MutationVerdict, +}; + /// The authority's own declared module path, for consumers outside this module. /// /// Exposed rather than re-implemented: a second parser for `module ` would be a second diff --git a/src/v1/stage0/src/emitted_closure_compile_host.rs b/src/v1/stage0/src/emitted_closure_compile_host.rs new file mode 100644 index 00000000000..770372e6d67 --- /dev/null +++ b/src/v1/stage0/src/emitted_closure_compile_host.rs @@ -0,0 +1,1073 @@ +//! Host realization for the required `emit-compile` phase: emit one entry's closure, +//! write it as a crate, and run cargo over it. +//! +//! WHY THIS MODULE EXISTS. DESIGN's Building-&-checks section carries a declared rung drop +//! headed "A BLOCKING EMIT-STAGE DIAGNOSTIC CAN SIT ON MAIN INDEFINITELY WITH NO REQUIRED +//! PHASE THAT FAILS", and its restoration trigger names a required phase that emits over a +//! closure and compiles it. The `v2-emission` phase beside this one emits and stops: its own +//! header says so in as many words -- what it does not catch is "a rustc error in the emitted +//! tree (nothing here compiles the emission)". This module is that missing conjunct, and it is +//! deliberately the SAME PRODUCER (`compile_entry_emission`), so a green there and a green here +//! cannot be two different facts about two different emissions. +//! +//! THE SUBJECT IS A CLOSURE, NOT A FILE. DESIGN's row measures its own specimen as reachable +//! from an entry whose closure INCLUDES the offending call site and unreachable from the file +//! that HOLDS it, and measures the holding module compiling clean in isolation. So a per-file +//! or per-module check answers a different question; the subject here is the emitted closure of +//! a declared entry, compiled whole. +//! +//! THE DISCRIMINATION IS EXECUTED, NOT ASSERTED. A phase that runs cargo and cannot go red is +//! worse than absent (DESIGN 4b): it gets cited as coverage. So every run of this phase +//! establishes its own red BY MUTATION rather than by inspection -- baseline green, then ONE +//! injected fault in ONE emitted file which must fail ALONE, then a byte-exact restore which +//! must return the tree to green. A run in which the mutated tree still compiles FAILS THE +//! PHASE, because at that point the cargo verdict is known to be insensitive to the bytes it +//! was handed and the green above it carries no information. The restore is as much of the +//! evidence as the failure is: without it, a red could be residue from the emission rather +//! than from the fault. A FAILED RESTORE IS TERMINAL FOR THE RUN and is not recoverable by +//! re-running the phase -- see `run_required_emit_compile`, which stops there and reports every +//! later entry as `NotExecuted` rather than measuring it through a target directory whose state +//! is no longer known. +//! +//! WHAT THIS PHASE IS NOT. It carries no baseline, no diagnostic count and no ratchet. Cargo's +//! own exit status is the whole verdict, and warnings are not errors here. Pinning a +//! diagnostic population measured on the current tree would be the tree-copied oracle DESIGN 5 +//! rejects; an identity-grain debt contract over the emitted population is a separate +//! construction with a separate argument. + +use std::path::{Path, PathBuf}; + +use super::{ + ci_layer_roots_authority_content, compile_entry_emission, process_workspace_root, + string_list_data_from_ci_layer_roots_source, CompileDisposition, CompileRun, +}; +use crate::extdeps_cargo::{CargoDepSource, CargoDependency}; +use crate::extdeps_cargo_version::render_cargo_package_header_prefix; +use crate::v1_compiler_stage0_crates::{ + render_stage0_crate_dep, stage0_foundation_runtime_dependencies, +}; + +const REQUIRED_EMIT_COMPILE_ENTRIES_DATA_NAME: &str = "required_emit_compile_entries"; + +/// The crate name the emitted closure is compiled under. One name for every entry: the crate +/// is rebuilt per entry in its own directory, so the name is a label rather than an identity. +const PROBE_PACKAGE_NAME: &str = "gunbc-emitted-closure"; + +/// THE INJECTED FAULT. A type error rather than a syntax error, deliberately: a syntax error +/// would also be caught by anything that merely parses the file, so it cannot discriminate a +/// cargo verdict from a cheaper reader. `E0308` requires rustc to have type-checked the +/// module, which is exactly the reach being claimed. The name is unique enough that it cannot +/// collide with emitted output, and the item is `pub` so no dead-code lint can elide it. +const MUTATION_ITEM: &str = + "\npub const EMIT_COMPILE_MUTATION_PROBE: u8 = \"the phase's own discriminating red\";\n"; + +/// The `.dag` entry paths whose emitted closure a required phase compiles, read live from +/// `gunbc.ci_layer_roots` `required_emit_compile_entries`. +/// +/// A `List` for the same reason the emission roster is one: the axis is WHICH ENTRIES, +/// so a second entry is a row and never a second host reader. +pub fn required_emit_compile_entries() -> Vec { + string_list_data_from_ci_layer_roots_source( + ci_layer_roots_authority_content(), + REQUIRED_EMIT_COMPILE_ENTRIES_DATA_NAME, + ) +} + +/// What cargo did, at the grain the phase can act on. +/// +/// The three arms are the ones `PartitionCompileOutcome` already separates in this seed, and +/// for the reason recorded there: a process killed without an exit status reports an empty +/// diagnostic population, which renders identically to a clean build unless the disposition +/// says otherwise. +#[derive(Debug, Clone)] +pub enum CargoVerdict { + /// The toolchain was never invoked. + NotAttempted { reason: String }, + /// Launched, and reached no exit status of its own -- killed, or the spawn failed. + DidNotComplete { detail: String }, + /// Ran to completion and reported its own exit status. + Completed { status: i32, stderr_tail: String }, +} + +/// Only a completed, zero-status run compiled. Every other arm -- including the one that never +/// launched -- is a refusal. +/// +/// FREE FUNCTIONS RATHER THAN `impl` METHODS, throughout this module, and it is deliberate: an +/// `impl` method has no `DeclarationRef` spelling (`std.decl_ref` offers `WholeDeclaration` or +/// `NamedField`, and neither names a method on an impl block), so every method would grow the +/// uncitable-item class `gunbc.seed_growth_admission` reports in +/// `seed_growth_uncitable_item_keys`. `v1_compiler.declaration_index` took the same route for +/// the same reason. +pub fn cargo_verdict_compiled(verdict: &CargoVerdict) -> bool { + matches!(verdict, CargoVerdict::Completed { status: 0, .. }) +} + +pub fn cargo_verdict_summary(verdict: &CargoVerdict) -> String { + match verdict { + CargoVerdict::NotAttempted { reason } => format!("NotAttempted reason={reason}"), + CargoVerdict::DidNotComplete { detail } => format!("DidNotComplete detail={detail}"), + CargoVerdict::Completed { status, .. } => format!("Completed status={status}"), + } +} + +pub fn cargo_verdict_stderr_tail(verdict: &CargoVerdict) -> &str { + match verdict { + CargoVerdict::Completed { stderr_tail, .. } => stderr_tail.as_str(), + _ => "", + } +} + +/// WHICH FILE THE FAULT WENT INTO, carried rather than inferred. +/// +/// A closure member is the stronger subject -- it establishes that the cargo verdict reaches +/// past the entry's own bytes into the closure the entry pulled in, which is the property +/// DESIGN's row turns on. `EntryModule` is the honest fallback for a closure whose only member +/// is the entry, and naming it means a reader can tell the weaker measurement from the stronger +/// one instead of assuming the stronger. +#[derive(Debug, Clone)] +pub enum MutationSubject { + ClosureMember { rust_module: String }, + EntryModule { rust_module: String }, +} + +pub fn mutation_subject_rust_module(subject: &MutationSubject) -> &str { + match subject { + MutationSubject::ClosureMember { rust_module } => rust_module.as_str(), + MutationSubject::EntryModule { rust_module } => rust_module.as_str(), + } +} + +pub fn mutation_subject_name(subject: &MutationSubject) -> &'static str { + match subject { + MutationSubject::ClosureMember { .. } => "ClosureMember", + MutationSubject::EntryModule { .. } => "EntryModule", + } +} + +/// WHETHER THIS RUN'S CARGO VERDICT IS SENSITIVE TO THE BYTES IT WAS HANDED. +/// +/// Only `Discriminated` is a pass. Every other arm says the baseline green above it carries no +/// information, which is a phase failure rather than a note -- the whole point of the arm is +/// that a decoration must not be able to report coverage. +#[derive(Debug, Clone)] +pub enum MutationVerdict { + /// No fault was injected. Carries why: a baseline that never went green has nothing to + /// discriminate against, and a tree with no writable module has nowhere to put the fault. + NotAttempted { reason: String }, + /// The fault went in and cargo still compiled the tree. THE INSTRUMENT IS NOT MEASURING + /// WHAT IT CLAIMS TO. + NotDiscriminating { detail: String }, + /// The fault produced a red, and the restore did not return the tree to the state it + /// started in -- either the bytes differ, or the restored tree does not compile. The red is + /// then unattributable: it may be residue rather than the fault. + RestoreFailed { detail: String }, + /// Red under the fault, green again after a byte-exact restore. + Discriminated { + subject: MutationSubject, + red_line: String, + }, +} + +pub fn mutation_verdict_discriminated(verdict: &MutationVerdict) -> bool { + matches!(verdict, MutationVerdict::Discriminated { .. }) +} + +pub fn mutation_verdict_summary(verdict: &MutationVerdict) -> String { + match verdict { + MutationVerdict::NotAttempted { reason } => format!("NotAttempted reason={reason}"), + MutationVerdict::NotDiscriminating { detail } => { + format!("NotDiscriminating detail={detail}") + } + MutationVerdict::RestoreFailed { detail } => format!("RestoreFailed detail={detail}"), + MutationVerdict::Discriminated { subject, red_line } => format!( + "Discriminated subject={} module={} red={red_line}", + mutation_subject_name(subject), + mutation_subject_rust_module(subject) + ), + } +} + +/// One entry's whole story, and every verdict is reached THROUGH the stage that produced it. +/// +/// `EmissionRefused` and `CrateNotWritten` have no cargo verdict to carry, so "cargo found +/// nothing wrong" and "cargo was never reached" cannot share a spelling -- the +/// execution-provenance-loss failure DESIGN names, which is exactly what a `passed: bool` +/// beside an optional cause would have reintroduced. +#[derive(Debug, Clone)] +pub enum EmitCompileOutcome { + /// The emission transaction did not complete. The emitted tree does not exist, so nothing + /// downstream ran. + EmissionRefused { + entry: String, + stage: String, + cause: String, + }, + /// Emission completed and the crate could not be laid out on disk. + CrateNotWritten { entry: String, cause: String }, + /// The entry was never reached, because an earlier entry's restore failed and a failed + /// restore is TERMINAL for the run. Carries the entry that ended it, so "not reached" can + /// never be read as "reached and clean". + NotExecuted { entry: String, cause: String }, + /// The crate exists and both arms ran. + Measured { + entry: String, + crate_dir: String, + emitted_files: usize, + baseline: CargoVerdict, + mutation: MutationVerdict, + }, +} + +/// A pass is a completed emission, a green baseline AND an executed discrimination. The third +/// conjunct is not decoration: without it the first two are satisfied by an instrument that +/// cannot fail. +pub fn emit_compile_outcome_passed(outcome: &EmitCompileOutcome) -> bool { + match outcome { + EmitCompileOutcome::Measured { + baseline, mutation, .. + } => cargo_verdict_compiled(baseline) && mutation_verdict_discriminated(mutation), + _ => false, + } +} + +pub fn emit_compile_outcome_summary(outcome: &EmitCompileOutcome) -> String { + match outcome { + EmitCompileOutcome::EmissionRefused { + entry, + stage, + cause, + } => { + format!("{entry} EmissionRefused stage={stage} cause={cause}") + } + EmitCompileOutcome::CrateNotWritten { entry, cause } => { + format!("{entry} CrateNotWritten cause={cause}") + } + EmitCompileOutcome::NotExecuted { entry, cause } => { + format!("{entry} NotExecuted cause={cause}") + } + EmitCompileOutcome::Measured { + entry, + crate_dir, + emitted_files, + baseline, + mutation, + } => format!( + "{entry} Measured files={emitted_files} crate={crate_dir} baseline=[{}] mutation=[{}]", + cargo_verdict_summary(baseline), + mutation_verdict_summary(mutation) + ), + } +} + +/// The manifest for the probe crate, rendered from the modeled cargo authorities rather than +/// authored as markup. +/// +/// The package header comes from `extdeps.rust.version` `render_cargo_package_header_prefix`, +/// the dependency rows from `v1.compiler.stage0_crates` +/// `stage0_foundation_runtime_dependencies` -- the seed's own runtime dependency set, which is +/// what emitted code links against -- and each row is rendered by that module's +/// `render_stage0_crate_dep`. No `[lib]` section is written because `src/lib.rs` is cargo's own +/// default library path, so naming it would be a second spelling of a fact cargo already owns. +/// +/// A hand-authored TOML string was available and is deliberately not used: the corpus already +/// carries one (`tools.self_host_curated_seed_linked_harness` +/// `cssl_v1_compiled_probe_lib_cargo_toml`), it is marked scaffold debt in its own module for +/// being concat-authored markup, and adding a required gate as a consumer of it would have +/// pinned that debt open on the merge path. +fn probe_manifest(workspace: &Path) -> String { + let mut deps: Vec = stage0_foundation_runtime_dependencies() + .iter() + .map(|dep| (**dep).clone()) + .collect(); + // The emitted closure links against the seed crate for the runtime surface it does not + // emit for itself (`v1_rt` and friends). A path dependency, absolute, because the probe + // crate is written outside the repository and a relative path would not resolve from it. + deps.push(CargoDependency { + name: "v1-compiler".to_string(), + source: std::rc::Rc::new(CargoDepSource::LocalPathDep { + path: workspace.join("src/v1/stage0").display().to_string(), + }), + }); + let rendered: String = deps + .into_iter() + .map(|dep| render_stage0_crate_dep(std::rc::Rc::new(dep))) + .collect::>() + .join(""); + format!( + "{}\nedition = \"2021\"\n\n[dependencies]\n{rendered}", + render_cargo_package_header_prefix(PROBE_PACKAGE_NAME.to_string()) + ) +} + +/// Where one entry's probe crate is written. Outside the repository deliberately: a crate under +/// the workspace root is inferred into the workspace by cargo and would have to declare its own +/// `[workspace]` to escape, which is a manifest fact invented to work around its own location. +fn probe_root() -> PathBuf { + std::env::temp_dir().join("gunbc-emit-compile") +} + +fn probe_crate_dir(entry: &str) -> PathBuf { + let slug: String = entry + .chars() + .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' }) + .collect(); + probe_root().join(slug) +} + +/// Write the emitted Rust files plus a manifest, and return the crate directory. +fn write_probe_crate(run: &CompileRun, entry: &str) -> Result<(PathBuf, usize), String> { + let emission = run + .emissions + .iter() + .find(|emission| emission.target_name == "rust") + .ok_or_else(|| "the emission carries no rust target".to_string())?; + let dir = probe_crate_dir(entry); + // A STALE TREE IS NOT A SUBJECT. The previous run's bytes under the same slug would let a + // module deleted from the closure keep compiling, so the directory is removed rather than + // written over. + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(dir.join("src")) + .map_err(|e| format!("creating {}: {e}", dir.display()))?; + let mut written = 0usize; + for file in emission.result.files.iter() { + let path = dir.join(&*file.path); + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent) + .map_err(|e| format!("creating {}: {e}", parent.display()))?; + } + std::fs::write(&path, &*file.content) + .map_err(|e| format!("writing {}: {e}", path.display()))?; + written += 1; + } + if !dir.join("src/lib.rs").is_file() { + return Err(format!( + "the emission wrote no src/lib.rs into {} — there is no crate root to compile", + dir.display() + )); + } + std::fs::write( + dir.join("Cargo.toml"), + probe_manifest(&process_workspace_root()), + ) + .map_err(|e| format!("writing the manifest into {}: {e}", dir.display()))?; + Ok((dir, written)) +} + +/// Run cargo over the probe crate. +/// +/// `build --release` INTO THE WORKSPACE TARGET DIRECTORY, and both halves are cost decisions +/// with one reason. The lane's own first step is `cargo build --release -p v1-compiler --bins`, +/// so the seed crate this probe depends on is already compiled there under exactly that +/// profile; a `check`, or a private target directory, would share no fingerprint with it and +/// would rebuild the whole dependency graph inside a required phase. Sharing it means the +/// baseline arm compiles the emitted crate and nothing else, and the two further arms are +/// incremental on top of that. +/// +/// The phases inside one required run are sequential in one process, so nothing else is holding +/// cargo's lock on that directory while this runs. +fn run_cargo(crate_dir: &Path, workspace: &Path) -> CargoVerdict { + let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".to_string()); + let mut command = std::process::Command::new(&cargo); + command + .arg("build") + .arg("--release") + .arg("--manifest-path") + .arg(crate_dir.join("Cargo.toml")) + .env("CARGO_TARGET_DIR", workspace.join("target")) + .current_dir(crate_dir); + match command.output() { + Err(e) => CargoVerdict::DidNotComplete { + detail: format!("spawning {cargo} failed: {e}"), + }, + Ok(output) => match output.status.code() { + None => CargoVerdict::DidNotComplete { + detail: format!("{cargo} terminated by signal without an exit status"), + }, + Some(status) => { + let stderr = String::from_utf8_lossy(&output.stderr); + let tail: Vec<&str> = stderr.lines().rev().take(20).collect(); + CargoVerdict::Completed { + status, + stderr_tail: tail.into_iter().rev().collect::>().join("\n"), + } + } + }, + } +} + +/// The rust module basenames the emitted `lib.rs` declares, in its own order. +fn closure_modules(lib_rs: &Path) -> Vec { + let Ok(content) = std::fs::read_to_string(lib_rs) else { + return Vec::new(); + }; + content + .lines() + .filter_map(|line| { + line.trim() + .strip_prefix("pub mod ") + .and_then(|rest| rest.strip_suffix(';')) + .map(|m| m.trim().to_string()) + }) + .collect() +} + +/// Pick the file the fault goes into: a closure member other than the entry where one exists, +/// the entry itself otherwise. +fn mutation_subject(crate_dir: &Path, entry_module: &str) -> Option { + let modules = closure_modules(&crate_dir.join("src/lib.rs")); + if let Some(member) = modules + .iter() + .find(|m| m.as_str() != entry_module && crate_dir.join(format!("src/{m}.rs")).is_file()) + { + return Some(MutationSubject::ClosureMember { + rust_module: member.clone(), + }); + } + if crate_dir.join(format!("src/{entry_module}.rs")).is_file() { + return Some(MutationSubject::EntryModule { + rust_module: entry_module.to_string(), + }); + } + None +} + +/// THE DISCRIMINATING RED, ESTABLISHED BY MUTATION AND RESTORED BEFORE THE PHASE REPORTS. +/// +/// One fault, in one file, failing alone -- the baseline immediately above it is the control, +/// and the restore immediately after it is the second control. A round in which several things +/// change at once would establish that cargo responds to damage, not that this instrument reads +/// this closure. +fn establish_discriminating_red( + crate_dir: &Path, + workspace: &Path, + entry_module: &str, +) -> MutationVerdict { + let Some(subject) = mutation_subject(crate_dir, entry_module) else { + return MutationVerdict::NotAttempted { + reason: format!( + "no writable emitted module under {} to carry the fault", + crate_dir.display() + ), + }; + }; + let path = crate_dir.join(format!("src/{}.rs", mutation_subject_rust_module(&subject))); + let original = match std::fs::read_to_string(&path) { + Ok(bytes) => bytes, + Err(e) => { + return MutationVerdict::NotAttempted { + reason: format!("reading {}: {e}", path.display()), + } + } + }; + let mutated = format!("{original}{MUTATION_ITEM}"); + if let Err(e) = std::fs::write(&path, &mutated) { + return MutationVerdict::NotAttempted { + reason: format!("writing the fault into {}: {e}", path.display()), + }; + } + + let red = run_cargo(crate_dir, workspace); + + // THE RESTORE RUNS WHATEVER THE FAULTED ARM ANSWERED. Leaving a faulted tree behind would + // make the next run's baseline red for a reason that has nothing to do with the corpus. + let restore_write = std::fs::write(&path, &original); + let restored_bytes = std::fs::read_to_string(&path).unwrap_or_default(); + + if cargo_verdict_compiled(&red) { + return MutationVerdict::NotDiscriminating { + detail: format!( + "cargo compiled {} with a deliberate type error appended to src/{}.rs — \ + the verdict is not a function of the emitted bytes, so the green baseline \ + beside it carries no information", + crate_dir.display(), + mutation_subject_rust_module(&subject) + ), + }; + } + + if let Err(e) = restore_write { + return MutationVerdict::RestoreFailed { + detail: format!("restoring {}: {e}", path.display()), + }; + } + if restored_bytes != original { + return MutationVerdict::RestoreFailed { + detail: format!( + "{} did not return to its emitted bytes after the fault was removed", + path.display() + ), + }; + } + let restored = run_cargo(crate_dir, workspace); + if !cargo_verdict_compiled(&restored) { + return MutationVerdict::RestoreFailed { + detail: format!( + "the restored tree does not compile ({}) — the red above it cannot be \ + attributed to the injected fault", + cargo_verdict_summary(&restored) + ), + }; + } + + let red_tail = cargo_verdict_stderr_tail(&red); + let red_line = red_tail + .lines() + .find(|line| line.contains("error[")) + .unwrap_or_else(|| red_tail.lines().next().unwrap_or("")) + .trim() + .to_string(); + MutationVerdict::Discriminated { subject, red_line } +} + +/// The rust module basename an entry `.dag` file emits under, from its own `module` line. +fn entry_rust_module(entry: &str, workspace: &Path) -> Result { + let path = workspace.join(entry); + let content = std::fs::read_to_string(&path) + .map_err(|e| format!("reading the entry {}: {e}", path.display()))?; + content + .lines() + .find(|line| line.starts_with("module ")) + .map(|line| line.trim_start_matches("module ").trim().replace('.', "_")) + .ok_or_else(|| format!("the entry {entry} declares no module line")) +} + +/// One entry, end to end. +pub fn run_emit_compile_entry(source_roots: &[String], entry: &str) -> EmitCompileOutcome { + // PROGRESS IS REPORTED AS THE STAGE IS ENTERED, NOT WHEN THE ENTRY FINISHES. + // + // This is not decoration. Every stage below is a long host effect -- a whole-index emission, + // then up to three cargo invocations -- and a phase that reports only on completion renders a + // HANG and a KILL identically to a reader, and both identically to a slow run. That is the + // execution-provenance loss DESIGN names, arriving in the instrument's own output: measured + // the hard way, when two verification runs died inside this function and produced no line at + // all, so nothing in the log distinguished "still emitting" from "killed". + eprintln!("emit-compile: {entry} emitting"); + let workspace = process_workspace_root(); + let run = compile_entry_emission( + source_roots, + entry, + true, + crate::v1_compiler_artifact::RenderTarget::Rust, + ); + match &run.disposition { + CompileDisposition::Refused { phase, cause } => { + return EmitCompileOutcome::EmissionRefused { + entry: entry.to_string(), + stage: phase.clone(), + cause: cause.clone(), + } + } + CompileDisposition::NotExecuted { + earlier_phase, + cause, + } => { + return EmitCompileOutcome::EmissionRefused { + entry: entry.to_string(), + stage: earlier_phase.clone(), + cause: cause.clone(), + } + } + CompileDisposition::Completed { .. } => {} + } + + let (crate_dir, emitted_files) = match write_probe_crate(&run, entry) { + Ok(pair) => pair, + Err(cause) => { + return EmitCompileOutcome::CrateNotWritten { + entry: entry.to_string(), + cause, + } + } + }; + let entry_module = match entry_rust_module(entry, &workspace) { + Ok(module) => module, + Err(cause) => { + return EmitCompileOutcome::CrateNotWritten { + entry: entry.to_string(), + cause, + } + } + }; + + eprintln!( + "emit-compile: {entry} emitted {emitted_files} file(s) into {} — cargo baseline", + crate_dir.display() + ); + let baseline = run_cargo(&crate_dir, &workspace); + eprintln!( + "emit-compile: {entry} baseline {} — mutation", + cargo_verdict_summary(&baseline) + ); + // THE DISCRIMINATION IS NOT ATTEMPTED OVER A RED BASELINE, and it says so rather than + // reporting a red it cannot attribute: a tree that already fails would go red under the + // fault for a reason the fault did not cause, which is a green control wearing a red one's + // clothes. + let mutation = if cargo_verdict_compiled(&baseline) { + establish_discriminating_red(&crate_dir, &workspace, &entry_module) + } else { + MutationVerdict::NotAttempted { + reason: format!( + "the baseline did not compile ({}) — a fault injected into a failing tree \ + discriminates nothing", + cargo_verdict_summary(&baseline) + ), + } + }; + + EmitCompileOutcome::Measured { + entry: entry.to_string(), + crate_dir: crate_dir.display().to_string(), + emitted_files, + baseline, + mutation, + } +} + +/// Every configured entry, each run whatever the previous one did -- the stopped-line audit +/// shape the required run already uses: report everything, green nothing. +/// +/// AN EMPTY ROSTER REFUSES. Zero entries compiled is not zero breaks; it is the phase failing +/// to reach any subject, and reporting it as clean is the empty-observation narrow. +/// THE DENOMINATOR THE COVER IS A FRACTION OF — authored `.dag` modules under the source roots +/// the phase was invoked with. +/// +/// WHY THE PHASE REPORTS THIS AND NOT ONLY ITS OWN COUNT. A required check named for compiling +/// emitted closures that compiles a small declared cover and prints only `declared=8 passed=8` +/// reads, to anyone scanning a log, as a statement about the tree. It is not: it is a statement +/// about eight entries. DESIGN's own record of this shape is the compile-clean witness family — +/// nine identities named for compile-clean, one of which passes, and that one checks whether two +/// realizations agree about a policy row. A reader counting those nine concluded the corpus was +/// compile-checked. Printing the denominator beside the cover is what makes that misreading +/// unavailable from the output itself, rather than available to anyone who does not go and read +/// the roster. +/// +/// It counts modules rather than admissible entries deliberately: an admissible-entry denominator +/// would be a second measurement that moves for reasons unrelated to coverage (an emitter repair +/// clearing a widely-reached site returns many entries at once), and a coverage fraction whose +/// denominator moves under repairs is not a coverage fraction. Authored modules is the stable +/// subject the corpus actually has. +fn authored_dag_module_count(source_roots: &[String]) -> usize { + let mut files = Vec::new(); + for root in source_roots { + super::collect_dag_files_tolerant(std::path::Path::new(root), &mut files); + } + files.sort(); + files.dedup(); + files.len() +} + +/// The cover fraction, rendered for the phase's summary line. +pub fn emit_compile_cover_denominator(source_roots: &[String]) -> usize { + authored_dag_module_count(source_roots) +} + +/// THE NUMERATOR, IN THE SAME UNIT AS THE DENOMINATOR: modules the cover's closures REACHED. +/// +/// WHY NOT THE ENTRY COUNT. `covered_entries=8 of 3900 authored modules` is not a fraction — the +/// numerator is entries and the denominator is modules — and it reads as a coverage ratio +/// precisely because it is formatted like one. It understates by a wide and unknown margin, since +/// eight closures reach far more than eight modules, and understating is not the safe direction: +/// a number that looks that bad invites growing the entry roster, which is exactly the move the +/// retirement trigger forbids (a trigger satisfied at forty-one entries leaves the corpus +/// unmeasured). An unpaired count tells no lie; a mismatched fraction does. +/// +/// This is the union of the emitted module sets, read from the crates the phase already wrote, so +/// it costs a readdir per entry and no extra compilation. It moves for the right reason: up when +/// the cover reaches new code, unchanged when an unrelated emitter repair lands. +/// +/// WHAT IT DOES NOT DISTINGUISH, said here rather than left for a reader to assume: reached AS AN +/// ENTRY and reached ONLY AS A DEPENDENCY are both counted. The second is real coverage of a +/// weaker kind — a dependency module is compiled, but no run ever emits from its own closure, so +/// an emit-stage diagnostic reachable only from ITS entry is still invisible. Splitting the two +/// numerators is strictly better and is not done here. +pub fn emit_compile_modules_reached(outcomes: &[EmitCompileOutcome]) -> usize { + // `src/lib.rs` IS NOT DEDUPLICABLE BY NAME, AND UNIONING IT WOULD UNDER-COUNT. + // The emission writes each entry's own root module as `lib.rs` — the compiler refuses the + // crate outright without one — so every entry contributes a DIFFERENT root under the SAME + // file name. Unioning names would collapse N distinct roots into one, which is a numerator + // that shrinks as the cover grows. The roots are therefore counted per measured entry and + // the dependency modules unioned by name, which is what "reached" means. + let mut reached: Vec = Vec::new(); + let mut roots = 0usize; + for outcome in outcomes { + if let EmitCompileOutcome::Measured { crate_dir, .. } = outcome { + let src = std::path::Path::new(crate_dir).join("src"); + if let Ok(entries) = std::fs::read_dir(&src) { + roots += 1; + for entry in entries.flatten() { + if let Some(name) = entry.file_name().to_str() { + if name == "lib.rs" { + continue; + } + reached.push(name.to_string()); + } + } + } + } + } + reached.sort(); + reached.dedup(); + reached.len() + roots +} + +/// THE SELECTION, WITH ITS REMAINDER CARRIED AT IDENTITY GRAIN. +/// +/// WHY THIS REPLACES THE COVERAGE FRACTION RATHER THAN JOINING IT. A fraction — however +/// unit-consistent — is the wrong instrument for an uncovered remainder, because §4b(3) asks a +/// rung drop for a BOUNDED POPULATION and a percentage is not one: it says how much is missing +/// and never WHICH, so nothing downstream can join it, refuse on it, or watch it shrink. The +/// identities are the population. A percentage may stand as context and may never be the gap's +/// identity or its dissolution trigger. +/// +/// The universe is authored `.dag` modules under the invoked source roots; the selection is the +/// declared roster; the remainder is the set difference, RETAINED — written to a file beside the +/// run and digested, so the phase's own output names where the unselected identities are rather +/// than summarising them away. Counts and digests are printed; the identities are persisted. +pub struct EmitCompileSelection { + pub universe: Vec, + pub selected: Vec, + pub not_selected: Vec, +} + +fn digest_of_identities(identities: &[String]) -> String { + let mut material = String::new(); + for identity in identities { + material.push_str(identity); + material.push('\0'); + } + super::fnv1a64_digest_of_material(&material) +} + +pub fn emit_compile_selection(source_roots: &[String]) -> EmitCompileSelection { + let mut universe: Vec = Vec::new(); + for root in source_roots { + let mut files = Vec::new(); + super::collect_dag_files_tolerant(std::path::Path::new(root), &mut files); + for file in files { + universe.push(file.to_string_lossy().to_string()); + } + } + universe.sort(); + universe.dedup(); + + let mut selected = required_emit_compile_entries(); + selected.sort(); + selected.dedup(); + + // THE SELECTION IS NOT ASSUMED TO BE A SUBSET, IT IS INTERSECTED. A roster row naming a path + // the walk does not find is a defect worth seeing rather than a silent membership; it shows + // up here as a selected identity absent from the universe, and the remainder stays exact. + let not_selected: Vec = universe + .iter() + .filter(|module| !selected.contains(module)) + .cloned() + .collect(); + + EmitCompileSelection { + universe, + selected, + not_selected, + } +} + +pub fn emit_compile_selection_universe_digest(selection: &EmitCompileSelection) -> String { + digest_of_identities(&selection.universe) +} + +pub fn emit_compile_selection_selected_digest(selection: &EmitCompileSelection) -> String { + digest_of_identities(&selection.selected) +} + +pub fn emit_compile_selection_not_selected_digest(selection: &EmitCompileSelection) -> String { + digest_of_identities(&selection.not_selected) +} + +/// Persist the unselected identities beside the run. RETAINED means retained: the phase writes +/// the list rather than reporting its size, so the remainder is a population a later operation can +/// read, and not a number a later reader must trust. +pub fn retain_not_selected_identities( + selection: &EmitCompileSelection, + dir: &str, +) -> Result { + let path = std::path::Path::new(dir).join("emit-compile-not-selected.txt"); + let mut body = String::new(); + for identity in &selection.not_selected { + body.push_str(identity); + body.push('\n'); + } + std::fs::create_dir_all(dir) + .map_err(|e| format!("could not create {dir} to retain the remainder: {e}"))?; + std::fs::write(&path, body) + .map_err(|e| format!("could not retain the unselected identities at {path:?}: {e}"))?; + Ok(path.to_string_lossy().to_string()) +} + +/// THE ONE REPORT BOTH SURFACES PRINT. +/// +/// The required phase and the standalone `--required-emit-compile` mode are two callers of one +/// producer, and a report authored twice is one fact with two authorities — free to disagree about +/// exactly the numbers a reader compares across the two surfaces. So the selection, the remainder +/// and the context line are rendered here, once, and each caller prints what it is given. +/// +/// Retention is attempted here and its failure is RETURNED rather than swallowed, because the +/// remainder is the declared population of what this phase does not observe: a run reporting a +/// remainder it could not persist has published a count with nothing behind it. +pub fn emit_compile_report( + outcomes: &[EmitCompileOutcome], + source_roots: &[String], + prefix: &str, +) -> (Vec, Option) { + let selection = emit_compile_selection(source_roots); + let mut lines = Vec::new(); + lines.push(format!( + "{prefix} selection: universe={} {} selected={} {} not_selected={} {}", + selection.universe.len(), + emit_compile_selection_universe_digest(&selection), + selection.selected.len(), + emit_compile_selection_selected_digest(&selection), + selection.not_selected.len(), + emit_compile_selection_not_selected_digest(&selection), + )); + let retained_dir = std::env::temp_dir() + .join("gunbc-emit-compile") + .to_string_lossy() + .to_string(); + let retention_error = match retain_not_selected_identities(&selection, &retained_dir) { + Ok(path) => { + lines.push(format!( + "{prefix} remainder retained at {path} (unselected identities, one per line)" + )); + None + } + Err(err) => { + lines.push(format!("{prefix} FAILED to retain remainder: {err}")); + Some(err) + } + }; + // Context only, after the identities and never in place of them. + lines.push(format!( + "{prefix} context: {} declared entries reach {} modules (dependencies included; they are \ + compiled but never emitted from)", + outcomes.len(), + emit_compile_modules_reached(outcomes) + )); + (lines, retention_error) +} + +/// TWO CONCURRENT RUNS IN ONE WORKSPACE CORRUPT EACH OTHER'S EVIDENCE, SO THE SECOND REFUSES. +/// +/// The arms deliberately share one probe root and one cargo target directory — that is what makes +/// the baseline warm and the restore comparable. It also means two runs interleave: one run's +/// faulted tree is the other run's baseline, and one run's restore erases the other's red before +/// it is read. Neither process observes anything wrong; both report confidently. +/// +/// MEASURED, NOT ANTICIPATED. Verifying the blunted-mutation arm, a stale background invocation +/// overlapped a foreground one. The phase reported `Discriminated` with a red line quoting a +/// `#[cfg]` WARNING, over a cargo run whose own tail said `Finished` — a green compile reported as +/// a discriminating red. The arm that exists to catch a non-discriminating verdict was itself +/// given a fabricated one. A clean re-run answered `NotDiscriminating` correctly. +/// +/// The refusal is a lock file created exclusively, NOT a wait and NOT a private directory per run. +/// Waiting would serialize into the same shared state with the same ambiguity about whose +/// artifacts are whose; a private directory would buy isolation by throwing away the warm target +/// dir the phase is built around. Refusing is the fail-closed arm: the line stops, the cause is +/// typed and located, and the operator sees that two runs were attempted rather than receiving a +/// verdict computed across both. +fn acquire_probe_root_lock(root: &Path) -> Result { + std::fs::create_dir_all(root) + .map_err(|e| format!("could not create the probe root {}: {e}", root.display()))?; + let lock = root.join("emit-compile.lock"); + match std::fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(&lock) + { + Ok(_) => Ok(lock), + Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => Err(format!( + "another emitted-closure compile run holds {} — two runs sharing one probe root \ + interleave their faulted and restored trees, so neither verdict is attributable. \ + Remove the lock only after establishing no other run is live.", + lock.display() + )), + Err(e) => Err(format!("could not take {}: {e}", lock.display())), + } +} + +pub fn run_required_emit_compile( + source_roots: &[String], +) -> Result, String> { + let entries = required_emit_compile_entries(); + if entries.is_empty() { + return Err( + "gunbc.ci_layer_roots required_emit_compile_entries is empty — the phase has no subject" + .to_string(), + ); + } + // See `acquire_probe_root_lock`: a second concurrent run refuses rather than interleaving. + let lock = acquire_probe_root_lock(&probe_root())?; + // A FAILED RESTORE ENDS THE RUN, and it is not merely reported per entry. + // + // WHY IT IS TERMINAL RATHER THAN A FINDING SIBLINGS CONTINUE PAST, which is the shape every + // other refusal here takes: the arms share ONE cargo target directory, so after a restore + // fails the tree that directory holds is unknown -- it may carry artifacts of a faulted + // crate. Every later entry's baseline is then unattributable, and reporting those baselines + // would be the execution-provenance loss this module exists to refuse, one level out. + // + // AND IT MUST NOT BE PAPERABLE OVER BY A RE-RUN. A re-run re-emits from scratch, so a + // transient restore failure simply vanishes and the phase greens -- at which point the + // byte-exact restore has stopped being evidence and has become a flaky step people re-run. + // Ending the run means the head that produced it has NO green from this phase at all, rather + // than a green whose restore arm was never established. + let mut outcomes = Vec::new(); + for entry in &entries { + let outcome = run_emit_compile_entry(source_roots, entry); + let terminal = matches!( + &outcome, + EmitCompileOutcome::Measured { + mutation: MutationVerdict::RestoreFailed { .. }, + .. + } + ); + outcomes.push(outcome); + if terminal { + let ended_at = entry.clone(); + for remaining in entries.iter().skip(outcomes.len()) { + outcomes.push(EmitCompileOutcome::NotExecuted { + entry: remaining.clone(), + cause: format!( + "the run ended at {ended_at}: a failed restore is terminal, because the \ + shared cargo target directory is in an unknown state and no later \ + baseline taken through it would be attributable" + ), + }); + } + break; + } + } + // The lock is released on the success path only. A run that returned early left the probe + // root in a state no later run should silently build on, and the stale lock is the signal. + let _ = std::fs::remove_file(&lock); + Ok(outcomes) +} + +/// THESE ARE LOCAL-ONLY EVIDENCE AND ARE LABELLED AS SUCH. The Rust suite was removed from CI +/// on 2026-07-11 (DESIGN, Building & checks), so nothing here executes on the merge path and +/// none of it may be cited as coverage. THE EXECUTED EVIDENCE FOR THIS PHASE IS THE PHASE +/// ITSELF: `establish_discriminating_red` runs on every required run, and a mutation that fails +/// to go red stops the line. What these add is the discrimination the in-run arm cannot perform +/// on itself -- that a non-`Discriminated` mutation is a FAILURE rather than a note, and that +/// the fault prefers a closure member over the entry. +#[cfg(test)] +mod tests { + use super::*; + + /// The manifest is DERIVED, so this asserts the derivation reached the modeled rows rather + /// than asserting a golden string: a package header from the version authority, the seed's + /// runtime dependency set, and the path dependency the emitted closure links against. + #[test] + fn manifest_carries_the_modeled_dependency_rows() { + let manifest = probe_manifest(Path::new("/repo")); + assert!(manifest.starts_with("[package]\nname = \"gunbc-emitted-closure\"")); + assert!(manifest.contains("edition = \"2021\"")); + for name in ["im", "serde", "serde_json", "stacker"] { + assert!(manifest.contains(name), "missing dependency row {name}"); + } + assert!(manifest.contains("/repo/src/v1/stage0")); + // `src/lib.rs` is cargo's own default, so restating it would be a second spelling. + assert!(!manifest.contains("[lib]")); + } + + /// A closure member is preferred over the entry, because it is the stronger subject. + #[test] + fn mutation_prefers_a_closure_member_over_the_entry() { + let dir = std::env::temp_dir().join(format!("emit_compile_subject_{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(dir.join("src")).expect("src"); + std::fs::write( + dir.join("src/lib.rs"), + "pub mod std_logic;\npub mod v2_std_node;\n", + ) + .expect("lib"); + std::fs::write(dir.join("src/std_logic.rs"), "// member\n").expect("member"); + std::fs::write(dir.join("src/v2_std_node.rs"), "// entry\n").expect("entry"); + let subject = mutation_subject(&dir, "v2_std_node").expect("a subject"); + assert!(matches!(subject, MutationSubject::ClosureMember { .. })); + assert_eq!(mutation_subject_rust_module(&subject), "std_logic"); + let _ = std::fs::remove_dir_all(&dir); + } + + /// A closure whose only member is the entry falls back to the entry AND SAYS SO, so the + /// weaker measurement is legible as the weaker one. + #[test] + fn mutation_falls_back_to_the_entry_and_names_it() { + let dir = std::env::temp_dir().join(format!("emit_compile_solo_{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(dir.join("src")).expect("src"); + std::fs::write(dir.join("src/lib.rs"), "pub mod v2_std_node;\n").expect("lib"); + std::fs::write(dir.join("src/v2_std_node.rs"), "// entry\n").expect("entry"); + let subject = mutation_subject(&dir, "v2_std_node").expect("a subject"); + assert!(matches!(subject, MutationSubject::EntryModule { .. })); + let _ = std::fs::remove_dir_all(&dir); + } + + /// AN ENTRY THE RUN NEVER REACHED IS NOT A PASS. The terminal-restore arm exists precisely + /// so that "not reached" has a spelling of its own; if it could pass, ending the run early + /// would silently green every entry after the failure. + #[test] + fn an_unreached_entry_is_not_a_pass() { + assert!(!emit_compile_outcome_passed( + &EmitCompileOutcome::NotExecuted { + entry: "e.dag".to_string(), + cause: "the run ended earlier".to_string(), + } + )); + } + + /// EVERY NON-`Discriminated` MUTATION ARM FAILS THE PHASE. Stated as a test because the + /// tempting weakening -- treating the mutation as advisory beside a green baseline -- is + /// exactly what would turn this phase into the decoration it exists not to be. + #[test] + fn a_green_baseline_does_not_pass_without_the_discrimination() { + let green = CargoVerdict::Completed { + status: 0, + stderr_tail: String::new(), + }; + for mutation in [ + MutationVerdict::NotAttempted { + reason: "r".to_string(), + }, + MutationVerdict::NotDiscriminating { + detail: "d".to_string(), + }, + MutationVerdict::RestoreFailed { + detail: "d".to_string(), + }, + ] { + let outcome = EmitCompileOutcome::Measured { + entry: "e.dag".to_string(), + crate_dir: "/tmp/x".to_string(), + emitted_files: 1, + baseline: green.clone(), + mutation, + }; + assert!( + !emit_compile_outcome_passed(&outcome), + "{}", + emit_compile_outcome_summary(&outcome) + ); + } + let discriminated = EmitCompileOutcome::Measured { + entry: "e.dag".to_string(), + crate_dir: "/tmp/x".to_string(), + emitted_files: 1, + baseline: green, + mutation: MutationVerdict::Discriminated { + subject: MutationSubject::ClosureMember { + rust_module: "std_logic".to_string(), + }, + red_line: "error[E0308]".to_string(), + }, + }; + assert!(emit_compile_outcome_passed(&discriminated)); + } +} diff --git a/src/v1/stage0/src/gunbc_stage0_crate_layout_generated.rs b/src/v1/stage0/src/gunbc_stage0_crate_layout_generated.rs index 0d1913aa098..986b1a8b799 100644 --- a/src/v1/stage0/src/gunbc_stage0_crate_layout_generated.rs +++ b/src/v1/stage0/src/gunbc_stage0_crate_layout_generated.rs @@ -39,7 +39,7 @@ pub fn generated_pub_mod_basenames() -> Rc> { pub fn generated_stage0_filenames() -> Rc> { thread_local! { static CACHED: Rc> = { - Rc::new(vec!["v1_interpreter.rs".to_string(), "bounded_shell_host_drain.rs".to_string(), "cli_run.rs".to_string(), "codex_app_server_stdio_session.rs".to_string(), "coproduct_reflection.rs".to_string(), "data_initializer_identity.rs".to_string(), "declaration_index.rs".to_string(), "resolved_graph_cache.rs".to_string(), "shared_typecheck_store.rs".to_string(), "recorded_fixture.rs".to_string(), "phase_profile.rs".to_string(), "pre_push.rs".to_string(), "census_exclude_derive.rs".to_string(), "derived_realization_schedule.rs".to_string(), "memory_governor.rs".to_string(), "std_lens_verdict.rs".to_string(), "v2_compiler_body_producer.rs".to_string(), "v2_compiler_normalize.rs".to_string(), "v2_compiler_target_carriers.rs".to_string(), "v2_compiler_discovery_enumeration.rs".to_string(), "v2_compiler_parse_engine_hooks.rs".to_string(), "v2_compiler_use_site_verdict.rs".to_string(), "cssl_seed_linked_closure_assembly.rs".to_string(), "required_regen_host.rs".to_string(), "partition_crate_boundary_host.rs".to_string(), "v2_compiler_compile.rs".to_string(), "v2_compiler_program_assembly.rs".to_string(), "v2_compiler_source_authority.rs".to_string(), "usv_pilot_v2_std_algebra.rs".to_string(), "usv_pilot_v2_std_collection.rs".to_string(), "usv_pilot_v2_std_node.rs".to_string(), "v2_compiler_resolve.rs".to_string(), "v2_compiler_program_partition.rs".to_string(), "v2_compiler_tokenize.rs".to_string(), "v2_compiler_infer.rs".to_string(), "bootstrap_stage0_crate_layout_generated.rs".to_string(), "v1_interpreter_dispatch_generated.rs".to_string(), "main.rs".to_string()]) + Rc::new(vec!["v1_interpreter.rs".to_string(), "bounded_shell_host_drain.rs".to_string(), "cli_run.rs".to_string(), "codex_app_server_stdio_session.rs".to_string(), "coproduct_reflection.rs".to_string(), "data_initializer_identity.rs".to_string(), "declaration_index.rs".to_string(), "resolved_graph_cache.rs".to_string(), "shared_typecheck_store.rs".to_string(), "recorded_fixture.rs".to_string(), "phase_profile.rs".to_string(), "pre_push.rs".to_string(), "census_exclude_derive.rs".to_string(), "derived_realization_schedule.rs".to_string(), "memory_governor.rs".to_string(), "std_lens_verdict.rs".to_string(), "v2_compiler_body_producer.rs".to_string(), "v2_compiler_normalize.rs".to_string(), "v2_compiler_target_carriers.rs".to_string(), "v2_compiler_discovery_enumeration.rs".to_string(), "v2_compiler_parse_engine_hooks.rs".to_string(), "v2_compiler_use_site_verdict.rs".to_string(), "cssl_seed_linked_closure_assembly.rs".to_string(), "required_regen_host.rs".to_string(), "partition_crate_boundary_host.rs".to_string(), "emitted_closure_compile_host.rs".to_string(), "v2_compiler_compile.rs".to_string(), "v2_compiler_program_assembly.rs".to_string(), "v2_compiler_source_authority.rs".to_string(), "usv_pilot_v2_std_algebra.rs".to_string(), "usv_pilot_v2_std_collection.rs".to_string(), "usv_pilot_v2_std_node.rs".to_string(), "v2_compiler_resolve.rs".to_string(), "v2_compiler_program_partition.rs".to_string(), "v2_compiler_tokenize.rs".to_string(), "v2_compiler_infer.rs".to_string(), "bootstrap_stage0_crate_layout_generated.rs".to_string(), "v1_interpreter_dispatch_generated.rs".to_string(), "main.rs".to_string()]) }; } CACHED.with(|c: &Rc>| c.clone()) diff --git a/src/v2/compiler/self_host/stage0_crate_layout.dag b/src/v2/compiler/self_host/stage0_crate_layout.dag index 729286dbbf8..5156020e0f4 100644 --- a/src/v2/compiler/self_host/stage0_crate_layout.dag +++ b/src/v2/compiler/self_host/stage0_crate_layout.dag @@ -94,6 +94,7 @@ data seed_retained_intrinsic_registrations: List Date: Thu, 27 Aug 2026 05:00:12 +0000 Subject: [PATCH 2/9] Move the DESIGN edits into their authority DESIGN.md is a generated artifact (gunbc.generated_artifact DesignArtifact, .gitattributes merge=generated-artifact); its prose lives in gunbc.design_document. Editing the artifact leaves the authority untouched, so the next regen re-derives DESIGN.md and silently drops the edit -- and the generated-artifact drift gates are on DESIGN's own unguarded list from the floor cut, so no required run refuses it. Co-Authored-By: Claude Opus 5 (1M context) --- dag/gunbc/design_document.dag | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dag/gunbc/design_document.dag b/dag/gunbc/design_document.dag index 1835f1aafce..47064ccb693 100644 --- a/dag/gunbc/design_document.dag +++ b/dag/gunbc/design_document.dag @@ -180,11 +180,11 @@ fn building_checks_blocks() -> List { li(text: "`cargo test --workspace` · `cargo clippy --all-targets -- -D warnings` · `cargo fmt --all --check`"), li(text: "one-time per clone: `git config core.hooksPath .githooks` — the only documented manual seed; generated pre-commit/pre-push hooks then idempotently converge `merge.generated-artifact.driver` and re-assert `core.hooksPath` via argv derived from `gunbc.repo_local_git_config` (clones that skip hooksPath degrade to vanilla text-merge for generated-artifact paths; drift gate still guards at CI). The driver REFUSES rather than answering `true`: git reaches a low-level merge driver only when both sides changed the path since the merge base — measured on a four-case matrix, one-sided and identical changes never reach it — and taking the ours side there dropped the other side's authority-derived bytes with no conflict, twice on #7836 against the stage0 seed. It now leaves the ours side in the worktree with no conflict markers, marks the path unmerged, and prints the regeneration recipe; the class is mechanically preventable, not structural, and its next-rung trigger is the commit-writer binding rows in `gunbc.commit_workflow`"), li(text: "explicit actuator (CI / tooling): `gunbc run --source-root dag --source-root src/v2 --entry dag/gunbc/repo_local_git_config.dag --function converge`"), - li(text: "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 `v2.workflow.required_floor` `run_required_floor`. 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, 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 and the v2-emission compile) 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. 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.** 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. 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`, `--behavioral-receipt-plan`, `--behavioral-receipt-selftest`, `--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."), + li(text: "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 `v2.workflow.required_floor` `run_required_floor`. 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, 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. 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. 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`, `--behavioral-receipt-plan`, `--behavioral-receipt-selftest`, `--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."), li(text: "**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 RATHER THAN RETIRING ON ITS AUTHOR'S SAY-SO.** The instrument is `tools.emission_entry_instrument` `measure_entry_emission`, invoked as `gunbc run --source-root dag --source-root src/v2 --entry dag/tools/emission_entry_instrument.dag --function measure --arg entry= --arg report=`. It runs the same spine the deleted probe script ran — emit one entry's closure, assemble it with `cssl_assemble`, build the assembled crate under cargo's JSON message format — and returns a TYPED measurement rather than a row of text: the emit-stage population from `gunbc.emit_diagnostic_observation` and the rustc coded-diagnostic population from `extdeps.cargo_diagnostic`, each member carrying its own identity and location, so two runs can be JOINED rather than only differenced. **WHAT THE CARRIER FIXES THAT THE SCRIPT DID NOT:** `EmissionMeasurement` has no spelling in which a stage that never ran renders as a stage that ran and found nothing — an unreached stage is its own variant naming the stage — and the emit decode REFUSES when the population it recovered disagrees with the compiler's own declared total, so an unrecognised diagnostic shape stops the line instead of quietly shrinking the answer. That is the execution-provenance-loss row applied to the instrument that most needed it. **WHAT IS NOT CLAIMED.** It is a measurement route and NOT a gate: no workflow invokes it, no phase enrols it, and its exit status reports whether the INSTRUMENT completed, never whether the subject was clean. The whole-corpus route is still refused by `gunbc.whole_corpus_compile_admission` and this does not change that; it is the per-entry route that module's own scope note says fits. Every other clause of the bankruptcy above stands unchanged, including that a figure copied into prose is debt whether or not a producer exists for it.") li(text: "**THE REGEN CUT DELETED A PRODUCER ALONG WITH ITS BINARY, DECLARED NOTHING, AND THIS ROW IS THAT DECLARATION (2026-08-20).** It sits beside the CI entry above rather than inside it, because the two are different facts on different clocks — that paragraph narrates what the floor and regen cuts removed, this row declares one capability the regen cut removed in silence — and because a declaration wedged into the repository's most-edited paragraph collides with every unrelated edit to it (three merge conflicts in two hours, each one re-resolving prose neither side had touched). The regen cut re-derived the deleted binary's VERIFIER half — `claim_executor --required-regen`, which compares the committed stage0 mirror against a fresh emit — and did not re-derive its PRODUCER half: writing the emitted tree to disk unconditionally, whatever the comparison then says about it. `run_required_regen` did write a candidate tree, but only on the path where the emitted and committed populations already agreed; every refusal arm returned ahead of the write. The one population asymmetry an author can actually cause is adding a module to the v1 seed closure — its mirror is emitted-not-committed by construction on the first commit that introduces it — so from the cut until this entry, that change refused while naming a file no sanctioned route in the repository produced, and its only reachable green was a hand-authored mirror. That is the same laundering the fixed-point repair above closed one gate over, arrived at from the other direction: there, the gate's only closing move was forbidden; here, the gate's only closing move did not exist. WHAT THE RUNG DROP IS, stated at the honest grain: the class is not a compiler guarantee that fell a rung, it is an OPERATION that lost its only route, so it sat outside the ladder entirely — nothing to mitigate, because nothing could be attempted. Naming it as a declared drop rather than a defect is the point of the entry: the regen cut owed one under §4b(3) and filed none, and a capability deleted in silence is exactly what §3's delete-first doctrine says the census is supposed to surface loudly. It did not surface because no dependent could refuse — the author who needed the producer was outside the tree. THE RESTORATION, and its rung: production now precedes adjudication. `v2.workflow.required_regen` `required_regen_run` is the authority, and it holds the ordering by construction rather than by check — every arm that reports a verdict carries the `CandidateTree` the verdict was computed against, so refused-with-no-tree has no spelling once emit succeeded, and the one tree-less arm is reachable only where emit produced nothing at all (*structurally guaranteed*, §4b). The host `v1_compiler.required_regen_host` `run_required_regen` mirrors that ordering by hand and is therefore only *mitigatable*; its next-rung trigger is the host being derived from the carrier rather than written beside it. The gate did not weaken: it refuses the same populations with the same typed causes, and the refusal now names the directory holding the first mirror the author must install."), li(text: "**THE CITED-SYMBOL CENSUS IS NO LONGER A REQUIRED CHECK, AND THIS ROW DECLARES THE RUNG IT DROPS (2026-08-23).** It sits beside the CI entry above rather than inside it, for the reason the regen row already gives: that paragraph narrates the floor and regen cuts, this is a third drop on its own clock, and a declaration wedged into the repository's most-edited prose collides with every unrelated edit to it. WHAT WAS HERE: a second `witnesses.yml` job, `cited-symbol`, running `claim_executor --required-cited-symbol --source-root dag --source-root src/v2` and stopping the line when any authored `DeclarationRef` named a symbol that does not resolve — the executing half of §3's cite-the-symbol-not-the-position rule. **IT IS DELETED** — the job, its command authority (`gunbc.fabric_witness_run` `cited_symbol_run_command`), the job row and capability wiring in `gunbc.witness_floor_workflow`, and the closure witness that covered it. REASON: operator directive, 2026-08-23. This is not a defect finding and the mechanism was not failing; it was executing and green, and the directive is that it does not belong in CI as a separate corpus-wide job. PREVIOUS RUNG: *mechanically preventable* — a real wall, armed on every push, measured green at `checked=390` on run `32664434197` (`f49886339a5`, 2026-08-23T20:26Z). TEMPORARY RUNG: *mitigatable* — the rule survives as review diligence, which is strictly weaker in the exact way §6 already records for the deleted inert-lens census: a newly authored citation naming a symbol that does not exist is writable again, and nothing detects it. MEASURED POPULATION AT THE CUT: 390 authored references, on the last green run of the job. FUTURE EXPOSURE, STATED AS A SECOND FACT BECAUSE JOINING THE TWO IS THE DENOMINATOR ERROR THIS DOCUMENT KEEPS FINDING: unbounded. Nothing counts a citation authored after the cut and nothing refuses one, so §4b(3)'s BOUNDED-POPULATION REQUIREMENT IS NOT SATISFIED HERE, and this row does not pretend otherwise — the drop is an operator-approved exception to that clause rather than an instance of it, and saying so is the whole point of writing the row down. An earlier revision of this row read *the 390 references, plus every citation authored after it* and called that the bounded population; an exact measurement joined to an open future set is not bounded, and calling it so is the same move §5 forbids when a count copied from the current tree is asked to serve as an oracle. The measured half also rots the way §3 says positional citations do: it is the population's size AT THE MOMENT OF THE DROP, never a standing figure. WHAT WAS NOT CLAIMED WHILE THE DROP STOOD: the capability survived at its own entry point — `--required-cited-symbol` was still a flag on `claim_executor` — but a mode no workflow invokes guards nothing, and calling the surviving flag a mitigation would have been exactly the inflation §4b(1) forbids. **THE RESTORATION TRIGGER FIRED ON 2026-08-25 AND THIS ROW IS RETIRED AS A DROP, WITH ITS EXPOSURE CLOSED RATHER THAN RE-DECLARED.** The trigger read: this row retires when the citation wall is re-derived where the operator's own framing puts it — *you would just make them a normal compiler error* — checked at ingestion, on the module whose source carries the citation, from that module's own text, rather than reconstructed corpus-wide by a second job; and it named §6's module-authorship trigger as the same rung, to be landed together rather than each rebuilding a corpus walk. Both landed on one construction, `v1_compiler.declaration_index`, inside the `parse` phase of `claim_executor --required-ci`: the sweep that already parses every authored module now derives one record per module and resolves every authored `DeclarationRef` against it by keyed lookup. `--required-cited-symbol` is DELETED with the same change, so there is one route and not two. RUNG: back to *mechanically preventable*, and STRICTLY WIDER than what was dropped — the enrolled population is every authored citation in a non-fixture module (measured 1441 authored, 161 in fixture carriers, 79 naming namespaces no `.dag` module declares), not the five carriers the deleted lens's population named, and test modules are INDEXED, so the outside-index disposition those exclusions forced is not needed. WHAT THE FIRST EXECUTION FOUND, because a wall that lands green over a corpus nobody checked for two days would be the more suspicious result: 46 sites over 38 distinct targets, every one a citation naming a declaration that does not exist — the exact class this rule names, accumulated in the unguarded window this row declared unbounded. They are NOT repaired here and NOT silently excluded: they are enumerated at identity grain in `PRE_EXISTING_CITATION_DEBT` as a §5 monotone debt contract whose universe is discovered by the index itself and whose rows REFUSE once their citation stops refusing, so the roster can only shrink. WHAT IS STILL OPEN, stated so this retirement is not read as wider than it is: `v2.lens.cited_symbol_resolution` is DELETED as of 2026-08-26, and the disposition was three-way rather than the two this row admitted. The count was stale on arrival — sixteen was the file's size at #7707 and it had grown to 27 `test fn` identities by the time this sentence was written — and \"dead\" was true of the lens and false of a third of its witnesses. Measured against the seven symbols that file imported FROM the lens, only 6 of the 27 touch one; those 6 died with it. Six more call `resolve_declaration_ref`, which lives in `v2.std.decl_ref_resolution` and SURVIVES with four other consumers, so they are the only executing evidence for a live authority's five-arm refusal and §4b(4) rehomed them to `test.claim.long.decl_ref_resolution_witness_test` rather than deleting them with the machinery that climbed. The remaining 15 are population and projection claims about the carriers that PROJECT `DeclarationRef`s and moved to `test.claim.long.carrier_reference_integrity_witness_test`. What the corpus-wide census subsumes is TYPED-LITERAL citations specifically — `DeclarationRef` record literals and the `decl_ref`/`decl_field_ref` constructors — not \"citations\" in general; a prose reference inside a `String` is covered by nothing, before or after. The per-PR witness that survives was renamed `test.claim.doc_graph_reference_partition_witness_test`, because its subject is a bucket partition over `gunbc.doc_graph_roots` and never was resolution, and under the old name it would have been the only cited-symbol-named thing left in the tree — a misreading two readers made independently from exactly that surface; and the wall is host Rust rather than a modeled ingestion operation, declared as seed growth in `gunbc.declaration_index_seed_growth`."), - li(text: "**A BLOCKING EMIT-STAGE DIAGNOSTIC CAN SIT ON MAIN INDEFINITELY WITH NO REQUIRED PHASE THAT FAILS, AND THIS ROW DECLARES THAT RUNG (2026-08-25).** It sits beside the CI entry above for the reason the regen and cited-symbol rows already give: that paragraph narrates the floor and regen cuts, this is a fourth drop on its own clock, and a declaration wedged into the repository's most-edited prose collides with every unrelated edit to it. **THE CLASS IS NOT ONE OPERATION.** It is any BLOCKING diagnostic produced at the EMIT stage, and the escape surface is Rust-target emission specifically: `v1.05_emit` `file_binding_refusal` returns a `FileEmissionRefusal`, and `file_emission_target_is_modeled` answers `Rust => true` with Python, Go and Dag all false, so the refusal exists only on the path that emits Rust. A parse phase cannot reach it and a typecheck cannot reach it; only a phase that EMITS over a closure containing the offending CALL SITE can. **HALF OF THIS IS ALREADY ON THE RECORD AND IS NOT CLAIMED AS NEW.** The CI entry above already declares, measured 2026-08-20, that `entry_file_touched_via_import_closure` and `compile_clean_scope_plan_for_ci` have zero references under `src/v1/stage0/src/bin`, that no CLI flag reaches them, and that the only `pub` surfaces into that chain return `Bool` — the authority survives and the capability does not. That is the missing compile capability, and it was declared five days before this row. **WHAT IS NEW IS THE SECOND HALF, AND IT IS WORSE: THE WITNESS FAMILY THAT APPEARS TO COMPENSATE IS ALSO INERT.** Measured on main run `32778026868` (`08488aee2`), nine identities named for compile-clean, and not one of them compiles anything. `compile_clean_shard_a_exemplar_compile_green`, `cross_shard_seam_preservation_holds_on_live_tree`, `perturb_fixture_green_holds`, `perturb_optional_skew_fixture_red_holds` and `perturb_unresolved_import_fixture_red_holds` are all NO-ROUTE — refused at the hermetic boundary, discovered and counted and answering nothing. `dag_compile_clean_scope_witness` and `dag_compile_clean_shard_totality_witness` declare `ReadsLiveTree`, so they are DeclinedLiveTree and never run. `compile_clean_shard_entry_paths_fast_hand_rust_witness` declares no disposition at all, so the fail-closed default makes it ReadsLiveTree and it is declined too. The single member that PASSES is `dag_compile_clean_cli_floor_agreement`, and it is `SubstrateInputsOnly`: it checks that two realizations AGREE ABOUT A POLICY ROW, never that anything is clean. **AND THE COVERAGE WOULD NOT HAVE HELPED EVEN HAD IT ROUTED**, which is what makes the pair a stronger claim than either half: `tools.dag_compile_clean_shard_transport` `shard_a_exemplar_entry_path` is `dag/std/logic.dag`. At full strength the family compiles ONE MODULE. So a reader counting witnesses named compile-clean concludes the corpus is compile-checked, and the corpus is not compile-checked and would not have been. That is §4b's worse-than-absent decoration, arrived at not by a check whose RED is unauthorable but by a family whose every member is routed away from its subject. PREVIOUS RUNG: *mechanically preventable* — the compile-clean gate ran ahead of everything else in the required run until the 2026-08-15 floor cut deleted it. TEMPORARY RUNG: **outside the ladder, not mitigatable.** This is the shape the regen row names: an operation that lost its only route has nothing to mitigate, because nothing can be attempted. Review diligence is not a fallback here in the way it is for the cited-symbol drop — a reviewer reads a diff and does not run an emitter, so no human process substitutes for the missing phase. **POPULATION: UNCOUNTED AND UNBOUNDED.** §4b(3) requires a bounded population and this row does not have one and does not pretend to. Two specimens are named below, escaping by three distinct modes; how many other blocking diagnostics stand on main today is unmeasured, and it is unmeasured by a deliberate scope decision rather than because the census is hard — the finding is the missing phase, and a specimen count would have been mistaken for the bound. Anyone who takes the named specimens as the population has made the denominator error this document keeps recording. **AND THIS ROW CLAIMS NO OPERATOR APPROVAL FOR THAT, WHICH IS WHERE IT DIFFERS FROM THE CITED-SYMBOL ROW ABOVE AND MUST NOT BE READ AS MATCHING IT.** That row's unbounded exposure is an operator-approved exception to §4b(3); this row's is simply an unmet requirement, declared as unmet. The distinction is the difference between a clause someone with the authority to waive it waived, and a clause this row does not satisfy — and reading the second as the first would manufacture an approval nobody gave, which is the authority-substitution failure this document names. THE NAMED SPECIMEN, WITH ITS PROVENANCE STATED HONESTLY BECAUSE THE TWO HALVES WERE MEASURED BY DIFFERENT PEOPLE ON DIFFERENT INSTRUMENTS: `extdeps.cloud.gcp.gcp` `ReadADC` DECLARED three structured output keys — `client_id`, `client_secret`, `refresh_token` — over a `transport file` that carries bytes, with nothing stating how a JSON document became those fields, and the compiler said so (`file transport output key client_id has no modeled channel`). **THAT SPECIMEN IS REPAIRED AS OF 2026-08-25 AND THE OPERATION NO LONGER EXISTS**, repaired ALONG THE LINE THIS ROW PRESCRIBED: `extdeps.cloud.gcp.adc_document` reads the document and decodes it through `extdeps.languages.json.parse`, so the read-then-decode seam this row ruled for is the seam that landed, and the `Secret`/`String` distinction a bytes channel could not carry is carried by a typed record. A row whose prescribed fix was implemented is evidence the prescription was right. The specimen is kept in the past tense rather than deleted because the CLASS claim below does not depend on it — and because nothing re-derives this sentence, which is why it stood stale until a session tripped over it. It was found cold and measured as the SOLE blocking diagnostic of a whole-census entry compile at `63501ff7e0`, from `--entry dag/gunbc/systemctl_show_read.dag` — a measurement this row's author did not take and does not restate as their own. **A SECOND COMPILE FROM A DIFFERENT ENTRY IS NOT A FAILED REPRODUCTION OF IT, AND THE DIFFERENCE IS THE CLASS DEFINITION DOING WORK.** Compiling `gunbc.auth.credentials` — the module that CONTAINS the call site — as its own entry refuses earlier, at typecheck, with four unrelated hard diagnostics, so that compile never reaches the stage where the channel refusal is produced. Nothing is contradicted: the two entries have different closures and stop at different phases. What the pair establishes is sharper than either alone — **the refusal is reachable from an entry whose closure INCLUDES the call site and unreachable from the file that HOLDS it**, so an emit-stage diagnostic is a property of a CLOSURE, not of a file. A per-file or per-module check would therefore not have caught this either, which is why the restoration trigger below names a phase over closures and not a linter. **A SECOND AND INDEPENDENT ESCAPE MODE, FOUND BY ACCIDENT WHILE MEASURING THE FIRST.** Those four typecheck diagnostics are not an incidental specimen of the same route — they escape a different way. `gunbc.auth.credentials` has ZERO IMPORT EDGES anywhere in `dag/` or `src/v2/`: it is an orphan, so no closure reaches it and nothing typechecks it, and its four hard errors (two `undefined variable shell`, two unresolved `AuthPrintAccessToken`) stand on main for a reason that has nothing to do with which phases emit. The first mode is *no required phase emits over this closure*; the second is *no closure reaches this module at all*. **AND A THIRD, WHICH IS THE WORST OF THEM, because it is the only one that misleads a reader rather than merely hiding from a checker.** The orphan is NOT unreferenced: `gunbc.tailscale_acl_phase2_credential` carries two `DeclarationRef` rows naming `gunbc.auth.credentials` as its credential authority — `gcp_secret_credential` and `gcp_oauth_access_token_via_adc_refresh`. So the module is CLAIMED AS AN AUTHORITY by a carrier that depends on it being correct, while no import edge reaches it and nothing typechecks it. An unreferenced orphan misleads nobody; a cited one asserts that a fact has a home, and the home does not compile. **THE THIRD MODE IS WHERE TWO DECLARED DROPS COMPOSE, AND NEITHER ROW ALONE PREDICTS IT.** The cited-symbol row above declares, from 2026-08-23, that nothing checks whether an authored citation resolves; this row declares that nothing emits over the closure a citation names. These two `DeclarationRef` rows were authored into exactly that window. A citation to a module that typechecks nowhere is invisible to both mechanisms at once — the first stopped asking *does this symbol exist*, the second stopped asking *does this module compile* — and the composition is not a complaint about either operator decision, it is what makes the population claim below concrete rather than rhetorical. Neither of the three modes was found by searching. All three were tripped over while measuring something else, which is the strongest available argument that the population below is not two or three. ONE MEASUREMENT THAT CORRECTS THE OBVIOUS ASSUMPTION, recorded so the next reader does not repeat it: compiling `extdeps/cloud/gcp/gcp.dag` AS AN ENTRY returns **0 blocking, 79 advisory**. The declaration alone does not refuse. The operation looks self-evidently broken and compiles clean in isolation, so an entry-grain check over extdeps would not have caught it either — it takes an entry whose closure reaches the call site. RESTORATION TRIGGER: this row retires when a required phase EMITS over a closure that reaches call sites — the compile re-add on the queue the floor cut created — and not when the gcp operation is repaired. Fixing the specimen closes the specimen; only the phase closes the class. The gcp repair is separately ruled: `extdeps.filesystem.filesystem_io` `Read` already models file-read with a `content` channel and `extdeps.languages.json` already models decode, so the seam is read-then-decode over two authorities that exist, and minting a gcp-specific channel would be the §3 nicknaming violation — it would additionally flatten the distinction that `client_secret` and `refresh_token` are `Secret` while `client_id` is `String`, which a bytes channel cannot carry and a typed record can."), + li(text: "**A BLOCKING EMIT-STAGE DIAGNOSTIC CAN SIT ON MAIN INDEFINITELY WITH NO REQUIRED PHASE THAT FAILS, AND THIS ROW DECLARES THAT RUNG (2026-08-25).** It sits beside the CI entry above for the reason the regen and cited-symbol rows already give: that paragraph narrates the floor and regen cuts, this is a fourth drop on its own clock, and a declaration wedged into the repository's most-edited prose collides with every unrelated edit to it. **THE CLASS IS NOT ONE OPERATION.** It is any BLOCKING diagnostic produced at the EMIT stage, and the escape surface is Rust-target emission specifically: `v1.05_emit` `file_binding_refusal` returns a `FileEmissionRefusal`, and `file_emission_target_is_modeled` answers `Rust => true` with Python, Go and Dag all false, so the refusal exists only on the path that emits Rust. A parse phase cannot reach it and a typecheck cannot reach it; only a phase that EMITS over a closure containing the offending CALL SITE can. **HALF OF THIS IS ALREADY ON THE RECORD AND IS NOT CLAIMED AS NEW.** The CI entry above already declares, measured 2026-08-20, that `entry_file_touched_via_import_closure` and `compile_clean_scope_plan_for_ci` have zero references under `src/v1/stage0/src/bin`, that no CLI flag reaches them, and that the only `pub` surfaces into that chain return `Bool` — the authority survives and the capability does not. That is the missing compile capability, and it was declared five days before this row. **WHAT IS NEW IS THE SECOND HALF, AND IT IS WORSE: THE WITNESS FAMILY THAT APPEARS TO COMPENSATE IS ALSO INERT.** Measured on main run `32778026868` (`08488aee2`), nine identities named for compile-clean, and not one of them compiles anything. `compile_clean_shard_a_exemplar_compile_green`, `cross_shard_seam_preservation_holds_on_live_tree`, `perturb_fixture_green_holds`, `perturb_optional_skew_fixture_red_holds` and `perturb_unresolved_import_fixture_red_holds` are all NO-ROUTE — refused at the hermetic boundary, discovered and counted and answering nothing. `dag_compile_clean_scope_witness` and `dag_compile_clean_shard_totality_witness` declare `ReadsLiveTree`, so they are DeclinedLiveTree and never run. `compile_clean_shard_entry_paths_fast_hand_rust_witness` declares no disposition at all, so the fail-closed default makes it ReadsLiveTree and it is declined too. The single member that PASSES is `dag_compile_clean_cli_floor_agreement`, and it is `SubstrateInputsOnly`: it checks that two realizations AGREE ABOUT A POLICY ROW, never that anything is clean. **AND THE COVERAGE WOULD NOT HAVE HELPED EVEN HAD IT ROUTED**, which is what makes the pair a stronger claim than either half: `tools.dag_compile_clean_shard_transport` `shard_a_exemplar_entry_path` is `dag/std/logic.dag`. At full strength the family compiles ONE MODULE. So a reader counting witnesses named compile-clean concludes the corpus is compile-checked, and the corpus is not compile-checked and would not have been. That is §4b's worse-than-absent decoration, arrived at not by a check whose RED is unauthorable but by a family whose every member is routed away from its subject. PREVIOUS RUNG: *mechanically preventable* — the compile-clean gate ran ahead of everything else in the required run until the 2026-08-15 floor cut deleted it. TEMPORARY RUNG: **outside the ladder, not mitigatable.** This is the shape the regen row names: an operation that lost its only route has nothing to mitigate, because nothing can be attempted. Review diligence is not a fallback here in the way it is for the cited-symbol drop — a reviewer reads a diff and does not run an emitter, so no human process substitutes for the missing phase. **POPULATION: UNCOUNTED AND UNBOUNDED.** §4b(3) requires a bounded population and this row does not have one and does not pretend to. Two specimens are named below, escaping by three distinct modes; how many other blocking diagnostics stand on main today is unmeasured, and it is unmeasured by a deliberate scope decision rather than because the census is hard — the finding is the missing phase, and a specimen count would have been mistaken for the bound. Anyone who takes the named specimens as the population has made the denominator error this document keeps recording. **AND THIS ROW CLAIMS NO OPERATOR APPROVAL FOR THAT, WHICH IS WHERE IT DIFFERS FROM THE CITED-SYMBOL ROW ABOVE AND MUST NOT BE READ AS MATCHING IT.** That row's unbounded exposure is an operator-approved exception to §4b(3); this row's is simply an unmet requirement, declared as unmet. The distinction is the difference between a clause someone with the authority to waive it waived, and a clause this row does not satisfy — and reading the second as the first would manufacture an approval nobody gave, which is the authority-substitution failure this document names. THE NAMED SPECIMEN, WITH ITS PROVENANCE STATED HONESTLY BECAUSE THE TWO HALVES WERE MEASURED BY DIFFERENT PEOPLE ON DIFFERENT INSTRUMENTS: `extdeps.cloud.gcp.gcp` `ReadADC` DECLARED three structured output keys — `client_id`, `client_secret`, `refresh_token` — over a `transport file` that carries bytes, with nothing stating how a JSON document became those fields, and the compiler said so (`file transport output key client_id has no modeled channel`). **THAT SPECIMEN IS REPAIRED AS OF 2026-08-25 AND THE OPERATION NO LONGER EXISTS**, repaired ALONG THE LINE THIS ROW PRESCRIBED: `extdeps.cloud.gcp.adc_document` reads the document and decodes it through `extdeps.languages.json.parse`, so the read-then-decode seam this row ruled for is the seam that landed, and the `Secret`/`String` distinction a bytes channel could not carry is carried by a typed record. A row whose prescribed fix was implemented is evidence the prescription was right. The specimen is kept in the past tense rather than deleted because the CLASS claim below does not depend on it — and because nothing re-derives this sentence, which is why it stood stale until a session tripped over it. It was found cold and measured as the SOLE blocking diagnostic of a whole-census entry compile at `63501ff7e0`, from `--entry dag/gunbc/systemctl_show_read.dag` — a measurement this row's author did not take and does not restate as their own. **A SECOND COMPILE FROM A DIFFERENT ENTRY IS NOT A FAILED REPRODUCTION OF IT, AND THE DIFFERENCE IS THE CLASS DEFINITION DOING WORK.** Compiling `gunbc.auth.credentials` — the module that CONTAINS the call site — as its own entry refuses earlier, at typecheck, with four unrelated hard diagnostics, so that compile never reaches the stage where the channel refusal is produced. Nothing is contradicted: the two entries have different closures and stop at different phases. What the pair establishes is sharper than either alone — **the refusal is reachable from an entry whose closure INCLUDES the call site and unreachable from the file that HOLDS it**, so an emit-stage diagnostic is a property of a CLOSURE, not of a file. A per-file or per-module check would therefore not have caught this either, which is why the restoration trigger below names a phase over closures and not a linter. **A SECOND AND INDEPENDENT ESCAPE MODE, FOUND BY ACCIDENT WHILE MEASURING THE FIRST.** Those four typecheck diagnostics are not an incidental specimen of the same route — they escape a different way. `gunbc.auth.credentials` has ZERO IMPORT EDGES anywhere in `dag/` or `src/v2/`: it is an orphan, so no closure reaches it and nothing typechecks it, and its four hard errors (two `undefined variable shell`, two unresolved `AuthPrintAccessToken`) stand on main for a reason that has nothing to do with which phases emit. The first mode is *no required phase emits over this closure*; the second is *no closure reaches this module at all*. **AND A THIRD, WHICH IS THE WORST OF THEM, because it is the only one that misleads a reader rather than merely hiding from a checker.** The orphan is NOT unreferenced: `gunbc.tailscale_acl_phase2_credential` carries two `DeclarationRef` rows naming `gunbc.auth.credentials` as its credential authority — `gcp_secret_credential` and `gcp_oauth_access_token_via_adc_refresh`. So the module is CLAIMED AS AN AUTHORITY by a carrier that depends on it being correct, while no import edge reaches it and nothing typechecks it. An unreferenced orphan misleads nobody; a cited one asserts that a fact has a home, and the home does not compile. **THE THIRD MODE IS WHERE TWO DECLARED DROPS COMPOSE, AND NEITHER ROW ALONE PREDICTS IT.** The cited-symbol row above declares, from 2026-08-23, that nothing checks whether an authored citation resolves; this row declares that nothing emits over the closure a citation names. These two `DeclarationRef` rows were authored into exactly that window. A citation to a module that typechecks nowhere is invisible to both mechanisms at once — the first stopped asking *does this symbol exist*, the second stopped asking *does this module compile* — and the composition is not a complaint about either operator decision, it is what makes the population claim below concrete rather than rhetorical. Neither of the three modes was found by searching. All three were tripped over while measuring something else, which is the strongest available argument that the population below is not two or three. ONE MEASUREMENT THAT CORRECTS THE OBVIOUS ASSUMPTION, recorded so the next reader does not repeat it: compiling `extdeps/cloud/gcp/gcp.dag` AS AN ENTRY returns **0 blocking, 79 advisory**. The declaration alone does not refuse. The operation looks self-evidently broken and compiles clean in isolation, so an entry-grain check over extdeps would not have caught it either — it takes an entry whose closure reaches the call site. RESTORATION TRIGGER: this row retires when a required phase EMITS over a closure that reaches call sites — the compile re-add on the queue the floor cut created — and not when the gcp operation is repaired. Fixing the specimen closes the specimen; only the phase closes the class. The gcp repair is separately ruled: `extdeps.filesystem.filesystem_io` `Read` already models file-read with a `content` channel and `extdeps.languages.json` already models decode, so the seam is read-then-decode over two authorities that exist, and minting a gcp-specific channel would be the §3 nicknaming violation — it would additionally flatten the distinction that `client_secret` and `refresh_token` are `Secret` while `client_id` is `String`, which a bytes channel cannot carry and a typed record can. **A REQUIRED PHASE NOW COMPILES AN EMITTED CLOSURE, AND THIS ROW IS NARROWED RATHER THAN RETIRED (2026-08-26).** The trigger above says the row retires when a required phase emits over a closure that reaches call sites; a phase that emits and compiles one now exists, and it does not reach every closure, so what changes is the SIZE of the exposure and not its existence. WHAT LANDED: a fifth required phase, `emit-compile`, in the `build` lane — the same producer the `v2-emission` phase calls (`compile_entry_emission`), its emitted files written as a crate whose manifest is RENDERED from the modeled cargo authorities rather than authored as markup, and `cargo` run over it. Its subject is `gunbc.ci_layer_roots` `required_emit_compile_entries`, a bounded roster, bounded deliberately: `gunbc.whole_corpus_compile_admission` refuses a whole-bundle compile on the default runner and carries two `EXIT=137` kills behind that refusal, so a whole-corpus required compile is the one form measurement already rules out. **THE PHASE ESTABLISHES ITS OWN RED BY MUTATION, ON EVERY RUN, AND THAT IS THE POINT OF IT RATHER THAN A FLOURISH.** A cargo phase that is green because nothing was measured is exactly the decoration §4b calls worse than absent, and the compile-clean family this row already indicts is what that looks like at nine identities. So a green baseline alone is NOT a pass: `v1_compiler.emitted_closure_compile_host` `establish_discriminating_red` injects ONE type error into ONE emitted file, requires cargo to fail ALONE on it, restores the bytes byte-exactly and requires the green back — and every non-discriminating arm (`NotAttempted`, `NotDiscriminating`, `RestoreFailed`) stops the line with its own typed cause. The restore is as much of the evidence as the failure: without it a red could be residue from the emission rather than from the fault. **WHAT IS STILL OPEN, AND THE ROW STAYS FOR IT.** Escape mode one is narrowed, not closed — a blocking emit-stage diagnostic in a closure no rostered entry reaches still fails no phase, and the population of such closures remains uncounted. Escape modes two and three are UNTOUCHED: an orphan module no closure reaches is still typechecked by nothing, and a `DeclarationRef` naming it still asserts a home that does not compile. The phase carries no diagnostic count, no baseline and no ratchet — a merge-blocking comparison against a population measured on the current tree is the tree-copied oracle §5 rejects — so it answers *does the emitted tree compile*, never *how clean is it*. **THE COVER IS NOT THE CORPUS, AND THE PHASE'S OWN OUTPUT SAYS SO**, because the failure this row already indicts is exactly a reader counting compile-clean-named things and concluding the tree is compile-checked. The summary line reports the covered entries beside the count of authored `.dag` modules under the source roots, so the misreading is unavailable from the log rather than merely avoidable by anyone who goes and reads the roster. **WHAT THE COVER'S SIZE IS ACTUALLY BOUNDED BY, MEASURED RATHER THAN ASSUMED:** an entry costs ~40–50s wall and ~85% of that is `compile.reconcile`, paid INDEPENDENTLY PER ENTRY over closures that overlap heavily — most of `dag/std` sits in nearly every closure. That is a §2 cost-shape defect, not a budget fact: the same modules are reconciled tens of times in one run, and §6's bare-minimum-cost rule says a proven cost-shape defect is fixed regardless of the realized n. So the honest reading is not *the ceiling is forty entries* but *the per-entry cover is the wrong unit, and forty is what the wrong unit buys*. THE ROW RETIRES on the CAPABILITY, not on the cover's size: when required emission coverage reaches every closure the corpus has, by whatever construction, AND THAT INSTRUMENT IS SUFFICIENT TO COMPLETE AND PERSIST THE WHOLE-ROSTER TRANSACTION WITHIN THE ADMITTED RUNNER ENVELOPE. The sufficiency clause is not belt-and-braces: without it the trigger fires the moment a phase named for whole-roster coverage is ENROLLED, which a partial phase satisfies while the capability is still absent — the same defect one level in from the roster-size version, since the roster can be whole while the run that walks it cannot finish or cannot keep what it observed. AND THE NAME CARRIES THE SAME BURDEN: this phase's required context is a SELECTED emission observation, never a whole one, and its success means THE SELECTED OBSERVATION WAS TAKEN AND PERSISTED — never THE CORPUS IS CLEAN. A partial phase is a legitimate wall for an exact selected subject and zero wall for its complement; it becomes decoration only when its name, its trigger, or its consumers let the selected proposition stand in for the exhaustive one, which is why the remainder is reported as RETAINED IDENTITIES rather than as a percentage. A fraction says how much is unobserved and never which, so it is not the bounded population §4b(3) asks for; it may stand as context and may never be the gap's identity or its dissolution trigger. A trigger reading *grow the roster* would be satisfied at forty-one while the corpus stayed unmeasured, which is why it is not written that way. Its named dependency is the reconcile sharing above — a cover whose unit is the entry cannot reach the corpus at any budget, so the unblocking work is making one run reconcile a shared closure once, and that is a separate lane this row does not claim."), ]), ] } From 5077b88e6bb026f09776c36421193ffc5b16f2cc Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Thu, 27 Aug 2026 05:49:00 +0000 Subject: [PATCH 3/9] Give each probe crate its own package name, and install the regenerated stage0 layout mirror The phase compiled every roster entry under one package name and version into a shared CARGO_TARGET_DIR, so the only thing separating two entries' cargo fingerprints was cargo's use of the manifest path -- an implementation detail of a tool, load-bearing for a merge gate, stated nowhere. Had a build ever been judged fresh against another entry's artifacts, cargo would replay that entry's cached diagnostics, and a replayed clean compile is byte-identical in the output to a real one: the arm would report Completed status=0 for an entry it never compiled and the gate would go green over it. Fail-open. Deriving the package name from the entry makes each probe crate its own package, so the fingerprints cannot alias. Dependencies are separate packages and stay shared, so the warmth the target dir buys is untouched. The layout mirror is installed from the regen candidate rather than hand-edited: main added namespace_wave_admission.rs and target_invocation_host.rs while this branch was open, and the merge's ours-side resolution of a generated file dropped them. Co-Authored-By: Claude Opus 5 (1M context) --- .../src/emitted_closure_compile_host.rs | 36 +++++++++++++++---- .../gunbc_stage0_crate_layout_generated.rs | 2 +- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/v1/stage0/src/emitted_closure_compile_host.rs b/src/v1/stage0/src/emitted_closure_compile_host.rs index 2b4a39c4027..c42d4634e03 100644 --- a/src/v1/stage0/src/emitted_closure_compile_host.rs +++ b/src/v1/stage0/src/emitted_closure_compile_host.rs @@ -49,9 +49,31 @@ use crate::v1_compiler_stage0_crates::{ const REQUIRED_EMIT_COMPILE_ENTRIES_DATA_NAME: &str = "required_emit_compile_entries"; -/// The crate name the emitted closure is compiled under. One name for every entry: the crate -/// is rebuilt per entry in its own directory, so the name is a label rather than an identity. -const PROBE_PACKAGE_NAME: &str = "gunbc-emitted-closure"; +/// The crate name the emitted closure is compiled under — DERIVED PER ENTRY, not shared. +/// +/// WHY IT IS NOT ONE NAME FOR EVERY ENTRY, WHICH IS WHAT IT WAS. The entries share one +/// `CARGO_TARGET_DIR` deliberately: that is what keeps dependency artifacts warm across a roster, +/// and rebuilding `im`, `serde` and the seed crate once per entry would multiply the phase's cost +/// by its roster size. But a shared target directory plus one package name and version means the +/// only thing separating two entries' fingerprints is cargo's use of the manifest path. That is +/// an implementation detail of a tool, load-bearing for a merge gate, and nothing here states it. +/// +/// THE FAILURE IT WOULD PRODUCE IS FAIL-OPEN, WHICH IS WHY IT IS WORTH A NAME RATHER THAN A +/// COMMENT SAYING CARGO HANDLES IT. If one entry's build were ever judged fresh against another's +/// artifacts, cargo would replay the other's cached diagnostics — and a replayed clean compile is +/// byte-identical in the output to a real one. The arm would report `Completed status=0` for an +/// entry it never compiled, and the gate would go green over it. +/// +/// Deriving the name from the entry makes each probe crate its own package, so the fingerprints +/// cannot alias whatever cargo keys on. Dependencies are separate packages and stay shared, so +/// the warmth the shared target dir buys is untouched. +fn probe_package_name(entry: &str) -> String { + let slug: String = entry + .chars() + .map(|c| if c.is_ascii_alphanumeric() { c } else { '-' }) + .collect(); + format!("gunbc-emitted-closure-{slug}") +} /// THE INJECTED FAULT. A type error rather than a syntax error, deliberately: a syntax error /// would also be caught by anything that merely parses the file, so it cannot discriminate a @@ -274,7 +296,7 @@ pub fn emit_compile_outcome_summary(outcome: &EmitCompileOutcome) -> String { /// `cssl_v1_compiled_probe_lib_cargo_toml`), it is marked scaffold debt in its own module for /// being concat-authored markup, and adding a required gate as a consumer of it would have /// pinned that debt open on the merge path. -fn probe_manifest(workspace: &Path) -> String { +fn probe_manifest(workspace: &Path, entry: &str) -> String { let mut deps: Vec = stage0_foundation_runtime_dependencies() .iter() .map(|dep| (**dep).clone()) @@ -295,7 +317,7 @@ fn probe_manifest(workspace: &Path) -> String { .join(""); format!( "{}\nedition = \"2021\"\n\n[dependencies]\n{rendered}", - render_cargo_package_header_prefix(PROBE_PACKAGE_NAME.to_string()) + render_cargo_package_header_prefix(probe_package_name(entry)) ) } @@ -347,7 +369,7 @@ fn write_probe_crate(run: &CompileRun, entry: &str) -> Result<(PathBuf, usize), } std::fs::write( dir.join("Cargo.toml"), - probe_manifest(&process_workspace_root()), + probe_manifest(&process_workspace_root(), entry), ) .map_err(|e| format!("writing the manifest into {}: {e}", dir.display()))?; Ok((dir, written)) @@ -935,7 +957,7 @@ mod tests { /// runtime dependency set, and the path dependency the emitted closure links against. #[test] fn manifest_carries_the_modeled_dependency_rows() { - let manifest = probe_manifest(Path::new("/repo")); + let manifest = probe_manifest(Path::new("/repo"), "dag/std/logic.dag"); assert!(manifest.starts_with("[package]\nname = \"gunbc-emitted-closure\"")); assert!(manifest.contains("edition = \"2021\"")); for name in ["im", "serde", "serde_json", "stacker"] { diff --git a/src/v1/stage0/src/gunbc_stage0_crate_layout_generated.rs b/src/v1/stage0/src/gunbc_stage0_crate_layout_generated.rs index 986b1a8b799..f310831c1fa 100644 --- a/src/v1/stage0/src/gunbc_stage0_crate_layout_generated.rs +++ b/src/v1/stage0/src/gunbc_stage0_crate_layout_generated.rs @@ -39,7 +39,7 @@ pub fn generated_pub_mod_basenames() -> Rc> { pub fn generated_stage0_filenames() -> Rc> { thread_local! { static CACHED: Rc> = { - Rc::new(vec!["v1_interpreter.rs".to_string(), "bounded_shell_host_drain.rs".to_string(), "cli_run.rs".to_string(), "codex_app_server_stdio_session.rs".to_string(), "coproduct_reflection.rs".to_string(), "data_initializer_identity.rs".to_string(), "declaration_index.rs".to_string(), "resolved_graph_cache.rs".to_string(), "shared_typecheck_store.rs".to_string(), "recorded_fixture.rs".to_string(), "phase_profile.rs".to_string(), "pre_push.rs".to_string(), "census_exclude_derive.rs".to_string(), "derived_realization_schedule.rs".to_string(), "memory_governor.rs".to_string(), "std_lens_verdict.rs".to_string(), "v2_compiler_body_producer.rs".to_string(), "v2_compiler_normalize.rs".to_string(), "v2_compiler_target_carriers.rs".to_string(), "v2_compiler_discovery_enumeration.rs".to_string(), "v2_compiler_parse_engine_hooks.rs".to_string(), "v2_compiler_use_site_verdict.rs".to_string(), "cssl_seed_linked_closure_assembly.rs".to_string(), "required_regen_host.rs".to_string(), "partition_crate_boundary_host.rs".to_string(), "emitted_closure_compile_host.rs".to_string(), "v2_compiler_compile.rs".to_string(), "v2_compiler_program_assembly.rs".to_string(), "v2_compiler_source_authority.rs".to_string(), "usv_pilot_v2_std_algebra.rs".to_string(), "usv_pilot_v2_std_collection.rs".to_string(), "usv_pilot_v2_std_node.rs".to_string(), "v2_compiler_resolve.rs".to_string(), "v2_compiler_program_partition.rs".to_string(), "v2_compiler_tokenize.rs".to_string(), "v2_compiler_infer.rs".to_string(), "bootstrap_stage0_crate_layout_generated.rs".to_string(), "v1_interpreter_dispatch_generated.rs".to_string(), "main.rs".to_string()]) + Rc::new(vec!["v1_interpreter.rs".to_string(), "bounded_shell_host_drain.rs".to_string(), "cli_run.rs".to_string(), "codex_app_server_stdio_session.rs".to_string(), "coproduct_reflection.rs".to_string(), "data_initializer_identity.rs".to_string(), "declaration_index.rs".to_string(), "resolved_graph_cache.rs".to_string(), "shared_typecheck_store.rs".to_string(), "recorded_fixture.rs".to_string(), "phase_profile.rs".to_string(), "pre_push.rs".to_string(), "census_exclude_derive.rs".to_string(), "derived_realization_schedule.rs".to_string(), "memory_governor.rs".to_string(), "namespace_wave_admission.rs".to_string(), "std_lens_verdict.rs".to_string(), "v2_compiler_body_producer.rs".to_string(), "v2_compiler_normalize.rs".to_string(), "v2_compiler_target_carriers.rs".to_string(), "v2_compiler_discovery_enumeration.rs".to_string(), "v2_compiler_parse_engine_hooks.rs".to_string(), "v2_compiler_use_site_verdict.rs".to_string(), "cssl_seed_linked_closure_assembly.rs".to_string(), "required_regen_host.rs".to_string(), "target_invocation_host.rs".to_string(), "partition_crate_boundary_host.rs".to_string(), "emitted_closure_compile_host.rs".to_string(), "v2_compiler_compile.rs".to_string(), "v2_compiler_program_assembly.rs".to_string(), "v2_compiler_source_authority.rs".to_string(), "usv_pilot_v2_std_algebra.rs".to_string(), "usv_pilot_v2_std_collection.rs".to_string(), "usv_pilot_v2_std_node.rs".to_string(), "v2_compiler_resolve.rs".to_string(), "v2_compiler_program_partition.rs".to_string(), "v2_compiler_tokenize.rs".to_string(), "v2_compiler_infer.rs".to_string(), "bootstrap_stage0_crate_layout_generated.rs".to_string(), "v1_interpreter_dispatch_generated.rs".to_string(), "main.rs".to_string()]) }; } CACHED.with(|c: &Rc>| c.clone()) From 770a041661f8f21e1816159bb93ec298e5e0444f Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Thu, 27 Aug 2026 06:36:44 +0000 Subject: [PATCH 4/9] Require the faulted arm to complete and its red to name the injected fault The mutation arm accepted any non-compiling cargo verdict as evidence of the injected type error. A killed cargo, a spawn failure, or a red for an unrelated reason all satisfy !cargo_verdict_compiled, so the arm could report Discriminated -- and green a required gate -- while establishing nothing about sensitivity to the emitted bytes. That is a fabricated red inside the phase whose whole purpose is to refuse fabricated evidence. The arm now demands three things of the faulted run, each ruling out a different way the old check could be satisfied without measuring anything: Completed, so a run that never reached a verdict is not a red; nonzero, so it refused; and a diagnostic naming the injected symbol, so it refused for OUR reason rather than for something already wrong in the tree. Attribution is scanned from the whole stderr and carried on the verdict, not read from stderr_tail: the tail is the last 20 lines and a genuine diagnostic for the injected item can sit above it, so deciding attribution from the tail would fail runs whose fault WAS refused. The reported red line is the same line the check accepted, so the receipt cannot disagree with the evidence. Executed both ways at one entry: normal injection Discriminated with the probe line quoted, RC=0; the same fault renamed so no diagnostic mentions the probe symbol, NotDiscriminating, RC=1. Co-Authored-By: Claude Opus 5 (1M context) --- .../src/emitted_closure_compile_host.rs | 113 +++++++++++++++--- 1 file changed, 97 insertions(+), 16 deletions(-) diff --git a/src/v1/stage0/src/emitted_closure_compile_host.rs b/src/v1/stage0/src/emitted_closure_compile_host.rs index c42d4634e03..7a8f232cc5d 100644 --- a/src/v1/stage0/src/emitted_closure_compile_host.rs +++ b/src/v1/stage0/src/emitted_closure_compile_host.rs @@ -80,6 +80,11 @@ fn probe_package_name(entry: &str) -> String { /// cargo verdict from a cheaper reader. `E0308` requires rustc to have type-checked the /// module, which is exactly the reach being claimed. The name is unique enough that it cannot /// collide with emitted output, and the item is `pub` so no dead-code lint can elide it. +/// The symbol the injected item declares. The faulted arm's diagnostics must NAME it: that is +/// what makes the red attributable to this phase's own fault rather than to anything else that +/// happened to be wrong in the emitted tree at the same moment. +const MUTATION_PROBE_SYMBOL: &str = "EMIT_COMPILE_MUTATION_PROBE"; + const MUTATION_ITEM: &str = "\npub const EMIT_COMPILE_MUTATION_PROBE: u8 = \"the phase's own discriminating red\";\n"; @@ -108,7 +113,18 @@ pub enum CargoVerdict { /// Launched, and reached no exit status of its own -- killed, or the spawn failed. DidNotComplete { detail: String }, /// Ran to completion and reported its own exit status. - Completed { status: i32, stderr_tail: String }, + /// + /// `probe_line` carries the first diagnostic line naming the injected probe symbol, scanned + /// from the WHOLE stderr rather than from `stderr_tail`. The two are different questions and + /// conflating them would reintroduce the defect this field exists for: the tail is the last + /// 20 lines, kept so a human can read a failure, and a genuine `E0308` for the injected item + /// can sit well above it when other diagnostics follow. Deciding attribution from the tail + /// would then fail a run whose fault WAS refused, for the reason that the receipt was short. + Completed { + status: i32, + stderr_tail: String, + probe_line: Option, + }, } /// Only a completed, zero-status run compiled. Every other arm -- including the one that never @@ -132,6 +148,14 @@ pub fn cargo_verdict_summary(verdict: &CargoVerdict) -> String { } } +/// The diagnostic line naming the injected probe symbol, if the run produced one. +pub fn cargo_verdict_probe_line(verdict: &CargoVerdict) -> Option<&str> { + match verdict { + CargoVerdict::Completed { probe_line, .. } => probe_line.as_deref(), + _ => None, + } +} + pub fn cargo_verdict_stderr_tail(verdict: &CargoVerdict) -> &str { match verdict { CargoVerdict::Completed { stderr_tail, .. } => stderr_tail.as_str(), @@ -408,9 +432,14 @@ fn run_cargo(crate_dir: &Path, workspace: &Path) -> CargoVerdict { Some(status) => { let stderr = String::from_utf8_lossy(&output.stderr); let tail: Vec<&str> = stderr.lines().rev().take(20).collect(); + let probe_line = stderr + .lines() + .find(|line| line.contains(MUTATION_PROBE_SYMBOL)) + .map(|line| line.trim().to_string()); CargoVerdict::Completed { status, stderr_tail: tail.into_iter().rev().collect::>().join("\n"), + probe_line, } } }, @@ -495,17 +524,69 @@ fn establish_discriminating_red( let restore_write = std::fs::write(&path, &original); let restored_bytes = std::fs::read_to_string(&path).unwrap_or_default(); - if cargo_verdict_compiled(&red) { + // THE FAULTED ARM MUST HAVE COMPLETED, AND ITS RED MUST BE ATTRIBUTABLE TO THE FAULT. + // + // A NONZERO EXIT IS NOT EVIDENCE ON ITS OWN, which is the hole this block closes. Cargo can + // be killed, fail to spawn, run out of disk, or die for a reason having nothing to do with + // the injected item — and `!cargo_verdict_compiled(&red)` is true in every one of those + // cases. Accepting them would let the phase report `Discriminated` while establishing + // nothing about sensitivity to the mutation, and then green a merge gate on it: a fabricated + // red, which is the fabricated-plausible-output failure aimed at the phase's own evidence. + // + // THIS IS NOT HYPOTHETICAL. Verifying the blunted-mutation arm, a concurrent run produced + // exactly this shape — a `Discriminated` verdict whose red line quoted a `#[cfg]` WARNING + // over a cargo run that had actually said `Finished`. The probe-root lock closes the cause; + // this closes the arm that accepted the result, and the two are different defects. + // + // So the arm demands three things of the faulted run, in order of what they rule out: + // 1. `Completed` — cargo ran to a verdict, so `NotAttempted`/`DidNotComplete` fail rather + // than passing as a red; + // 2. a nonzero status — it refused; + // 3. a diagnostic naming THE INJECTED SYMBOL — it refused for OUR reason. Requiring the + // symbol rather than merely the code is what distinguishes the injected fault from an + // unrelated `E0308` that was already in the emitted tree; the code alone would accept a + // pre-existing type error as the phase's own evidence. + match &red { + CargoVerdict::Completed { status: 0, .. } => { + return MutationVerdict::NotDiscriminating { + detail: format!( + "cargo compiled {} with a deliberate type error appended to src/{}.rs — \ + the verdict is not a function of the emitted bytes, so the green baseline \ + beside it carries no information", + crate_dir.display(), + mutation_subject_rust_module(&subject) + ), + }; + } + CargoVerdict::NotAttempted { reason } => { + return MutationVerdict::NotDiscriminating { + detail: format!( + "the faulted arm never ran cargo ({reason}) — a run that did not happen is \ + not a red, and treating its absence as one would fabricate the evidence \ + this phase exists to establish" + ), + }; + } + CargoVerdict::DidNotComplete { detail } => { + return MutationVerdict::NotDiscriminating { + detail: format!( + "the faulted arm did not reach a cargo verdict ({detail}) — a killed or \ + unspawnable cargo is not evidence that the injected fault was refused" + ), + }; + } + CargoVerdict::Completed { .. } => {} + } + let Some(attributed) = cargo_verdict_probe_line(&red) else { return MutationVerdict::NotDiscriminating { detail: format!( - "cargo compiled {} with a deliberate type error appended to src/{}.rs — \ - the verdict is not a function of the emitted bytes, so the green baseline \ - beside it carries no information", - crate_dir.display(), - mutation_subject_rust_module(&subject) + "the faulted arm refused, but no diagnostic names {MUTATION_PROBE_SYMBOL} — the \ + red is not attributable to the injected fault, so it establishes nothing about \ + sensitivity to the emitted bytes" ), }; - } + }; + let attributed = attributed.to_string(); if let Err(e) = restore_write { return MutationVerdict::RestoreFailed { @@ -531,14 +612,13 @@ fn establish_discriminating_red( }; } - let red_tail = cargo_verdict_stderr_tail(&red); - let red_line = red_tail - .lines() - .find(|line| line.contains("error[")) - .unwrap_or_else(|| red_tail.lines().next().unwrap_or("")) - .trim() - .to_string(); - MutationVerdict::Discriminated { subject, red_line } + // The reported line is the diagnostic that NAMES THE FAULT, which is the same line the + // attribution check above accepted -- so the receipt a reader sees is the evidence the arm + // actually decided on, rather than a separately-chosen line that could disagree with it. + MutationVerdict::Discriminated { + subject, + red_line: attributed, + } } /// The rust module basename an entry `.dag` file emits under, from its own `module` line. @@ -1022,6 +1102,7 @@ mod tests { let green = CargoVerdict::Completed { status: 0, stderr_tail: String::new(), + probe_line: None, }; for mutation in [ MutationVerdict::NotAttempted { From be51ccffe1b832e0a7075ed45ff382cf4fc325c7 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Thu, 27 Aug 2026 07:50:49 +0000 Subject: [PATCH 5/9] Render the probe manifest's [features] section from the modeled authority Every roster entry's baseline returned status=101 in CI while returning status=0 locally. The emitted v1_rt.rs gates on #[cfg(feature = "text_lookup_work_counter")]; the probe manifest declared no [features] section; and a crate referencing a feature it does not declare earns unexpected_cfgs, which is a WARNING locally and a hard ERROR under CI's RUSTFLAGS=-D warnings. So the phase reported a red on every entry that had nothing to do with the emitted closure. The corpus already carried this finding. gunbc.self_host_logic_behavioral_transport slb_cargo_features_note records the same exit=101 and the same mechanism, and predicts the general case in as many words: any -D-warnings consumer of a gunbc-emitted crate breaks the same way because the emitted Cargo.toml omits the block. This phase is that consumer. The section is rendered from stage0_partition_row_features and render_stage0_crate_features_section -- the authority the partition crates already use -- rather than from a third hand-concatenated [features] string beside the two the corpus carries. Verified under CI's own condition rather than the default: with RUSTFLAGS="-D warnings", all 8 entries report baseline Completed status=0 and mutation Discriminated with the probe line quoted, RC=0. The five verification arms all passed before this fix; none of them could have caught it, because none ran with the flags the required lane sets. Co-Authored-By: Claude Opus 5 (1M context) --- .../src/emitted_closure_compile_host.rs | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/v1/stage0/src/emitted_closure_compile_host.rs b/src/v1/stage0/src/emitted_closure_compile_host.rs index 7a8f232cc5d..66bbc296e64 100644 --- a/src/v1/stage0/src/emitted_closure_compile_host.rs +++ b/src/v1/stage0/src/emitted_closure_compile_host.rs @@ -43,8 +43,12 @@ use super::{ }; use crate::extdeps_cargo::{CargoDepSource, CargoDependency}; use crate::extdeps_cargo_version::render_cargo_package_header_prefix; +use crate::gunbc_stage0_crate_partition_generated::{ + GeneratedPartitionCrateKind, GeneratedPartitionCrateRow, +}; use crate::v1_compiler_stage0_crates::{ - render_stage0_crate_dep, stage0_foundation_runtime_dependencies, + render_stage0_crate_dep, render_stage0_crate_features_section, + stage0_foundation_runtime_dependencies, stage0_partition_row_features, }; const REQUIRED_EMIT_COMPILE_ENTRIES_DATA_NAME: &str = "required_emit_compile_entries"; @@ -339,8 +343,35 @@ fn probe_manifest(workspace: &Path, entry: &str) -> String { .map(|dep| render_stage0_crate_dep(std::rc::Rc::new(dep))) .collect::>() .join(""); + // THE FEATURE SECTION IS NOT OPTIONAL, AND CI IS WHERE ITS ABSENCE BITES. + // + // The emitted `v1_rt.rs` gates on `#[cfg(feature = "text_lookup_work_counter")]`. A crate + // that references a feature it does not declare earns the `unexpected_cfgs` lint, which is a + // WARNING locally and a hard ERROR under CI's `RUSTFLAGS=-D warnings` — so the probe crate + // compiled clean on a workstation and failed `status=101` on every entry in CI, with the + // baseline arm reporting a red that had nothing to do with the emitted closure. + // + // Rendered from the same modeled authority the partition crates use + // (`stage0_partition_row_features` / `render_stage0_crate_features_section`) rather than + // authored here: the corpus already carries two hand-concatenated `[features]` blocks for + // exactly this reason, each with a note explaining the failure, and adding a third string + // would be the second representation those notes are evidence against. + let features = render_stage0_crate_features_section(stage0_partition_row_features( + std::rc::Rc::new(GeneratedPartitionCrateRow { + package_name: probe_package_name(entry), + crate_dir: String::new(), + // The foundation kind is the one that carries the feature the emitted `v1_rt.rs` + // gates on, and the emitted closure always contains `v1_rt`. + kind: GeneratedPartitionCrateKind::GeneratedFoundationCrate, + // `im::Vector`, not `std::Vec`: the generated row's list fields are the corpus + // `List`, which that module aliases to `im::Vector`. + modules: std::rc::Rc::new(im::Vector::new()), + reexport_packages: std::rc::Rc::new(im::Vector::new()), + carries_non_empty_wrappers: false, + }), + )); format!( - "{}\nedition = \"2021\"\n\n[dependencies]\n{rendered}", + "{}\nedition = \"2021\"\n{features}\n[dependencies]\n{rendered}", render_cargo_package_header_prefix(probe_package_name(entry)) ) } From 6b11b502533b0d92f6b64ef95e21cb80d5759910 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Thu, 27 Aug 2026 08:51:50 +0000 Subject: [PATCH 6/9] Root the probe under RUNNER_TEMP, split EACCES from a live peer, adjudicate restore first Three defects, two of them found by the gate's own first real runs. THE ROOT WAS HOST-SHARED. probe_root() was a fixed path in the system temp dir. On a self-hosted runner /tmp persists across runs, slots and tenants, so the directory already existed owned by another uid and the lock returned EACCES. The phase refused permanently -- red on every future PR landing on that runner, with the only closing move being someone deleting a directory over SSH. A required gate whose sole remedy is manual host intervention outside the repository has no reachable green. RUNNER_TEMP is per-job and owned by the process that needs it, and it changes nothing the shared target dir buys: one run's entries still share workspace/target, and per-entry package names still separate them within it. A LIVE PEER AND AN UNWRITABLE ROOT ARE OPPOSITE REMEDIES. AlreadyExists said "investigate a concurrent run" and every other errno fell into one catch-all, so EACCES rendered as that message's neighbour and sent a reader hunting a peer that did not exist. They are now separate refusals; the second names the path and says the root is wrong. The lock's own rationale is narrowed with it: under a per-job root, concurrent collision is closed by construction, so what the lock still catches is an attempt in THIS job that died mid-flight. RESTORE IS ADJUDICATED BEFORE EVERY FAULT VERDICT. The fault arms return NotDiscriminating, which fails one entry and lets siblings continue; only RestoreFailed ends the run. Deciding the fault first therefore swallowed a terminal failure whenever both conditions held at once, and a later baseline could run against a tree whose state nobody established. The byte half is adjudicated first because it is free; whether the restored tree compiles stays below the fault verdicts, being a question about attributing a red the arm has already declined to claim. A test pins the ORDER rather than the arms, because both orders typecheck and only one is safe. The build lane's step name no longer enumerates phases. It read "(regen, v2 emission)" while the lane carried four, and a session triaging a red narrowed to the two it named and could not reach the one that failed. The run announces its own roster before any phase executes; the label points there. Verified under the lane's own conditions: RUNNER_TEMP set and RUSTFLAGS="-D warnings", all entries baseline Completed status=0 and mutation Discriminated, RC=0, crates written under RUNNER_TEMP. The EACCES arm executed separately against an unwritable root returns its own refusal naming the path. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/witnesses.yml | 2 +- dag/gunbc/witness_floor_workflow.dag | 13 +- .../src/emitted_closure_compile_host.rs | 138 +++++++++++++++--- 3 files changed, 132 insertions(+), 21 deletions(-) diff --git a/.github/workflows/witnesses.yml b/.github/workflows/witnesses.yml index 17fd293a022..5bfa8fa756e 100644 --- a/.github/workflows/witnesses.yml +++ b/.github/workflows/witnesses.yml @@ -65,7 +65,7 @@ jobs: rustup toolchain list || echo "rustup toolchain list: no answer" rustup default || echo "rustup default: no answer" if: "!cancelled()" - - name: "Required CI: build lane (regen, v2 emission)" + - name: "Required CI: build lane (phases named by the run, not by this label)" run: | ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) cd "$ROOT" diff --git a/dag/gunbc/witness_floor_workflow.dag b/dag/gunbc/witness_floor_workflow.dag index b06a240baa7..14fbdfe5559 100644 --- a/dag/gunbc/witness_floor_workflow.dag +++ b/dag/gunbc/witness_floor_workflow.dag @@ -563,9 +563,18 @@ fn witness_toolchain_environment_probe_step() -> Step { // THE BUILD LANE'S RUN STEP. Same binary, same mode, same source roots, one word different -- // which is the whole point of the lane being a parameter rather than a second invocation. +// +// THE STEP NAME DOES NOT ENUMERATE THE PHASES, AND THAT IS A CORRECTION RATHER THAN VAGUENESS. +// It read "(regen, v2 emission)" while the lane carried four, because a label listing a roster +// is a TRANSCRIPTION of something the run itself prints -- and it drifts silently every time the +// roster grows, which it has done three times in a week. The cost is not cosmetic: a session +// triaging a red step narrowed to the two phases the label named and could not reach the third, +// which was the one that failed. DESIGN's standing rule is to name the instrument and never +// transcribe its output; the instrument here is the required mode itself, which announces one +// `phase ` line per phase the lane owns before any of them runs. Read the roster there. fn build_lane_run_step() -> Step { RunStep { - name: Present { value: "Required CI: build lane (regen, v2 emission)" }, + name: Present { value: "Required CI: build lane (phases named by the run, not by this label)" }, id: none, run: build_lane_run_script(), shell: none, @@ -925,7 +934,7 @@ fn build_lane_bound_steps() -> List { WitnessFloorBoundStep { step: build_lane_run_step(), role: consumes_only(capabilities: [RustfmtCapability]), - step_name: "Required CI: build lane (regen, v2 emission)", + step_name: "Required CI: build lane (phases named by the run, not by this label)", }, ], ) diff --git a/src/v1/stage0/src/emitted_closure_compile_host.rs b/src/v1/stage0/src/emitted_closure_compile_host.rs index 66bbc296e64..b6c7a460a6e 100644 --- a/src/v1/stage0/src/emitted_closure_compile_host.rs +++ b/src/v1/stage0/src/emitted_closure_compile_host.rs @@ -379,8 +379,27 @@ fn probe_manifest(workspace: &Path, entry: &str) -> String { /// Where one entry's probe crate is written. Outside the repository deliberately: a crate under /// the workspace root is inferred into the workspace by cargo and would have to declare its own /// `[workspace]` to escape, which is a manifest fact invented to work around its own location. +/// +/// RUNNER-SCOPED, NOT HOST-SHARED, AND THIS WAS MEASURED THE HARD WAY. A fixed path in the host's +/// `/tmp` is shared by every tenant of a SELF-HOSTED runner and persists across runs, slots and +/// jobs. On the first required run the directory already existed there owned by another uid, so +/// creating the lock inside it returned `EACCES` and the phase refused — permanently, on every +/// subsequent PR landing on that runner, with the only closing move being someone deleting a +/// directory over SSH. A required gate whose sole remedy is manual host intervention outside the +/// repository has no reachable green, which is the shape DESIGN records for a gate that launders +/// rather than gates. +/// +/// `RUNNER_TEMP` is created and torn down per job and owned by the process that needs it, so two +/// tenants no longer name one path. It changes nothing the shared target directory buys: the +/// entries of ONE run still share `workspace/target`, and per-entry package names still separate +/// their fingerprints within it. fn probe_root() -> PathBuf { - std::env::temp_dir().join("gunbc-emit-compile") + let base = std::env::var("RUNNER_TEMP") + .ok() + .filter(|value| !value.is_empty()) + .map(PathBuf::from) + .unwrap_or_else(std::env::temp_dir); + base.join("gunbc-emit-compile") } fn probe_crate_dir(entry: &str) -> PathBuf { @@ -555,6 +574,35 @@ fn establish_discriminating_red( let restore_write = std::fs::write(&path, &original); let restored_bytes = std::fs::read_to_string(&path).unwrap_or_default(); + // RESTORATION IS ADJUDICATED BEFORE ANY FAULT VERDICT, AND THE ORDER IS THE WHOLE POINT. + // + // Every fault-verdict arm below returns `NotDiscriminating`, which fails this entry and lets + // SIBLINGS CONTINUE. `RestoreFailed` is the only verdict that ends the run. So if the restore + // failed at the same moment the fault arm was green, incomplete, or unattributed, deciding + // the fault first would report the non-terminal verdict and swallow the terminal one — and + // the next entry's baseline would then run against a target directory whose state nobody + // established, which is exactly the unattributable measurement the terminal rule exists to + // prevent. The two conditions are independent, so they co-occur; whichever is checked first + // wins, and only one of them is safe to lose. + // + // The BYTE half is adjudicated here because it is a filesystem fact, already in hand and + // free. Whether the RESTORED TREE COMPILES stays below the fault verdicts deliberately: it + // costs a third cargo invocation, and it is a question about attributing THIS entry's red, + // which is moot once the arm has already refused to claim one. + if let Err(e) = restore_write { + return MutationVerdict::RestoreFailed { + detail: format!("restoring {}: {e}", path.display()), + }; + } + if restored_bytes != original { + return MutationVerdict::RestoreFailed { + detail: format!( + "{} did not return to its emitted bytes after the fault was removed", + path.display() + ), + }; + } + // THE FAULTED ARM MUST HAVE COMPLETED, AND ITS RED MUST BE ATTRIBUTABLE TO THE FAULT. // // A NONZERO EXIT IS NOT EVIDENCE ON ITS OWN, which is the hole this block closes. Cargo can @@ -619,19 +667,6 @@ fn establish_discriminating_red( }; let attributed = attributed.to_string(); - if let Err(e) = restore_write { - return MutationVerdict::RestoreFailed { - detail: format!("restoring {}: {e}", path.display()), - }; - } - if restored_bytes != original { - return MutationVerdict::RestoreFailed { - detail: format!( - "{} did not return to its emitted bytes after the fault was removed", - path.display() - ), - }; - } let restored = run_cargo(crate_dir, workspace); if !cargo_verdict_compiled(&restored) { return MutationVerdict::RestoreFailed { @@ -954,7 +989,15 @@ pub fn emit_compile_report( (lines, retention_error) } -/// TWO CONCURRENT RUNS IN ONE WORKSPACE CORRUPT EACH OTHER'S EVIDENCE, SO THE SECOND REFUSES. +/// A ROOT WHOSE LAST WRITER DIED IS NOT A ROOT TO SILENTLY BUILD ON, SO A SECOND HOLDER REFUSES. +/// +/// WHAT THIS LOCK IS FOR HAS NARROWED, and saying so matters because the argument below was +/// written for the wider case. Under a per-job `RUNNER_TEMP` root two CONCURRENT runs cannot +/// collide by construction — there is no path they both name — so the lock is no longer the +/// mechanism preventing interleaving in CI. What it still catches is a previous attempt in THIS +/// job that died mid-flight, and a local run started beside another when the root falls back to a +/// shared temp dir. Both are cases where the tree's state is unestablished, which is the thing +/// worth refusing on. /// /// The arms deliberately share one probe root and one cargo target directory — that is what makes /// the baseline warm and the restore comparable. It also means two runs interleave: one run's @@ -974,8 +1017,14 @@ pub fn emit_compile_report( /// typed and located, and the operator sees that two runs were attempted rather than receiving a /// verdict computed across both. fn acquire_probe_root_lock(root: &Path) -> Result { - std::fs::create_dir_all(root) - .map_err(|e| format!("could not create the probe root {}: {e}", root.display()))?; + std::fs::create_dir_all(root).map_err(|e| { + format!( + "could not create the probe root {} ({e}) — the root is derived from RUNNER_TEMP \ + when set and the system temp dir otherwise; a host-shared temp dir on a \ + self-hosted runner can already hold this path owned by another tenant", + root.display() + ) + })?; let lock = root.join("emit-compile.lock"); match std::fs::OpenOptions::new() .write(true) @@ -989,6 +1038,19 @@ fn acquire_probe_root_lock(root: &Path) -> Result { Remove the lock only after establishing no other run is live.", lock.display() )), + // A LIVE PEER AND AN UNWRITABLE ROOT ARE OPPOSITE REMEDIES, so they are opposite + // refusals. `AlreadyExists` says wait or investigate a concurrent run; `PermissionDenied` + // says this process cannot write here at all and the ROOT is wrong — nobody should go + // looking for a peer that does not exist. Collapsing the two is the state-space + // conflation DESIGN names, and it cost a triage cycle when the catch-all string sent a + // reader hunting a concurrent run on a runner that had none. + Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => Err(format!( + "the probe root {} is not writable by this process ({e}) — this is NOT a concurrent \ + run; the root itself is wrong. It is derived from RUNNER_TEMP when set and the \ + system temp dir otherwise, and a host-shared temp dir on a self-hosted runner can \ + already hold this path owned by another tenant.", + root.display() + )), Err(e) => Err(format!("could not take {}: {e}", lock.display())), } } @@ -1069,8 +1131,18 @@ mod tests { #[test] fn manifest_carries_the_modeled_dependency_rows() { let manifest = probe_manifest(Path::new("/repo"), "dag/std/logic.dag"); - assert!(manifest.starts_with("[package]\nname = \"gunbc-emitted-closure\"")); + // The package name is DERIVED PER ENTRY, so two entries cannot alias each other's cargo + // fingerprints in the shared target directory. + assert!( + manifest.starts_with("[package]\nname = \"gunbc-emitted-closure-dag-std-logic-dag\"") + ); assert!(manifest.contains("edition = \"2021\"")); + // THE FEATURE SECTION IS A REGRESSION GUARD, not decoration: the emitted `v1_rt.rs` gates + // on this feature, and a crate referencing a feature it does not declare compiles clean + // locally and fails under the required lane's `RUSTFLAGS=-D warnings`. Its absence is + // therefore invisible to every default-flag run, which is how it reached CI once. + assert!(manifest.contains("[features]")); + assert!(manifest.contains("text_lookup_work_counter = []")); for name in ["im", "serde", "serde_json", "stacker"] { assert!(manifest.contains(name), "missing dependency row {name}"); } @@ -1128,6 +1200,36 @@ mod tests { /// EVERY NON-`Discriminated` MUTATION ARM FAILS THE PHASE. Stated as a test because the /// tempting weakening -- treating the mutation as advisory beside a green baseline -- is /// exactly what would turn this phase into the decoration it exists not to be. + /// A FAILED RESTORE MUST WIN OVER EVERY NON-TERMINAL FAULT VERDICT. + /// + /// The two conditions are independent and therefore co-occur: the fault arm can be green, + /// incomplete or unattributed at the same moment the restore fails. Only `RestoreFailed` + /// ends the run; every `NotDiscriminating` arm lets siblings continue against a tree whose + /// state nobody established. This pins the ORDER rather than the arms, because both orders + /// typecheck and only one is safe -- which is how the ordering was wrong to begin with. + #[test] + fn a_failed_restore_is_not_masked_by_a_non_terminal_fault_verdict() { + // The source order of the checks is the guarantee. Both restore adjudications must + // appear before the first fault-verdict return, or a masked terminal failure is + // reachable again. + let src = include_str!("emitted_closure_compile_host.rs"); + let body = &src[src + .find("fn establish_discriminating_red") + .expect("the function this test pins must exist")..]; + let first_restore = body + .find("MutationVerdict::RestoreFailed") + .expect("the restore adjudication must be present"); + let first_fault = body + .find("MutationVerdict::NotDiscriminating") + .expect("the fault verdicts must be present"); + assert!( + first_restore < first_fault, + "a RestoreFailed adjudication must precede every NotDiscriminating return: a \ + terminal failure returned after a non-terminal one is swallowed, and the run \ + continues against an unrestored tree" + ); + } + #[test] fn a_green_baseline_does_not_pass_without_the_discrimination() { let green = CargoVerdict::Completed { From b32ea8eead2494e90d517d0b35ebcea7f736c759 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Thu, 27 Aug 2026 10:27:14 +0000 Subject: [PATCH 7/9] Compose the probe root in exactly one place, and split the features authority by crate kind Two findings, both from review. ROOT SPELLED TWICE. When the probe root moved to `RUNNER_TEMP`, `emit_compile_report` was left re-deriving `std::env::temp_dir() .join("gunbc-emit-compile")` by hand, so the crate directories landed on the runner path while the retained remainder still went to the shared host `/tmp` -- the exact EACCES the reroot closed, reopened one line away from the fix. `emit_compile_report` now calls `probe_root()`, and `the_probe_root_name_is_composed_in_exactly_one_place` pins that there is one composition site. That test assembles its own needle with `format!` rather than writing the literal, because a literal in the test body is itself a second spelling and the first cut of the test failed by counting itself. Verified by execution under `RUNNER_TEMP=/tmp/rt-verify-final`: the remainder is retained at `/gunbc-emit-compile/ emit-compile-not-selected.txt` with 4075 identities, and `/tmp/gunbc-emit-compile` is not created at all. FEATURES AUTHORITY. The probe manifest needs the same `[features]` the generated foundation crate declares -- without it `unexpected_cfgs` is a warning locally and a hard error under CI's `-D warnings`, which is what put all 8 baselines at `status=101`. `v1.compiler.stage0_crates` now exposes `stage0_features_for_crate_kind`, and `stage0_partition_row_features` is derived from it, so the host reads the modeled authority instead of copying either of the two hand-authored feature strings that already existed in the tree. The stage0 mirror is the emitter's own candidate, installed rather than hand-written. Co-Authored-By: Claude Opus 5 (1M context) --- .../src/emitted_closure_compile_host.rs | 68 +++++++++++++------ .../stage0/src/v1_compiler_stage0_crates.rs | 12 +++- src/v1/stage0_crates.dag | 16 ++++- 3 files changed, 69 insertions(+), 27 deletions(-) diff --git a/src/v1/stage0/src/emitted_closure_compile_host.rs b/src/v1/stage0/src/emitted_closure_compile_host.rs index b6c7a460a6e..59701f5ea7d 100644 --- a/src/v1/stage0/src/emitted_closure_compile_host.rs +++ b/src/v1/stage0/src/emitted_closure_compile_host.rs @@ -43,12 +43,10 @@ use super::{ }; use crate::extdeps_cargo::{CargoDepSource, CargoDependency}; use crate::extdeps_cargo_version::render_cargo_package_header_prefix; -use crate::gunbc_stage0_crate_partition_generated::{ - GeneratedPartitionCrateKind, GeneratedPartitionCrateRow, -}; +use crate::gunbc_stage0_crate_partition_generated::GeneratedPartitionCrateKind; use crate::v1_compiler_stage0_crates::{ - render_stage0_crate_dep, render_stage0_crate_features_section, - stage0_foundation_runtime_dependencies, stage0_partition_row_features, + render_stage0_crate_dep, render_stage0_crate_features_section, stage0_features_for_crate_kind, + stage0_foundation_runtime_dependencies, }; const REQUIRED_EMIT_COMPILE_ENTRIES_DATA_NAME: &str = "required_emit_compile_entries"; @@ -356,19 +354,15 @@ fn probe_manifest(workspace: &Path, entry: &str) -> String { // authored here: the corpus already carries two hand-concatenated `[features]` blocks for // exactly this reason, each with a note explaining the failure, and adding a third string // would be the second representation those notes are evidence against. - let features = render_stage0_crate_features_section(stage0_partition_row_features( - std::rc::Rc::new(GeneratedPartitionCrateRow { - package_name: probe_package_name(entry), - crate_dir: String::new(), - // The foundation kind is the one that carries the feature the emitted `v1_rt.rs` - // gates on, and the emitted closure always contains `v1_rt`. - kind: GeneratedPartitionCrateKind::GeneratedFoundationCrate, - // `im::Vector`, not `std::Vec`: the generated row's list fields are the corpus - // `List`, which that module aliases to `im::Vector`. - modules: std::rc::Rc::new(im::Vector::new()), - reexport_packages: std::rc::Rc::new(im::Vector::new()), - carries_non_empty_wrappers: false, - }), + // THE KIND IS THE WHOLE SUBJECT, so the kind is what is passed. An earlier revision handed + // over a fabricated `GeneratedPartitionCrateRow` -- blank crate_dir, empty module lists -- + // to reach a function that reads `row.kind` and nothing else. That row was not merely + // wasteful: it ASSERTED this probe is a generated partition crate, which it is not. It is a + // per-entry crate written outside the repository, and the only thing it shares with a + // partition crate is needing the foundation kind's feature set, because the emitted + // `v1_rt.rs` gates on it. + let features = render_stage0_crate_features_section(stage0_features_for_crate_kind( + GeneratedPartitionCrateKind::GeneratedFoundationCrate, )); format!( "{}\nedition = \"2021\"\n{features}\n[dependencies]\n{rendered}", @@ -963,10 +957,14 @@ pub fn emit_compile_report( selection.not_selected.len(), emit_compile_selection_not_selected_digest(&selection), )); - let retained_dir = std::env::temp_dir() - .join("gunbc-emit-compile") - .to_string_lossy() - .to_string(); + // THROUGH `probe_root()`, NEVER BY RESPELLING IT. This line composed the directory name a + // second time, so when the root moved to `RUNNER_TEMP` one spelling was repaired and the + // other kept the old behaviour: in one run, the crate dirs were written under the runner's + // per-job temp while the retention file was still being written to the host-shared `/tmp`, + // where it hit the same `EACCES` the reroot existed to escape. Two homes for one fact is the + // §3 violation, and the tell was visible in the phase's own log as two different paths in + // adjacent lines. `probe_root()` is the authority; nothing else composes this name. + let retained_dir = probe_root().to_string_lossy().to_string(); let retention_error = match retain_not_selected_identities(&selection, &retained_dir) { Ok(path) => { lines.push(format!( @@ -1200,6 +1198,32 @@ mod tests { /// EVERY NON-`Discriminated` MUTATION ARM FAILS THE PHASE. Stated as a test because the /// tempting weakening -- treating the mutation as advisory beside a green baseline -- is /// exactly what would turn this phase into the decoration it exists not to be. + /// THE PROBE ROOT HAS EXACTLY ONE SPELLING. + /// + /// It had two. When the root moved to `RUNNER_TEMP`, the `probe_root()` authority was + /// repaired and a hand-composed copy inside the report was not, so one run wrote its crate + /// dirs under the runner's per-job temp and its retention file to the host-shared `/tmp` -- + /// where it hit the very `EACCES` the reroot existed to escape. The defect was not a missed + /// callsite; it was the directory name being a fact with two homes. + /// + /// So this pins the SPELLING rather than the behaviour: a second composition of the name is + /// exactly what a behavioural test would not catch, because both spellings are correct until + /// the authority moves. + #[test] + fn the_probe_root_name_is_composed_in_exactly_one_place() { + let src = include_str!("emitted_closure_compile_host.rs"); + // The needle is ASSEMBLED rather than written, because a literal one appears in this + // file the moment it is written down -- the test would then count itself and report two + // spellings where there is one. Caught by the test failing on its own text. + let needle = format!("join({:?})", "gunbc-emit-compile"); + let compositions = src.matches(needle.as_str()).count(); + assert_eq!( + compositions, 1, + "the probe root directory name must be composed only by probe_root(); a second \ + spelling silently keeps the old root when the authority moves" + ); + } + /// A FAILED RESTORE MUST WIN OVER EVERY NON-TERMINAL FAULT VERDICT. /// /// The two conditions are independent and therefore co-occur: the fault arm can be green, diff --git a/src/v1/stage0/src/v1_compiler_stage0_crates.rs b/src/v1/stage0/src/v1_compiler_stage0_crates.rs index cd62e7a291c..e433b14df47 100644 --- a/src/v1/stage0/src/v1_compiler_stage0_crates.rs +++ b/src/v1/stage0/src/v1_compiler_stage0_crates.rs @@ -637,10 +637,10 @@ pub fn stage0_partition_row_dependencies_outcome( } } -pub fn stage0_partition_row_features( - row: Rc, +pub fn stage0_features_for_crate_kind( + kind: GeneratedPartitionCrateKind, ) -> Rc>> { - match row.kind.clone() { + match kind.clone() { GeneratedPartitionCrateKind::GeneratedFoundationCrate => { Rc::new(vec![Rc::new(CargoFeature { name: "text_lookup_work_counter".to_string(), @@ -652,6 +652,12 @@ pub fn stage0_partition_row_features( } } +pub fn stage0_partition_row_features( + row: Rc, +) -> Rc>> { + stage0_features_for_crate_kind(row.kind.clone()) +} + pub fn stage0_partition_row_to_spec_outcome( row: Rc, ) -> Rc { diff --git a/src/v1/stage0_crates.dag b/src/v1/stage0_crates.dag index be20f0bc992..3bb3c4bcc01 100644 --- a/src/v1/stage0_crates.dag +++ b/src/v1/stage0_crates.dag @@ -10,6 +10,7 @@ import gunbc.stage0_crate_partition_generated { GeneratedEmitCoreCrate, GeneratedFoundationCrate, GeneratedLayeredCoreCrate, + GeneratedPartitionCrateKind, GeneratedPartitionCrateRow, generated_partition_crate_rows } @@ -316,14 +317,25 @@ fn stage0_partition_row_dependencies_outcome( } } -fn stage0_partition_row_features(row: GeneratedPartitionCrateRow) -> List { - match row.kind { +// THE FEATURE SET IS A FUNCTION OF THE CRATE KIND, and nothing else about a row decides it. +// Stated at that grain because a second consumer exists that is NOT a partition crate: the +// emitted-closure compile phase builds a per-entry probe crate outside the repository, and it +// needs the foundation kind's feature set because the emitted v1_rt.rs gates on it. Asking that +// consumer to hand over a GeneratedPartitionCrateRow would make it fabricate a row -- blank +// crate_dir, empty module list -- whose only true field is the one being read, and the fabricated +// row would ASSERT the probe is a generated partition crate, which it is not. +fn stage0_features_for_crate_kind(kind: GeneratedPartitionCrateKind) -> List { + match kind { GeneratedFoundationCrate => [CargoFeature { name: "text_lookup_work_counter", dependencies: [] }] GeneratedLayeredCoreCrate => [] GeneratedEmitCoreCrate => [] } } +fn stage0_partition_row_features(row: GeneratedPartitionCrateRow) -> List { + stage0_features_for_crate_kind(kind: row.kind) +} + fn stage0_partition_row_to_spec_outcome( row: GeneratedPartitionCrateRow ) -> Stage0PartitionRowSpecOutcome { From 7fa80cf02c09155223bc3898be81e3f62a6f7fae Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Thu, 27 Aug 2026 14:01:28 +0000 Subject: [PATCH 8/9] The features comment cited a symbol this code does not call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `stage0_partition_row_features` is real and live, so the citation did not dangle -- but the call below the comment is `stage0_features_for_crate_kind`, and a reader checking the comment against the code found the two disagreeing. A citation naming a symbol the code no longer reaches, sitting in the comment that explains a §3 single-authority repair, is the same class the repair was about. The comment now names what the call actually reaches and keeps the partition-row wrapper in its true relation to it: the rows reach the same authority THROUGH `stage0_partition_row_features`, which is why the two names both belong in the sentence and why only one of them belongs in the call. Found in review by smart-ram-730, who correctly judged it not worth a CI cycle on its own; it is folded in here rather than pushed alone. Co-Authored-By: Claude Opus 5 (1M context) --- src/v1/stage0/src/emitted_closure_compile_host.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/v1/stage0/src/emitted_closure_compile_host.rs b/src/v1/stage0/src/emitted_closure_compile_host.rs index 59701f5ea7d..d126d5f925f 100644 --- a/src/v1/stage0/src/emitted_closure_compile_host.rs +++ b/src/v1/stage0/src/emitted_closure_compile_host.rs @@ -349,8 +349,9 @@ fn probe_manifest(workspace: &Path, entry: &str) -> String { // compiled clean on a workstation and failed `status=101` on every entry in CI, with the // baseline arm reporting a red that had nothing to do with the emitted closure. // - // Rendered from the same modeled authority the partition crates use - // (`stage0_partition_row_features` / `render_stage0_crate_features_section`) rather than + // Rendered from the same modeled authority the partition crates use -- + // `stage0_features_for_crate_kind`, which is what the call below reaches and which the + // partition rows themselves reach through `stage0_partition_row_features` -- rather than // authored here: the corpus already carries two hand-concatenated `[features]` blocks for // exactly this reason, each with a note explaining the failure, and adding a third string // would be the second representation those notes are evidence against. From 430266933f088d4abbc74b0c21b63bf9a3a18d39 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Thu, 27 Aug 2026 14:37:54 +0000 Subject: [PATCH 9/9] The seed-growth receipt cited a symbol that resolves to nothing, and omitted 16 declarations review 56685 (REQUEST_CHANGES) is correct on both counts and the audit it prompted found the problem was larger than the two items it named. THE STALE CITATION. The roster carried `PROBE_PACKAGE_NAME`, which resolves to nothing anywhere in the tree. An earlier revision of the host carried a package-name CONSTANT; the cargo-fingerprint-aliasing repair replaced it with the per-entry function `probe_package_name`, and the receipt was not updated with the code. THE OMISSIONS. Rather than patch the two the review named, the whole roster was audited against the file. It carried 32 rows against 47 declarations: 1 stale and 16 unaccounted. Every one of the 16 was added by a LATER repair inside this same PR -- `probe_root`, the selection digests, `retain_not_selected_identities`, the `cargo_verdict_probe_line` attribution fix, and two tests -- each of which grew the file without growing its receipt. That is precisely the drift this carrier exists to catch, committed inside the carrier, and it made the PR's sole checkable receipt both inaccurate and incomplete. The review's verdict is the right one. The roster is now exact against the file: 47 rows, 47 declarations, zero stale, zero unaccounted, zero duplicates, verified by re-running the audit after the edit rather than by reading the diff. A note records why it drifted, and states the standing hazard plainly: this is a HAND ROSTER BESIDE ITS SUBJECT, so it can only be re-verified, never trusted. It will drift again on the next declaration added and nothing in the required run compares the two. Its dissolution is the v1-hand-queue-drain lane this obligation already names. Co-Authored-By: Claude Opus 5 (1M context) --- .../emitted_closure_compile_seed_growth.dag | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/dag/gunbc/emitted_closure_compile_seed_growth.dag b/dag/gunbc/emitted_closure_compile_seed_growth.dag index a5e8a8e1845..cda8c3a8835 100644 --- a/dag/gunbc/emitted_closure_compile_seed_growth.dag +++ b/dag/gunbc/emitted_closure_compile_seed_growth.dag @@ -9,28 +9,31 @@ import gunbc.seed_growth { SeedGrowthJustification } // the obligation it declares, rather than inside gunbc.seed_growth_admission, which owns the // ROSTER and the join and would otherwise accumulate every lane's rows in the module that // adjudicates them. -data emitted_closure_compile_seed_growth_note: String = "Seed-growth obligation for the host behind the required emit-compile phase.\n\nWHAT THE CHANGE IS. The v2-emission phase emits one entry's closure and stops at the emitter. Its own header in cli_run.rs enumerates what it therefore cannot see, and the first item is 'a rustc error in the emitted tree (nothing here compiles the emission)'. DESIGN's Building-&-checks section carries a declared rung drop headed 'A BLOCKING EMIT-STAGE DIAGNOSTIC CAN SIT ON MAIN INDEFINITELY WITH NO REQUIRED PHASE THAT FAILS', whose restoration trigger reads: this row retires when a required phase EMITS over a closure that reaches call sites -- the compile re-add on the queue the floor cut created. This host is that phase: same producer (compile_entry_emission), the emitted files written as a crate, cargo run over it.\n\nWHY IT IS NOT A SECOND EMITTER. The phase calls the SAME transaction the emission phase calls and adds one stage after it. A green there and a green here cannot be two facts about two emissions, which is exactly the property a separately-authored probe would have given up.\n\nWHY THE MANIFEST IS DERIVED AND NOT AUTHORED. The corpus already carries a hand-concatenated probe manifest (tools.self_host_curated_seed_linked_harness cssl_v1_compiled_probe_lib_cargo_toml), marked scaffold debt in its own module for being concat-authored TOML. Consuming it from a merge-blocking gate would have pinned that debt open on the required path, and authoring a second one would have been new scaffolding the operator declined on 2026-08-25. The manifest here is rendered from the modeled cargo authorities instead -- extdeps.rust.version render_cargo_package_header_prefix for the package header, v1.compiler.stage0_crates stage0_foundation_runtime_dependencies for the seed's own runtime dependency set, and render_stage0_crate_dep per row -- so no new markup is authored at all.\n\nNO IMPL BLOCK, AND THAT IS DELIBERATE. Every item in the file is a free function or a type, because an impl method has no DeclarationRef spelling -- std.decl_ref offers WholeDeclaration or NamedField and neither names a method on an impl block -- so methods would have grown the class gunbc.seed_growth_admission reports as seed_growth_uncitable_item_keys. v1_compiler.declaration_index took the same route for the same reason. Uncitable items added by this change: ZERO.\n\nHAND-ITEM DELTA: enumerated below rather than counted. src/v1/stage0/src/cli_run.rs adds no declaration -- one #[path] mod line and one re-export list -- and src/v1/stage0/src/bin/claim_executor.rs adds one variant to an existing exhaustive enum and one phase body inside an existing function; both dispositions are ExistingSeedItemModified, and listing them would net a modification into an addition census.\n\nWHAT THE EXECUTED EVIDENCE IS, because the seed's own unit tests are not it. The Rust suite was removed from CI on 2026-07-11, so nothing under #[cfg(test)] executes on the merge path and none of it may be cited as coverage. The executed evidence is the phase itself: establish_discriminating_red injects one type error into one emitted file on EVERY required run, requires it to fail alone, restores the bytes and requires the green back -- and a mutation that fails to go red is a PHASE FAILURE, not a note. That is DESIGN 4b's authorable-RED question answered by execution rather than by inspection, and it is why a green from this phase carries information that a bare cargo-exit-status phase would not." +data emitted_closure_compile_seed_growth_note: String = "Seed-growth obligation for the host behind the required emit-compile phase.\n\nWHAT THE CHANGE IS. The v2-emission phase emits one entry's closure and stops at the emitter. Its own header in cli_run.rs enumerates what it therefore cannot see, and the first item is 'a rustc error in the emitted tree (nothing here compiles the emission)'. DESIGN's Building-&-checks section carries a declared rung drop headed 'A BLOCKING EMIT-STAGE DIAGNOSTIC CAN SIT ON MAIN INDEFINITELY WITH NO REQUIRED PHASE THAT FAILS', whose restoration trigger reads: this row retires when a required phase EMITS over a closure that reaches call sites -- the compile re-add on the queue the floor cut created. This host is that phase: same producer (compile_entry_emission), the emitted files written as a crate, cargo run over it.\n\nWHY IT IS NOT A SECOND EMITTER. The phase calls the SAME transaction the emission phase calls and adds one stage after it. A green there and a green here cannot be two facts about two emissions, which is exactly the property a separately-authored probe would have given up.\n\nWHY THE MANIFEST IS DERIVED AND NOT AUTHORED. The corpus already carries a hand-concatenated probe manifest (tools.self_host_curated_seed_linked_harness cssl_v1_compiled_probe_lib_cargo_toml), marked scaffold debt in its own module for being concat-authored TOML. Consuming it from a merge-blocking gate would have pinned that debt open on the required path, and authoring a second one would have been new scaffolding the operator declined on 2026-08-25. The manifest here is rendered from the modeled cargo authorities instead -- extdeps.rust.version render_cargo_package_header_prefix for the package header, v1.compiler.stage0_crates stage0_foundation_runtime_dependencies for the seed's own runtime dependency set, and render_stage0_crate_dep per row -- so no new markup is authored at all.\n\nNO IMPL BLOCK, AND THAT IS DELIBERATE. Every item in the file is a free function or a type, because an impl method has no DeclarationRef spelling -- std.decl_ref offers WholeDeclaration or NamedField and neither names a method on an impl block -- so methods would have grown the class gunbc.seed_growth_admission reports as seed_growth_uncitable_item_keys. v1_compiler.declaration_index took the same route for the same reason. Uncitable items added by this change: ZERO.\n\nHAND-ITEM DELTA: enumerated below rather than counted. src/v1/stage0/src/cli_run.rs adds no declaration -- one #[path] mod line and one re-export list -- and src/v1/stage0/src/bin/claim_executor.rs adds one variant to an existing exhaustive enum and one phase body inside an existing function; both dispositions are ExistingSeedItemModified, and listing them would net a modification into an addition census.\n\nWHY THIS ROSTER DRIFTED ONCE, RECORDED SO IT IS NOT REPEATED. Review 56685 found it citing PROBE_PACKAGE_NAME, which resolves to nothing: an earlier revision carried a package-name CONSTANT, the cargo-fingerprint-aliasing repair replaced it with the per-entry function probe_package_name, and the receipt was not updated with the code. An audit of the whole roster then found 1 stale name and 16 unaccounted declarations -- every one of the 16 added by a LATER repair in this same PR (probe_root, the selection digests, retention, the probe-line attribution fix, two tests), each of which grew the file without growing its receipt. That is the exact failure the carrier exists to catch, committed inside the carrier. The roster is now exact against the file: 47 rows, 47 declarations, zero stale, zero unaccounted. THE STANDING HAZARD IS THAT IT IS A HAND ROSTER BESIDE ITS SUBJECT, so it can only be re-verified, never trusted: it drifts silently on the next declaration added, and nothing in the required run compares the two. Its dissolution is the same v1-hand-queue-drain lane this obligation already names.\n\nWHAT THE EXECUTED EVIDENCE IS, because the seed's own unit tests are not it. The Rust suite was removed from CI on 2026-07-11, so nothing under #[cfg(test)] executes on the merge path and none of it may be cited as coverage. The executed evidence is the phase itself: establish_discriminating_red injects one type error into one emitted file on EVERY required run, requires it to fail alone, restores the bytes and requires the green back -- and a mutation that fails to go red is a PHASE FAILURE, not a note. That is DESIGN 4b's authorable-RED question answered by execution rather than by inspection, and it is why a green from this phase carries information that a bare cargo-exit-status phase would not." data emitted_closure_compile_seed_growth_justification: SeedGrowthJustification = SeedGrowthJustification { hand_authored_declarations: [ DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "REQUIRED_EMIT_COMPILE_ENTRIES_DATA_NAME", field: WholeDeclaration }, - DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "PROBE_PACKAGE_NAME", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "probe_package_name", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "MUTATION_PROBE_SYMBOL", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "MUTATION_ITEM", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "required_emit_compile_entries", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "CargoVerdict", field: WholeDeclaration }, - DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "MutationSubject", field: WholeDeclaration }, - DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "MutationVerdict", field: WholeDeclaration }, - DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "EmitCompileOutcome", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "cargo_verdict_compiled", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "cargo_verdict_summary", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "cargo_verdict_probe_line", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "cargo_verdict_stderr_tail", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "MutationSubject", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "mutation_subject_rust_module", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "mutation_subject_name", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "MutationVerdict", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "mutation_verdict_discriminated", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "mutation_verdict_summary", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "EmitCompileOutcome", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "emit_compile_outcome_passed", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "emit_compile_outcome_summary", field: WholeDeclaration }, - DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "required_emit_compile_entries", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "probe_manifest", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "probe_root", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "probe_crate_dir", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "write_probe_crate", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "run_cargo", field: WholeDeclaration }, @@ -39,12 +42,24 @@ data emitted_closure_compile_seed_growth_justification: SeedGrowthJustification DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "establish_discriminating_red", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "entry_rust_module", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "run_emit_compile_entry", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "emit_compile_modules_reached", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "EmitCompileSelection", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "digest_of_identities", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "emit_compile_selection", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "emit_compile_selection_universe_digest", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "emit_compile_selection_selected_digest", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "emit_compile_selection_not_selected_digest", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "retain_not_selected_identities", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "emit_compile_report", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "acquire_probe_root_lock", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "run_required_emit_compile", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "manifest_carries_the_modeled_dependency_rows", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "mutation_prefers_a_closure_member_over_the_entry", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "mutation_falls_back_to_the_entry_and_names_it", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "an_unreached_entry_is_not_a_pass", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "the_probe_root_name_is_composed_in_exactly_one_place", field: WholeDeclaration }, + DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "a_failed_restore_is_not_masked_by_a_non_terminal_fault_verdict", field: WholeDeclaration }, DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "a_green_baseline_does_not_pass_without_the_discrimination", field: WholeDeclaration }, - DeclarationRef { module_path: "v1_compiler.emitted_closure_compile_host", decl_name: "an_unreached_entry_is_not_a_pass", field: WholeDeclaration } ], reason: "WHY RUST IS STILL NEEDED, and it is a REACHABILITY limit rather than a modeling gap. The subject is a required CI phase: it must run inside claim_executor, which is the only witness-executing consumer in the tree, and its stages are host effects -- writing an emitted tree to disk and spawning cargo over it. The required floor's hermetic envelope REFUSES host effects during preparation, so a .dag witness whose subject is a subprocess exit status is counted executed while its assertion never runs; DESIGN's Building-&-checks section records that boundary in as many words, and records that mocking the refusal would pass the witness against a fabricated exit status. So the phase has to live where the effects do, exactly as required_regen_host and partition_crate_boundary_host do.\n\nWHY IT IS ADMITTED AGAINST THE v1 FREEZE, ON PRECEDENT RATHER THAN ANALOGY. gunbc.v1_maintenance_standing v1_seed_standing admits a change by PURPOSE -- does it serve the v2 self-host program -- and the purpose test reaches the INSTRUMENT that measures that program, not only the program. This is that instrument in the most direct available sense: the self-host claim IS that the emitted tree compiles and behaves, and until now nothing on the merge path compiled an emitted tree at all. gunbc.floor_non_verdict_enrollment and gunbc.declaration_index_seed_growth are both admitted on that same footing. Classified against the five refused classes: NewLanguageBehavior -- no, the compile pipeline is byte-untouched, no diagnostic is added, moved or removed. NewCompatibilityObligation -- no, nothing is kept working for an old caller. NewEscapeHatchOrAdmissionRow -- no, and the direction is opposite: this adds a wall and adds no flag, env var or mode that skips it. SeedFeatureCompletion -- no, the seed compiler gains no capability; it compiles exactly what it compiled before. PublicSurfaceGrowth -- the nearest, and the test is a diff over THE EMITTED SEED'S EXPORTED DECLARATIONS: the file is wired by #[path] mod inside cli_run.rs exactly as declaration_index.rs, phase_profile.rs and partition_crate_boundary_host.rs are, so it contributes no pub mod line to the emitted lib.rs and its SeedRetainedIntrinsicRegistration carries has_pub_mod: false.\n\nWHAT IS NOT CLAIMED. This phase is not a compile of the corpus and must not be read as one: gunbc.whole_corpus_compile_admission refuses a whole-bundle compile on the default runner and records two EXIT=137 kills behind that refusal, so the subject is a bounded roster of entries in gunbc.ci_layer_roots required_emit_compile_entries. It carries no diagnostic count, no baseline and no ratchet -- a merge-blocking comparison against a population measured on the current tree is the tree-copied oracle DESIGN 5 rejects.", owning_dissolution_lane: "v1-hand-queue-drain" as RoadmapNodeId,