diff --git a/.github/workflows/witnesses.yml b/.github/workflows/witnesses.yml index abb50886cff..6419a1aa6a4 100644 --- a/.github/workflows/witnesses.yml +++ b/.github/workflows/witnesses.yml @@ -224,7 +224,7 @@ jobs: timeout-minutes: 55 witnesses: runs-on: [self-hosted, linux, arm64] - needs: [required-witnesses-build, required-witnesses-floor, fabric-evidence] + needs: [required-witnesses-build, required-witnesses-floor] timeout-minutes: 5 if: always() steps: @@ -234,17 +234,16 @@ jobs: if '[' "$EVENT_NAME" '=' 'pull_request' ']'; then HEAD_STANDING='unobserved'; fi 'echo' 'required floor attempt: pull_request='"$PULL_REQUEST"' measured_head='"$MEASURED_HEAD"' run_id='"$RUN_ID"' head_standing='"$HEAD_STANDING" VERDICT='stands-green' - if '[' "$BUILD" '!=' 'success' ']' || '[' "$FLOOR" '!=' 'success' ']' || '[' "$FABRIC_EVIDENCE" '!=' 'success' ']'; then VERDICT='stands-unestablished'; fi - if '[' "$BUILD" '=' 'failure' ']' || '[' "$FLOOR" '=' 'failure' ']' || '[' "$FABRIC_EVIDENCE" '=' 'failure' ']'; then VERDICT='stands-red'; fi + if '[' "$BUILD" '!=' 'success' ']' || '[' "$FLOOR" '!=' 'success' ']'; then VERDICT='stands-unestablished'; fi + if '[' "$BUILD" '=' 'failure' ']' || '[' "$FLOOR" '=' 'failure' ']'; then VERDICT='stands-red'; fi MECHANISM='unestablished' ATTRIBUTION='unestablished' - 'echo' 'required lanes: build='"$BUILD"' floor='"$FLOOR"' fabric='"$FABRIC_EVIDENCE"' verdict='"$VERDICT"' mechanism='"$MECHANISM"' attribution='"$ATTRIBUTION" - if '[' "$VERDICT" '=' 'stands-red' ']'; then 'echo' '::error::a required lane concluded failure; that alone does not establish whether its subject was evaluated, so read the log before assuming a defect in the diff (build='"$BUILD"' floor='"$FLOOR"' fabric='"$FABRIC_EVIDENCE"' mechanism='"$MECHANISM"' attribution='"$ATTRIBUTION"') - open that job'\''s log' >&2; exit 1; fi - if '[' "$VERDICT" '=' 'stands-unestablished' ']'; then 'echo' '::error::a required lane produced no conclusion of its own, so this head'\''s floor verdict is unobservable rather than failed; rerun it (build='"$BUILD"' floor='"$FLOOR"' fabric='"$FABRIC_EVIDENCE"' mechanism='"$MECHANISM"' attribution='"$ATTRIBUTION"') - open that job'\''s log' >&2; exit 1; fi + 'echo' 'required lanes: build='"$BUILD"' floor='"$FLOOR"' verdict='"$VERDICT"' mechanism='"$MECHANISM"' attribution='"$ATTRIBUTION" + if '[' "$VERDICT" '=' 'stands-red' ']'; then 'echo' '::error::a required lane concluded failure; that alone does not establish whether its subject was evaluated, so read the log before assuming a defect in the diff (build='"$BUILD"' floor='"$FLOOR"' mechanism='"$MECHANISM"' attribution='"$ATTRIBUTION"') - open that job'\''s log' >&2; exit 1; fi + if '[' "$VERDICT" '=' 'stands-unestablished' ']'; then 'echo' '::error::a required lane produced no conclusion of its own, so this head'\''s floor verdict is unobservable rather than failed; rerun it (build='"$BUILD"' floor='"$FLOOR"' mechanism='"$MECHANISM"' attribution='"$ATTRIBUTION"') - open that job'\''s log' >&2; exit 1; fi env: BUILD: ${{ needs['required-witnesses-build'].result }} FLOOR: ${{ needs['required-witnesses-floor'].result }} - FABRIC_EVIDENCE: ${{ needs['fabric-evidence'].result }} PULL_REQUEST: ${{ github.event.pull_request.number }} EVENT_NAME: ${{ github.event_name }} MEASURED_HEAD: ${{ github.event.pull_request.head.sha }} diff --git a/DESIGN.md b/DESIGN.md index 7f9e15686a3..b2e4435602a 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -121,6 +121,7 @@ Every newly discovered error class — incident, review finding, runtime excepti - **Blocking emit-stage diagnostics on main** — declared 2026-08-25 - **Corpus-wide lens enforcement censuses** — declared 2026-08-11 - **Required gate reduced to the compiler floor** — declared 2026-08-29 +- **Fabric CI evidence lane as a required merge block** — declared 2026-08-31 **The floor first, the differentiator above it.** gunbc must first hold the ordinary compiler floor — names resolve, applications bind in exact bijection, values inhabit declared types, fields exist, closed variants eliminate exhaustively — and a failure there is a below-baseline safety regression, never compensated by higher-order capability. The differentiating claim begins above that floor: because the substrate carries causal, cardinality, algebraic, effect, ownership, cost, and realization facts structurally, the same ladder applies to classes ordinary compilers leave to tests, review, profiling, or production postmortems — a possibly-empty collection flowing into a nonempty consumer, recursion without a descent proof, a non-idempotent effect under automatic retry, a computation exceeding its declared complexity bound, a realization that does not preserve modeled behavior. diff --git a/dag/gunbc/required_lanes_gate.dag b/dag/gunbc/required_lanes_gate.dag index 274d21a8508..0c3c26c647f 100644 --- a/dag/gunbc/required_lanes_gate.dag +++ b/dag/gunbc/required_lanes_gate.dag @@ -212,18 +212,14 @@ fn required_lane_is_failure_test(var_name: String) -> Node { fn required_lanes_verdict_stmts( build_var: String, floor_var: String, - fabric_var: String, verdict_var: String ) -> List { [ bash_build_assign_lit(name: verdict_var, text: floor_rendered_verdict_green_name), bash_build_if_from_stmts( cond: bash_build_or_else( - left: bash_build_or_else( - left: required_lane_not_success_test(var_name: build_var), - right: required_lane_not_success_test(var_name: floor_var) - ), - right: required_lane_not_success_test(var_name: fabric_var) + left: required_lane_not_success_test(var_name: build_var), + right: required_lane_not_success_test(var_name: floor_var) ), then_stmts: [ bash_build_assign_lit(name: verdict_var, text: floor_rendered_verdict_unestablished_name) @@ -231,11 +227,8 @@ fn required_lanes_verdict_stmts( ), bash_build_if_from_stmts( cond: bash_build_or_else( - left: bash_build_or_else( - left: required_lane_is_failure_test(var_name: build_var), - right: required_lane_is_failure_test(var_name: floor_var) - ), - right: required_lane_is_failure_test(var_name: fabric_var) + left: required_lane_is_failure_test(var_name: build_var), + right: required_lane_is_failure_test(var_name: floor_var) ), then_stmts: [ bash_build_assign_lit(name: verdict_var, text: floor_rendered_verdict_red_name) @@ -276,7 +269,6 @@ fn required_lanes_interruption_stmts( fn required_lanes_verdict_receipt_stmt( build_var: String, floor_var: String, - fabric_var: String, verdict_var: String, mechanism_var: String, attribution_var: String @@ -290,8 +282,6 @@ fn required_lanes_verdict_receipt_stmt( bash_build_word_var(name: build_var), bash_build_word_lit(text: " floor="), bash_build_word_var(name: floor_var), - bash_build_word_lit(text: " fabric="), - bash_build_word_var(name: fabric_var), bash_build_word_lit(text: " verdict="), bash_build_word_var(name: verdict_var), bash_build_word_lit(text: " mechanism="), @@ -308,7 +298,6 @@ fn required_lanes_error_stmt( text: String, build_var: String, floor_var: String, - fabric_var: String, mechanism_var: String, attribution_var: String ) -> Node { @@ -322,8 +311,6 @@ fn required_lanes_error_stmt( bash_build_word_var(name: build_var), bash_build_word_lit(text: " floor="), bash_build_word_var(name: floor_var), - bash_build_word_lit(text: " fabric="), - bash_build_word_var(name: fabric_var), bash_build_word_lit(text: " mechanism="), bash_build_word_var(name: mechanism_var), bash_build_word_lit(text: " attribution="), @@ -356,7 +343,6 @@ fn required_lanes_error_stmt( fn required_lanes_refusal_stmts( build_var: String, floor_var: String, - fabric_var: String, verdict_var: String, mechanism_var: String, attribution_var: String @@ -372,7 +358,6 @@ fn required_lanes_refusal_stmts( text: "::error::a required lane concluded failure; that alone does not establish whether its subject was evaluated, so read the log before assuming a defect in the diff (build=", build_var: build_var, floor_var: floor_var, - fabric_var: fabric_var, mechanism_var: mechanism_var, attribution_var: attribution_var ), @@ -389,7 +374,6 @@ fn required_lanes_refusal_stmts( text: "::error::a required lane produced no conclusion of its own, so this head's floor verdict is unobservable rather than failed; rerun it (build=", build_var: build_var, floor_var: floor_var, - fabric_var: fabric_var, mechanism_var: mechanism_var, attribution_var: attribution_var ), @@ -435,7 +419,6 @@ fn required_lanes_refusal_stmts( fn required_lanes_gate_stmts( build_var: String, floor_var: String, - fabric_var: String, pull_request_var: String, event_name_var: String, measured_head_var: String, @@ -468,7 +451,6 @@ fn required_lanes_gate_stmts( right: required_lanes_verdict_stmts( build_var: build_var, floor_var: floor_var, - fabric_var: fabric_var, verdict_var: verdict_var ) ) @@ -485,7 +467,6 @@ fn required_lanes_gate_stmts( required_lanes_verdict_receipt_stmt( build_var: build_var, floor_var: floor_var, - fabric_var: fabric_var, verdict_var: verdict_var, mechanism_var: mechanism_var, attribution_var: attribution_var @@ -497,7 +478,6 @@ fn required_lanes_gate_stmts( right: required_lanes_refusal_stmts( build_var: build_var, floor_var: floor_var, - fabric_var: fabric_var, verdict_var: verdict_var, mechanism_var: mechanism_var, attribution_var: attribution_var diff --git a/dag/gunbc/rung_drop.dag b/dag/gunbc/rung_drop.dag index 0608741fe38..5fed1444d3a 100644 --- a/dag/gunbc/rung_drop.dag +++ b/dag/gunbc/rung_drop.dag @@ -86,6 +86,13 @@ data required_gate_bankruptcy: RungDrop = RungDrop { authored: "**RUNG DROP, DECLARED (2026-08-29, the CI bankruptcy, operator ruling in session neat-tern-658).** PREVIOUS RUNG: mechanically preventable for every class the required run carried -- eight phases over two lanes, the floor folding every discovered witness (11,996 on the last green run) through a whole-corpus strict preparation, plus v2-emission, emit-compile, partition-crates and generated-artifact drift. TEMPORARY RUNG: mechanically preventable ONLY for what the static gate names -- parse, namespace-wave-admission, regen, and a floor over `v2.workflow.required_floor` `required_gate_prefixes` prepared as that roster's import closure -- and MITIGATABLE for everything else: those witnesses and phases are still runnable (the floor with the gate widened, `claim_executor --required-v2-emission`, `--required-emit-compile`, `--required-partition-crates`, `--required-generated-artifact`) and their receipts are produced only when someone runs them, so a regression there is caught at the next manual run, not at merge. REASON: the last green run was 87 wall minutes (`gh run view 33140387402`), strict preparation alone 27 of them on one core, against ~50 squash-merges a day; main sat red for fifteen consecutive runs on two integration collisions no PR could have seen (#9662), and the CI-cost lane's change-denominated selection did not land in time to prevent it. A gate no merge can wait for validates nothing, which is a lower rung than a small gate that runs. POPULATION: every witness outside the roster (reported per run as `declined_outside_required_gate` in the disposition TSV), the four deleted required phases, and the v1-compiler lib tests that carry the `live-corpus` ignore reason -- enumerated by `cargo test -p v1-compiler --lib -- --ignored --list` -- each of which prepares or builds over the live tree and is run only by the receipts lane; the first-ever CI run of `cargo test -p v1-compiler --lib` (run 33238828500) was cancelled by its own 60-minute timeout with 204 of 682 tests finished, which is how that class was measured into existence. The workflow's two-lane shape, the aggregate context, and the per-claim cost receipt are unchanged, and the drop is countable from that receipt every run. RESTORATION TRIGGER: the CAPABILITY of a required run whose population is DERIVED from the change -- the roadmap's 'decide what matters before paying to prepare everything' -- executing on the required path with the whole corpus as its universe; a widening of the static roster does not retire this row, it only moves the population. Widening the roster is a wall-clock decision priced by the cost receipt and recorded on the roster's own header." } +data fabric_evidence_gating: RungDrop = RungDrop { + identity: "fabric_evidence_gating" as NonEmptyStr, + subject: "Fabric CI evidence lane as a required merge block", + declared: "2026-08-31", + authored: "**THE FABRIC-CI EVIDENCE LANE STOPS BLOCKING MERGES AND KEEPS EXECUTING (2026-08-31).** #9704 added `fabric-evidence` as a fourth job and, in the same change, made it a `needs` of the aggregating `witnesses` job that the `passing CI` ruleset names as this repository's one required context. PREVIOUS RUNG: mechanically preventable — a defect in the FCI-EVIDENCE-0 run-boundary contract was exposed by an enrolled calibration and blocked the merge. TEMPORARY RUNG: mitigatable — the same calibration still runs on every push and pull request, still refuses loudly, and its log is still the record; what is gone is the block, so a red is now a signal a human must read rather than a wall. REASON, and it is wall clock rather than doubt about the evidence: the required context's wall is the MAX over its three lanes, and on run 33350499023 that max was `fabric-evidence` at 27 minutes against 20 for the floor lane and 10.5 for the build lane, having moved the required wall from ~13 minutes to ~28-40 within a day of #9704 landing. 1469 of those 1620 seconds are the calibration step, and its own logs put all ~18 of the plan's `gunbc run` host processes at 80-90 seconds each. That cost is not the evidence: the instrument's import closure is six modules, and per `cli_run.entry_resolve` an `--entry` run is scoped in what it EMITS but WHOLE-TREE in what it PARSES, so each process re-parses and re-censuses the entire 4414-module corpus to evaluate a handful of rows. The lane is paying eighteen whole-corpus censuses (DESIGN §2 duplicated work) for thirteen assertions. Batching them is NOT the repair and is not what this row defers: `gunbc.witness_floor_workflow` `fabric_ci_evidence_calibration_timeout_minutes` records that distinct host processes ARE the process-edge subject, so fewer processes would remove the boundary rather than observe it more cheaply. BOUNDED POPULATION: exactly one job, `fabric-evidence`, and exactly one lost edge — its `needs.fabric-evidence.result` binding into the aggregate's closed-vocabulary verdict fold. No other lane, phase, witness or claim changes rung; the build and floor lanes keep every edge they had, and the calibration keeps every assertion it had. The drop is countable from the emitted workflow: `test.claim.witness_floor_workflow_consolidation_witness_test` `w_RED_fabric_evidence_executes_without_gating` reds if the job stops executing, and reds again if either gating spelling returns while this row still stands. ONE OPERATIONAL CONSEQUENCE, recorded here because it is the kind of practice that quietly stops once the person who agreed to it moves on. With the needs edge withdrawn, a `fabric-evidence` failure no longer reaches the aggregate verdict, so any lane that was reading the required context as a proxy for that lane's health is now reading a context that cannot see it. The FABRIC-CI program (warm-seal-35) accepted the drop on that basis and will check `fabric-evidence` EXPLICITLY on every head rather than inferring it from `witnesses`. Anyone else joining on the required context owes the same explicit check for as long as this row stands; that obligation ends when the trigger below is met and not before. RESTORATION TRIGGER: the CAPABILITY of a single fabric evidence process resolving its entry against the source roots at a cost that fits the required wall budget — concretely, the whole-tree parse and name census being paid once per tree state rather than once per host process, so that the 13-row plan executes its full process-edge roster inside the lane's share of a ~10-minute required wall. THIS IS NOT RETIRED BY THE MEMO PR MERGING. It is retired by a measured `fabric-evidence` job wall that leaves the required context at or under its budget with the needs edge and the FABRIC_EVIDENCE binding restored, which is the only thing that makes the block affordable again. Reducing the plan's process count, relaxing what a row asserts, or moving the calibration to a cadence does not satisfy this trigger — the first removes the subject, and the other two are different drops that would need their own rows." +} + data rung_drop_roster: List = [ floor_cut, measurement_bankruptcy, @@ -94,4 +101,5 @@ data rung_drop_roster: List = [ emit_stage_blocking, lens_enforcement_censuses, required_gate_bankruptcy, + fabric_evidence_gating, ] diff --git a/dag/gunbc/witness/witness_floor_workflow.dag b/dag/gunbc/witness/witness_floor_workflow.dag index a6a2b6e9e59..4781962399b 100644 --- a/dag/gunbc/witness/witness_floor_workflow.dag +++ b/dag/gunbc/witness/witness_floor_workflow.dag @@ -1587,7 +1587,6 @@ fn required_lanes_run_id_expression() -> String { // all. A `Rejected` fold can therefore never reach a published step. data required_lanes_gate_build_var: String = "BUILD" data required_lanes_gate_floor_var: String = "FLOOR" -data required_lanes_gate_fabric_var: String = "FABRIC_EVIDENCE" data required_lanes_gate_pull_request_var: String = "PULL_REQUEST" data required_lanes_gate_event_name_var: String = "EVENT_NAME" data required_lanes_gate_measured_head_var: String = "MEASURED_HEAD" @@ -1602,7 +1601,6 @@ fn required_lanes_aggregate_script_outcome() -> String? { stmts: required_lanes_gate_stmts( build_var: required_lanes_gate_build_var, floor_var: required_lanes_gate_floor_var, - fabric_var: required_lanes_gate_fabric_var, pull_request_var: required_lanes_gate_pull_request_var, event_name_var: required_lanes_gate_event_name_var, measured_head_var: required_lanes_gate_measured_head_var, @@ -1657,7 +1655,6 @@ fn required_lanes_aggregate_step_env() -> List { [ kv(key: required_lanes_gate_build_var, value: yaml_string(s: required_lane_result_expression(job_id: build_lane_job_id))), kv(key: required_lanes_gate_floor_var, value: yaml_string(s: required_lane_result_expression(job_id: floor_lane_job_id))), - kv(key: required_lanes_gate_fabric_var, value: yaml_string(s: required_lane_result_expression(job_id: fabric_evidence_job_id))), kv(key: required_lanes_gate_pull_request_var, value: yaml_string(s: required_lanes_pull_request_expression())), kv(key: required_lanes_gate_event_name_var, value: yaml_string(s: required_lanes_event_name_expression())), kv(key: required_lanes_gate_measured_head_var, value: yaml_string(s: required_lanes_measured_head_expression())), @@ -1682,13 +1679,22 @@ fn required_lanes_aggregate_step() -> Step { // It checks out nothing, installs nothing and builds nothing: it reads two results. A five minute // bound is an order of magnitude above anything that can take, and stops a stuck aggregator from // holding a runner for the inherited six hours. +// +// TWO RESULTS AND NOT THREE, AND THE THIRD IS A DECLARED DROP RATHER THAN AN OVERSIGHT. #9704 made +// `fabric-evidence` a needs edge here and bound its result into the verdict fold. That edge is +// withdrawn under `gunbc.rung_drop` `fabric_evidence_gating`, which carries the measurement, the +// previous and temporary rungs, the bounded population and the restoration trigger. The JOB is +// untouched and still runs on every push and pull request; only its authority to block a merge is +// suspended. A reader who wants to restore the edge should read that row first, because the +// trigger it names is a capability -- one evidence process resolving its entry without re-paying +// the whole-tree census -- and not a pull request. fn required_lanes_aggregate_job() -> Job { Job { id: witness_floor_workflow_job_id, name: none, runner: gunbc_ci_selected_runner_spec(), steps: [required_lanes_aggregate_step()], - needs: [build_lane_job_id, floor_lane_job_id, fabric_evidence_job_id], + needs: [build_lane_job_id, floor_lane_job_id], env: none, outputs: none, if_condition: Present { value: required_lanes_aggregate_job_condition() }, diff --git a/dag/test/claim/witness_floor_workflow_consolidation_witness_test.dag b/dag/test/claim/witness_floor_workflow_consolidation_witness_test.dag index 556ae393705..02f1a0953cd 100644 --- a/dag/test/claim/witness_floor_workflow_consolidation_witness_test.dag +++ b/dag/test/claim/witness_floor_workflow_consolidation_witness_test.dag @@ -232,22 +232,33 @@ test fn w_RED_lane_contexts_collide_with_no_other_emitted_workflow() -> Bool { test fn w_RED_neither_lane_waits_on_the_other() -> Bool { match expected_witness_floor_yml() { WitnessFloorGenerated { content: yml } => - string_contains(s: yml, pattern: concat("needs: [", concat(build_lane_job_id, concat(", ", concat(floor_lane_job_id, concat(", ", concat(fabric_evidence_job_id, "]"))))))) + string_contains(s: yml, pattern: concat("needs: [", concat(build_lane_job_id, concat(", ", concat(floor_lane_job_id, "]"))))) && !string_contains(s: yml, pattern: concat("needs: [", concat(build_lane_job_id, "]"))) && !string_contains(s: yml, pattern: concat("needs: [", concat(floor_lane_job_id, "]"))) WitnessFloorGenerationRefused { reason: _ } => false } } -// The parallel fabric calibration is gating, not merely executing: its result is both a needs -// edge and an input to the same closed-vocabulary verdict fold. Deleting either half authors RED. -test fn w_RED_fabric_evidence_failure_reaches_required_context() -> Bool { +// THE FABRIC LANE STILL RUNS AND NO LONGER GATES, AND THIS ROW ASSERTS BOTH HALVES. +// +// It replaces w_RED_fabric_evidence_failure_reaches_required_context, whose subject was the +// gating edge that gunbc.rung_drop `fabric_evidence_gating` withdraws. That row is not +// retired as obsolete -- its subject is real and its restoration is the drop's trigger -- it is +// asserting a fact that is deliberately no longer true, so keeping it would have been a red +// against the declared state rather than evidence about it. +// +// What survives is the half the drop does NOT withdraw: the calibration keeps executing on every +// push and pull request, so the evidence stream is unbroken and only the merge block is gone. A +// diff that deletes the job to "finish" the drop authors RED here; so does one that restores the +// needs edge or the FABRIC_EVIDENCE binding without also retiring the drop, because the second +// and third conjuncts forbid exactly the two spellings the gating form emits. +test fn w_RED_fabric_evidence_executes_without_gating() -> Bool { match expected_witness_floor_yml() { WitnessFloorGenerated { content: yml } => - string_contains(s: yml, pattern: concat("needs: [", concat(build_lane_job_id, concat(", ", concat(floor_lane_job_id, concat(", ", concat(fabric_evidence_job_id, "]"))))))) - && string_contains(s: yml, pattern: "FABRIC_EVIDENCE: ${{ needs['fabric-evidence'].result }}") - && string_contains(s: yml, pattern: "\"$FABRIC_EVIDENCE\" '=' 'failure'") - && string_contains(s: yml, pattern: "fabric='\"$FABRIC_EVIDENCE\"") + string_contains(s: yml, pattern: concat(" ", concat(fabric_evidence_job_id, ":"))) + && string_contains(s: yml, pattern: "bash tools/fabric_ci_evidence_calibration.sh") + && !string_contains(s: yml, pattern: "FABRIC_EVIDENCE") + && !string_contains(s: yml, pattern: concat(", ", concat(fabric_evidence_job_id, "]"))) WitnessFloorGenerationRefused { reason: _ } => false } } diff --git a/docs/design-ledgers.md b/docs/design-ledgers.md index c009f6854f9..bf70dd98471 100644 --- a/docs/design-ledgers.md +++ b/docs/design-ledgers.md @@ -46,7 +46,21 @@ CI — **RUNG DROP, DECLARED (2026-08-15, the floor cut).** WHAT WAS HERE: one c ### Self-host emission board measurement — declared 2026-08-24 -**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/gunbc/instruments/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 MEASUREMENT BANKRUPTCY DELETED A CAPABILITY, NOT ONLY ARTIFACTS, AND THIS ROW IS THAT DECLARATION (2026-08-24).** The bankruptcy above removed `docs/probes/` whole. Deleting the boards removes TRANSCRIPTIONS, which is the point; deleting the instruments removes a ROUTE, which is a different fact and is the one §4b(3) obliges a cut to declare. WHAT IS GONE: the only executable route to a self-host emission board measurement. PREVIOUS STATE — any lane could re-derive a per-entry board by running the committed probe script, last exercised 2026-08-24 against the then-current main, and that reading is what answered the operator when they asked what the emission trajectory was doing. TEMPORARY STATE — no route exists; the emission trajectory is not measurable from the tree, and a board figure quoted from here on names nothing that can produce it. BOUNDED POPULATION: one capability, the per-entry emission board. RESTORATION TRIGGER: a `.dag` entry point that emits, assembles and compiles one entry and returns the coded-diagnostic population, cited by name wherever a board figure is quoted — at which point the same figures become legitimate again unchanged, because the rule forbids transcribing output INSTEAD OF naming an instrument, and the defect today is that there is no instrument to name. **WHY THIS ROW EXISTS AT ALL, and it is the same reason the regen row beneath it does:** no dependent could refuse. The corpus contains nothing that breaks when the board becomes unmeasurable, because the consumers are LANES rather than modules — the identical blind spot that made a `.dag`-consumer census report the instruments as dead a few hours before this cut. So delete-first's census, which is normally the thing that surfaces a load-bearing deletion loudly, is structurally silent here, and a declared row is the only mechanism left. **THE TRIGGER HAS FIRED, AND THE ROW STAYS AS HISTORICAL EVIDENCE OF THE LOST PER-ENTRY ROUTE.** The restored route is `tools.emission_entry_instrument` `measure_entry_emission`, invoked as `gunbc run --source-root dag --source-root src/v2 --entry dag/gunbc/instruments/emission_entry_instrument.dag --function measure --arg entry= --arg report=`. It emits one entry's closure, assembles it with `cssl_assemble`, compiles the assembled crate under cargo's JSON message format, and returns typed emit-stage and coded rustc diagnostic populations. `EmissionMeasurement` has no spelling in which an unreached stage renders as an empty reached stage, and its decode refuses inconsistent populations. **THE WHOLE-CORPUS PERSISTENCE THAT NOW CITES THIS HISTORY IS SEPARATE:** `gunbc.self_host_compile_phase_frontier` derives the compile-phase board from that instrument's `00_compile` closure observation, persists the linked identity-grain receipt series, and executes the phase/identity ratchet over its latest validated pair. Board standings quoted by the program status and design-ledger projection cite that frontier rather than this historical row. This does not turn the historical per-entry drop into the live board, and every figure copied into prose without naming its producer remains debt. + +### Whole-corpus compile-phase frontier receipts — latest validated row + +Milestones: parse PASSES / expand PASSES / resolve PASSES / typeck PASSES / borrowck PASSES + +Tree: `sha1:1c7c79fbc01aa488abb541513fc8ea44367406ad` + +Invocation: `buildbuddy-b779daaf-cefa-4379-ab27-dbea5a8d2919` + +Census identity digest: `ce69956ca7a9de96` + +Error identities: 233 total = 233 coded + 0 codeless + +Producer: `tools.emission_entry_instrument::measure_entry_emission` ### Regen candidate-tree producer — declared 2026-08-20 @@ -67,3 +81,7 @@ CI — **RUNG DROP, DECLARED (2026-08-15, the floor cut).** WHAT WAS HERE: one c ### Required gate reduced to the compiler floor — declared 2026-08-29 **RUNG DROP, DECLARED (2026-08-29, the CI bankruptcy, operator ruling in session neat-tern-658).** PREVIOUS RUNG: mechanically preventable for every class the required run carried -- eight phases over two lanes, the floor folding every discovered witness (11,996 on the last green run) through a whole-corpus strict preparation, plus v2-emission, emit-compile, partition-crates and generated-artifact drift. TEMPORARY RUNG: mechanically preventable ONLY for what the static gate names -- parse, namespace-wave-admission, regen, and a floor over `v2.workflow.required_floor` `required_gate_prefixes` prepared as that roster's import closure -- and MITIGATABLE for everything else: those witnesses and phases are still runnable (the floor with the gate widened, `claim_executor --required-v2-emission`, `--required-emit-compile`, `--required-partition-crates`, `--required-generated-artifact`) and their receipts are produced only when someone runs them, so a regression there is caught at the next manual run, not at merge. REASON: the last green run was 87 wall minutes (`gh run view 33140387402`), strict preparation alone 27 of them on one core, against ~50 squash-merges a day; main sat red for fifteen consecutive runs on two integration collisions no PR could have seen (#9662), and the CI-cost lane's change-denominated selection did not land in time to prevent it. A gate no merge can wait for validates nothing, which is a lower rung than a small gate that runs. POPULATION: every witness outside the roster (reported per run as `declined_outside_required_gate` in the disposition TSV), the four deleted required phases, and the v1-compiler lib tests that carry the `live-corpus` ignore reason -- enumerated by `cargo test -p v1-compiler --lib -- --ignored --list` -- each of which prepares or builds over the live tree and is run only by the receipts lane; the first-ever CI run of `cargo test -p v1-compiler --lib` (run 33238828500) was cancelled by its own 60-minute timeout with 204 of 682 tests finished, which is how that class was measured into existence. The workflow's two-lane shape, the aggregate context, and the per-claim cost receipt are unchanged, and the drop is countable from that receipt every run. RESTORATION TRIGGER: the CAPABILITY of a required run whose population is DERIVED from the change -- the roadmap's 'decide what matters before paying to prepare everything' -- executing on the required path with the whole corpus as its universe; a widening of the static roster does not retire this row, it only moves the population. Widening the roster is a wall-clock decision priced by the cost receipt and recorded on the roster's own header. + +### Fabric CI evidence lane as a required merge block — declared 2026-08-31 + +**THE FABRIC-CI EVIDENCE LANE STOPS BLOCKING MERGES AND KEEPS EXECUTING (2026-08-31).** #9704 added `fabric-evidence` as a fourth job and, in the same change, made it a `needs` of the aggregating `witnesses` job that the `passing CI` ruleset names as this repository's one required context. PREVIOUS RUNG: mechanically preventable — a defect in the FCI-EVIDENCE-0 run-boundary contract was exposed by an enrolled calibration and blocked the merge. TEMPORARY RUNG: mitigatable — the same calibration still runs on every push and pull request, still refuses loudly, and its log is still the record; what is gone is the block, so a red is now a signal a human must read rather than a wall. REASON, and it is wall clock rather than doubt about the evidence: the required context's wall is the MAX over its three lanes, and on run 33350499023 that max was `fabric-evidence` at 27 minutes against 20 for the floor lane and 10.5 for the build lane, having moved the required wall from ~13 minutes to ~28-40 within a day of #9704 landing. 1469 of those 1620 seconds are the calibration step, and its own logs put all ~18 of the plan's `gunbc run` host processes at 80-90 seconds each. That cost is not the evidence: the instrument's import closure is six modules, and per `cli_run.entry_resolve` an `--entry` run is scoped in what it EMITS but WHOLE-TREE in what it PARSES, so each process re-parses and re-censuses the entire 4414-module corpus to evaluate a handful of rows. The lane is paying eighteen whole-corpus censuses (DESIGN §2 duplicated work) for thirteen assertions. Batching them is NOT the repair and is not what this row defers: `gunbc.witness_floor_workflow` `fabric_ci_evidence_calibration_timeout_minutes` records that distinct host processes ARE the process-edge subject, so fewer processes would remove the boundary rather than observe it more cheaply. BOUNDED POPULATION: exactly one job, `fabric-evidence`, and exactly one lost edge — its `needs.fabric-evidence.result` binding into the aggregate's closed-vocabulary verdict fold. No other lane, phase, witness or claim changes rung; the build and floor lanes keep every edge they had, and the calibration keeps every assertion it had. The drop is countable from the emitted workflow: `test.claim.witness_floor_workflow_consolidation_witness_test` `w_RED_fabric_evidence_executes_without_gating` reds if the job stops executing, and reds again if either gating spelling returns while this row still stands. ONE OPERATIONAL CONSEQUENCE, recorded here because it is the kind of practice that quietly stops once the person who agreed to it moves on. With the needs edge withdrawn, a `fabric-evidence` failure no longer reaches the aggregate verdict, so any lane that was reading the required context as a proxy for that lane's health is now reading a context that cannot see it. The FABRIC-CI program (warm-seal-35) accepted the drop on that basis and will check `fabric-evidence` EXPLICITLY on every head rather than inferring it from `witnesses`. Anyone else joining on the required context owes the same explicit check for as long as this row stands; that obligation ends when the trigger below is met and not before. RESTORATION TRIGGER: the CAPABILITY of a single fabric evidence process resolving its entry against the source roots at a cost that fits the required wall budget — concretely, the whole-tree parse and name census being paid once per tree state rather than once per host process, so that the 13-row plan executes its full process-edge roster inside the lane's share of a ~10-minute required wall. THIS IS NOT RETIRED BY THE MEMO PR MERGING. It is retired by a measured `fabric-evidence` job wall that leaves the required context at or under its budget with the needs edge and the FABRIC_EVIDENCE binding restored, which is the only thing that makes the block affordable again. Reducing the plan's process count, relaxing what a row asserts, or moving the calibration to a cadence does not satisfy this trigger — the first removes the subject, and the other two are different drops that would need their own rows.