fix(ci): the first build runs the disk precondition the rest already do - #987
Conversation
Measured 2026-09-02: the session's first `install:local` died inside `cargo build --release` on ENOSPC with 0MB free, over a `target/debug` a previous session had left at ~24GB. The failure named neither the disk nor the floor, and the recovery an agent reaches for from there is `rm -rf target/…` by hand — the journal-poisoning route CLOUD-1218 measured three times. `target-prune` exists for exactly that input; its own header says it runs when the disk is SHORT. `verify` calls it and every `land` lap calls it. The one build that runs before any of them did not, so every build the repository owns sat behind the precondition except the first. A `depends` rather than a guarded body call, and §5 is the reason: the refusal a reader should see is the prune's own pointer-only line naming free space and the floor. A body guard prints a second message over the first, which is a second authority for a verdict already rendered. `install:local` resolves it transitively and so gains the precondition without naming it. Three properties checked rather than assumed, each written where the next reader will be. `target-prune` declares no `depends` and tries the installed binary before `cargo run`, so the edge cannot cycle. This task is reached by `install:local` and the two benches while `verify` and `land` reach the engine through `cargo run -p batten`, so the prune pair bracketing a lap keeps its order. And `prune::Phase` is derived from the lap journal rather than declared, so a build outside a `verify` toggles a boundary — which cannot move the floor, a high-water mark, but can emit one `lap-close` describing no real lap. Shown able to fail by hand, because no sweep can carry it: `mutate::sources_for` resolves a gate to a shell task, a rego module, an engine module or a preset directory, and this subject is `mise.toml`, which is none of them. A `//MUTANT` row would read as coverage and apply nothing. With the `depends` line deleted and nothing else changed, both new cases went red and the anti-vacuity mirror stayed green; restoring it returned the suite to green. The demonstration is recorded on the case. Refs: CLOUD-1329
… mention `task_surface` concatenates `run` and `depends` because the reachability scan wants both and does not care which one a name came from. Asserting a DEPENDENCY over that concatenation proves nothing: delete the `depends` line and write `run = "echo target-prune && cargo build …"` and the `contains` assertion stays green over a build that runs no precondition at all — the shape CLOUD-418 names, a case that cannot tell the defect from its absence. So split the extraction into `task_block` / `task_value`, one pair shared by both readers so there is no second authority to drift, and add `task_depends` reading `depends` alone and splitting it into entries. The three cases now ask for an EXACT entry rather than a substring of the whole surface. Refs: CLOUD-1329
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository: button-inc/batten/.coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe release build task now depends on
Priority: ⬇️ Low Merge Risk: ⚪ Minimal · up to The release build now runs the disk-reclaim prerequisite first, with tests guarding the dependency edge and cycle-free task graph. No merge-blocking issue remains. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
3b5129d to
6b88311
Compare
|
/fast-forward |
Closes CLOUD-1329
What moved
[tasks."build:release"]gainsdepends = ["target-prune"].Measured 2026-09-02: the session's first
install:localdied insidecargo build --releaseonENOSPCwith 0MB free, over atarget/debuga previous session hadleft at ~24GB.
target-pruneexists for exactly that input — its own header says it"runs when the disk is SHORT" — and
verifyand everylandlap call it. This entrypoint, which runs before any of them, did not. The failure surfaced as a cargo IO
error naming neither the disk nor the floor.
Why
dependsrather than a guarded call in the bodyHouse-style §5: the refusal a reader should see is
target-prune's own pointer-onlyline, naming free space and the floor. A body guard would print a second message over
the first — a second authority for a verdict the prune already rendered.
dependsruns it before the body and propagates its exit verbatim.
install:localresolves ittransitively, so it gains the precondition without naming it.
No cycle, checked rather than assumed:
target-prunedeclares nodependsof itsown, and its body tries the installed binary before falling back to
cargo run—precisely so the reclaim needs no build in order to run. It does not reach inside
verify's lap: this task's callers areinstall:localand the two benches, whileverify,verify:gatedandlandreach the engine throughcargo run -p battendirectly, so the two prune calls that bracket a lap keep their order.
The gate
Three cases in
crates/batten/tests/it/session_provisioning.rsask for an exactdependency entry, not a substring of the task surface. The distinction is the whole
point and was caught in review on the first draft:
task_surfaceconcatenatesrunand
depends, socontains("target-prune")stays green overrun = "echo target-prune && cargo build …"with nodependsat all — a case thatcannot tell the defect from its absence (CLOUD-418). So
task_dependsreadsdependsalone and splits it into entries, sharing one
task_block/task_valuepair withtask_surfaceso there is no second extraction to drift.The anti-vacuity mirror stays: the reclaim itself declares no dependency (which is
what makes the no-cycle claim checkable rather than asserted), and both surfaces are
non-empty, so an extractor that silently read nothing would fail rather than pass.
mise run verifygreen;mise run test:cargoexits 0.