From 64d8cd9111a8901f55d5dff5425cdb3c212f5120 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 31 Aug 2026 03:49:58 +0000 Subject: [PATCH 1/4] CI-10MIN: withdraw fabric-evidence from the required aggregate under a declared 4b rung drop The required context 'witnesses' waits on the MAX of its needs, and on run 33350499023 that max was fabric-evidence at 27 minutes (build 10.5, floor 20). 1469s of its 1620s is the calibration step, whose ~18 gunbc host processes each re-parse and re-census the whole 4414-module corpus to evaluate a handful of rows -- the instrument's own import closure is six modules. The job keeps running on every push and pull request; only its needs edge and its FABRIC_EVIDENCE binding into the verdict fold are withdrawn, declared in gunbc.rung_drop fabric_evidence_gating with the capability that retires it. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01XXrkS4YTtkTPhEqvfSsefS --- dag/gunbc/required_lanes_gate.dag | 28 +++---------------- dag/gunbc/rung_drop.dag | 8 ++++++ dag/gunbc/witness/witness_floor_workflow.dag | 14 +++++++--- ...or_workflow_consolidation_witness_test.dag | 27 ++++++++++++------ 4 files changed, 41 insertions(+), 36 deletions(-) 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 e961b6b5ae0..29c63f934d7 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. 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 9ff60b4a55c..8cfd17f4b99 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..fcfa4c094e9 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 `required_ci_fabric_evidence_lane` 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 } } From b16f38b895331467803e1b82d6736c445b3b43fa Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 31 Aug 2026 03:52:20 +0000 Subject: [PATCH 2/4] rung_drop: record the explicit-check obligation the withdrawn needs edge creates warm-seal-35 accepted the drop on the basis that FABRIC-CI checks fabric-evidence directly rather than inferring its health from the required context. That is a cost of the drop and belongs in its reasoning, not only in the thread where it was agreed. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01XXrkS4YTtkTPhEqvfSsefS --- dag/gunbc/rung_drop.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dag/gunbc/rung_drop.dag b/dag/gunbc/rung_drop.dag index 29c63f934d7..cb5a68e3ae8 100644 --- a/dag/gunbc/rung_drop.dag +++ b/dag/gunbc/rung_drop.dag @@ -90,7 +90,7 @@ 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. 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." + 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 = [ From 5d2c0198204fcc31c83b2e0479cc517a93f0839f Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 31 Aug 2026 06:48:10 +0000 Subject: [PATCH 3/4] Regenerate the derived artifacts for the fabric-evidence gating withdrawal Produced by the sanctioned route, not hand-edited: gunbc run --source-root dag --source-root src/v2 --entry dag/gunbc/instruments/generated_artifact_gate.dag --function main_wet witnesses.yml loses the fabric-evidence needs edge, the FABRIC_EVIDENCE env binding and the three verdict-fold clauses that read it. The fabric-evidence JOB and its calibration step are untouched. DESIGN.md and design-ledgers.md gain the declared rung drop row. main_wet had to run locally: it peaks at 7.55 GiB RSS and the BuildBuddy runner VM is 7.86 GB total, so it is SIGKILLed there (RUN_EXIT=137) at any GUNBC_MEMORY_BUDGET_BYTES setting. Run under a 24 GiB ulimit -v per operator authorization. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01XXrkS4YTtkTPhEqvfSsefS --- .github/workflows/witnesses.yml | 13 ++++++------- DESIGN.md | 1 + docs/design-ledgers.md | 4 ++++ 3 files changed, 11 insertions(+), 7 deletions(-) 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 8ebd9330a18..2f6efe364b4 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -117,6 +117,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/docs/design-ledgers.md b/docs/design-ledgers.md index cac3b285bf9..6b38af08b78 100644 --- a/docs/design-ledgers.md +++ b/docs/design-ledgers.md @@ -64,3 +64,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. From 09a37a7f18ce8e7bf9287834bf839d494c54fb56 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 31 Aug 2026 06:54:58 +0000 Subject: [PATCH 4/4] Correct the rung-drop citation in the replacement witness The comment cited gunbc.rung_drop `required_ci_fabric_evidence_lane`, which does not exist; the declared authority is `fabric_evidence_gating`. Raised in review 57771. No generated artifact changes: this is a test-claim module and the edit is inside a // annotation, which DESIGN 4c erases before every semantic pass. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01XXrkS4YTtkTPhEqvfSsefS --- .../claim/witness_floor_workflow_consolidation_witness_test.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fcfa4c094e9..02f1a0953cd 100644 --- a/dag/test/claim/witness_floor_workflow_consolidation_witness_test.dag +++ b/dag/test/claim/witness_floor_workflow_consolidation_witness_test.dag @@ -242,7 +242,7 @@ test fn w_RED_neither_lane_waits_on_the_other() -> 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 `required_ci_fabric_evidence_lane` withdraws. That row is not +// 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.