8.1 KiB
scripts/gate --protocol — the build its sweep depends on
Status: framing pass, revision 1. Pre-implementation. Awaiting approval.
A narrow lane, deliberately. One missing step in one script, plus
the boundary question that let it go missing. No feature work, no
src/, no protocol.
1. The defect
scripts/gate --protocol adds the CRDT workspace sweep. That sweep has
a documented precondition, and the script does not run it.
docs/agent-handoff.md §5 (:532-535):
The crdt sweep needs
cargo build --workspacefirst, or twelvegpu_invocation_acceptancetests fail on a missingpmacs-gpubinary.cargo build --workspace --no-default-features --features luajit,crdtis the invocation that produces both binaries.
scripts/gate's plan emitter (:187-204) goes
… → gpu → sweep → sweep-crdt → diff-check, with no build step
anywhere. Read from the source, not inferred from the failure.
Observed, not theorised. PR #228's first gate run failed step 09
with twelve gpu_invocation_acceptance::crdt::* failures, all
"build pmacs-gpu before this acceptance suite", and debug/pmacs-gpu
was absent from that worktree's target directory. Running the
documented invocation and re-running the gate turned it green.
2. Why it was latent until now, which is the interesting part
#225 caused this to become reachable, and #225 is also what makes it matter.
Before #225 every worktree on this machine resolved to one shared
CARGO_TARGET_DIR. That directory almost always already contained a
pmacs-gpu binary from some earlier build, so the precondition was
satisfied by accident on essentially every run. #225 gave each
worktree its own target directory; a fresh one starts empty, and the
omission becomes load-bearing on the very first --protocol run in a
new worktree.
So this is not "a bug #225 introduced". It is a pre-existing gap in
the documented procedure that #225 stopped hiding — and the reason it
is urgent rather than tidy is that the failure mode is not a red gate.
A red gate is fine; it stops you. The hazard is the reverse: a green
--protocol run whose crdt sweep was decided by what happened to be
in the build directory rather than by the diff. That is a gate that
reports coverage it does not have, which is precisely what #225 exists
to prevent.
3. The likely mechanism, marked as inference
The failing tests are namespaced gpu_invocation_acceptance::crdt::*,
which suggests they are feature-gated to crdt and therefore
compile and run only under the crdt sweep. That would explain why the
default sweep passes on a tree with no pmacs-gpu binary at all — it
never runs the tests that spawn it.
This is inference from the test names and one observation, and it is not yet verified. Q#GR-1 makes establishing it part of the work rather than an assumption the fix rests on.
4. The change
My vote: a named build-crdt gate step, emitted immediately before
sweep-crdt and only under --protocol, running the invocation
handoff §5 names.
- A named step, not a silent prelude. It appears in
--print-plan, gets its own numbered log alongside the others, and fails the suite with its own name if the build fails. - Not folded into the
sweep-crdtcommand.cargo build … && cargo test …would make a build failure appear under the namesweep-crdtin the failure list — a wrong attribution in the one place the script exists to be trustworthy about. - Only under
--protocol. If §3's inference holds, the default sweep does not need it, and adding an unconditional workspace build to every gate run is a real cost paid for nothing.
5. The boundary question, which is the durable half
The script's own header says:
docs/agent-handoff.mdsection 3 owns the REASONING for each of these …--print-planrenders this without running anything, which is what makes drift from section 3 testable.
The drift here is from §5, not §3 — and that is a coherent reason
for the omission rather than mere oversight. scripts/gate was written
against §3's gate policy; this precondition lives in §5's hazard
register, which the script never claimed to encode.
So the durable fix is not only the missing line. It is deciding where a requirement like this belongs, and making the script's stated contract match what it actually has to guarantee. My vote: §3 gains the precondition (it is gate policy — it decides whether a gate's result means anything), §5 keeps the incident and its signature, and the script's header stops naming §3 as its only source. Q#GR-3.
6. Open questions
Q#GR-1 — what exactly must be built, and does the default sweep need it too?
§5 names cargo build --workspace --no-default-features --features luajit,crdt and says it "produces both binaries". §3's inference says
the default sweep is unaffected. Neither is verified by this
document.
Required before implementation, by observation rather than reading:
delete pmacs-gpu from a target directory, run the default sweep,
and record whether it passes; then repeat for the crdt sweep. If the
default sweep also needs a binary, the step is unconditional and §4's
"only under --protocol" is wrong.
This is the one thing in this lane I would not accept on reasoning. The whole defect is a precondition nobody checked; establishing its replacement by reading would repeat the error at one remove.
Q#GR-2 — does a build failure fail the suite, or abort it?
My vote: fail like any other gate, and let the remaining steps
run. --no-fail-fast is the established posture of this suite, and a
sweep that then fails for the missing binary produces a second,
consistent signal rather than a mysterious absence.
The counter-argument is real: twelve downstream failures with a known
cause is noise. But the script already prints per-gate logs and a
FAILED: list, so the cause is named at the top, and suppressing
downstream output is how a tool starts deciding what its user is
allowed to see.
Q#GR-3 — where does this requirement live?
See §5. My vote: §3 gains it, §5 keeps the incident, the script's header cites both. The alternative — leave §5 as the only home and have the script silently encode it — reproduces exactly the condition that made this gap invisible.
Q#GR-4 — should --print-plan be asserted against the handoff?
Tempting and out of scope. A test that parses prose out of
agent-handoff.md and compares it to the plan would be brittle in the
direction that produces false confidence. Not in this lane, and
named so it is not mistaken for an oversight.
7. Verification
--print-plan --protocolemitsbuild-crdtimmediately beforesweep-crdt. Order asserted, not just presence: a build after the sweep it feeds is the same defect with an extra line.--print-planWITHOUT--protocoldoes not emit it (subject to Q#GR-1 — if the default sweep turns out to need the binary too, this assertion inverts and §4 changes with it).- A real fresh-target
--protocolrun goes green without a manual build, which is the acceptance criterion and the thing that was false. Witnessed on a target directory with nopmacs-gpuin it. - A failing build is attributed to
build-crdt, not tosweep-crdt(Q#GR-2) — the wrong-name case §4 rejects. - The existing 15
tests/gate_script_acceptance.rstests still pass, and the new assertions join them on the no-gates paths (--print-planruns nothing), keeping the suite cheap.
What this will NOT prove: that the plan matches the handoff in general (Q#GR-4), or that any other §5 hazard is encoded in the script — this lane fixes one and asks where such requirements belong, it does not audit §5.
8. Not in scope
Any feature work. Any src/ change. Auditing the rest of handoff §5
for further unencoded preconditions (worth doing; not here). A
plan-versus-handoff consistency test (Q#GR-4). Changing which gates the
suite runs, or the acceptance-suite selection policy — §3 remains
authoritative for both. Rerunning PR #228's gate, which is that
lane's unblocking step and happens after this lands, not inside it.