Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions .github/workflows/witnesses.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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 }}
Expand Down
1 change: 1 addition & 0 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
28 changes: 4 additions & 24 deletions dag/gunbc/required_lanes_gate.dag
Original file line number Diff line number Diff line change
Expand Up @@ -212,30 +212,23 @@ 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<Node> {
[
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)
]
),
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)
Expand Down Expand Up @@ -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
Expand All @@ -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="),
Expand All @@ -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 {
Expand All @@ -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="),
Expand Down Expand Up @@ -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
Expand All @@ -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
),
Expand All @@ -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
),
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
)
)
Expand All @@ -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
Expand All @@ -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
Expand Down
8 changes: 8 additions & 0 deletions dag/gunbc/rung_drop.dag
Original file line number Diff line number Diff line change
Expand Up @@ -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<RungDrop> = [
floor_cut,
measurement_bankruptcy,
Expand All @@ -94,4 +101,5 @@ data rung_drop_roster: List<RungDrop> = [
emit_stage_blocking,
lens_enforcement_censuses,
required_gate_bankruptcy,
fabric_evidence_gating,
]
14 changes: 10 additions & 4 deletions dag/gunbc/witness/witness_floor_workflow.dag
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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,
Expand Down Expand Up @@ -1657,7 +1655,6 @@ fn required_lanes_aggregate_step_env() -> List<YamlKeyValue> {
[
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())),
Expand All @@ -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() },
Expand Down
Loading
Loading