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
1 change: 1 addition & 0 deletions .github/workflows/fleet-desired.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jobs:
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1.16.0
with:
components: rustfmt
cache: false
- name: Build the admission binary
run: |
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/witnesses.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
- name: Install Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1.16.0
with:
components: rustfmt
cache: false
- name: Build the witness fold
id: build_witness_fold
Expand Down
42 changes: 38 additions & 4 deletions dag/gunbc/witness_floor_workflow.dag
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module gunbc.witness_floor_workflow

import extdeps.languages.yaml.types { yaml_string, yaml_int, yaml_bool, kv }
import gunbc.roadmap_execution_contract { CargoCapability }
import gunbc.roadmap_execution_contract { CargoCapability, RustfmtCapability }
import gunbc.workflow_capability_closure {
CapabilityAnnotatedStep,
StepCapabilityRole,
Expand Down Expand Up @@ -187,13 +187,36 @@ fn witness_floor_checkout_step() -> Step {
// becomes a disk-pressure question instead of a correctness one. That is the right trade —
// a full disk refuses loudly, a deleted source file mid-compile does not — but it is a real
// obligation and it belongs to whoever owns fleet disk, not to this file.
// THIS STEP ASKS FOR rustfmt EXPLICITLY, and the reason is a measured incident rather than
// tidiness. Without the components key it installs a toolchain and takes whatever the runner's
// resolved default happens to carry -- so the job passes on a runner whose default has rustfmt
// and fails on one whose default does not, with no relationship to the diff under test.
//
// Observed 2026-08-22 on gunbc#8860: `required-ci: FAILED PHASE regen refused: normalize
// candidate wt_b.rs: spawn rustfmt: No such file or directory (os error 2)`, while the witness
// floor in the same run passed 10130/10130 with failed=0. The regen phase writes the emitted
// artifact as a FIXED POINT of the formatter, so it must spawn rustfmt; nothing in this
// workflow had asked for it.
//
// THE OBVIOUS READING OF THAT ERROR IS WRONG AND THIS REPOSITORY ALREADY PAID TO LEARN IT.
// `gunbc.host_toolchain_components` `toolchain_completeness_authority_note` records the same
// error on the same host class 2026-07-25: rustfmt WAS present on the machine, the job
// principal simply had two rustup toolchains and defaulted to the one without it. A COMPONENT
// IS A PROPERTY OF A TOOLCHAIN, NOT OF A MACHINE, so "install rustfmt on that host" converges
// green while the gate keeps failing. The fix belongs in what this workflow ASKS FOR.
//
// `gunbc.fleet_workflow_steps` `ci_setup_rust_step` already passes this same key to this same
// action; this step was the one that did not.
fn witness_floor_toolchain_step() -> Step {
UsesStep {
name: Present { value: "Install Rust toolchain" },
id: none,
uses: setup_rust_action,
with: Present {
value: [kv(key: "cache", value: yaml_bool(b: false))]
value: [
kv(key: "components", value: yaml_string(s: "rustfmt")),
kv(key: "cache", value: yaml_bool(b: false)),
]
},
env: none,
if_condition: none,
Expand Down Expand Up @@ -396,6 +419,17 @@ type WitnessFloorBoundStep {
step_name: String
}

// THE RUN STEP WAS DECLARED `capability_neutral` AND THAT DECLARATION WAS FALSE. It runs
// `claim_executor --required-ci`, whose regen phase spawns rustfmt to normalize the emitted
// mirror, so it consumes RustfmtCapability and now says so.
//
// A step that consumes a capability while declaring it consumes none is invisible to the
// closure check BY CONSTRUCTION: the check was honest and had nothing to catch, because the
// consumer said it consumed nothing. That is why the failure surfaced as a runner lottery
// instead of as a refusal.
//
// Cargo is deliberately NOT listed on the run step: it invokes a prebuilt binary and does not
// shell out to cargo. Listing it would trade one false declaration for another.
fn witness_floor_bound_steps() -> List<WitnessFloorBoundStep> {
[
WitnessFloorBoundStep {
Expand All @@ -405,7 +439,7 @@ fn witness_floor_bound_steps() -> List<WitnessFloorBoundStep> {
},
WitnessFloorBoundStep {
step: witness_floor_toolchain_step(),
role: provides_only(capabilities: [CargoCapability]),
role: provides_only(capabilities: [CargoCapability, RustfmtCapability]),
step_name: "Install Rust toolchain",
},
WitnessFloorBoundStep {
Expand All @@ -415,7 +449,7 @@ fn witness_floor_bound_steps() -> List<WitnessFloorBoundStep> {
},
WitnessFloorBoundStep {
step: witness_floor_run_step(),
role: capability_neutral,
role: consumes_only(capabilities: [RustfmtCapability]),
step_name: "All witnesses (one prepared subject, one fold)",
},
]
Expand Down