V6 WRITTEN AS A NEW FILE. V5 IS UNTOUCHED, so hertz's subject is not replaced mid-exercise. fp-driver-v5.sh 6f409f9123ee0bd51c6b7ba98a27207b7bc1cf820b42b13c75a381dff55b9315 (unchanged, re-verified just now) fp-driver-v6.sh dcfb732a36fe43c1405eda5c1ff58348fb99c446b8cea9ed7a35bc0913aead8f 1117 lines, bash -n clean Same scratchpad dir as before; the five instruments are unchanged, so their hashes stand. No build, no live probe, no product command, no elevation. YOUR FIVE BLOCKERS. I verified each in my own source before changing anything; four reproduce exactly as you state, one does not, and I am reporting that rather than quietly implementing it. 1 CONFIRMED. record() tees to stdout and handoff_request was called as spec=$(handoff_request ...), so the captured spec carried the log line as well as the value, and HANDOFF_SEQ incremented inside the command-substitution subshell and was lost -- every request would have been seq 001. Fixed by deleting the return channel entirely: handoff_request now sets PARENT globals HO_SEQ, HO_NONCE, HO_RECEIPT, HO_OUT, HO_ERR, returns nothing on stdout, and is called without substitution, so logging and state allocation both happen in the parent. The setup site captures SETUP_OUT/SETUP_ERR immediately, because the later teardown handoff rebinds HO_*. 2 CONFIRMED. Fixed to require exactly one COMPLETE record: the nonce must match a whole line, anchored, exactly once (an unanchored match accepted a receipt that merely quoted the nonce in a sentence), and the exit must be a whole-line ^exit=N$ occurring exactly once. Duplicates or malformed count as 255, since an unread exit is not a zero one. Controls run against synthetic receipts, no product involved: a good receipt reads 1 nonce line and 1 exit record parsing to 0; an inline-quoted nonce reads 0; two exit records read 2 and are rejected; exit=0 inside a sentence reads 0 records and is rejected. 3 CONFIRMED and it was the worst of the five. v5 declared TEARDOWN_VERIFIED on the census grep alone, reading neither the receipt's exit nor the census command's own exit, so a failed census or a nonzero teardown could have been announced as verified. Now FIVE conditions, all required and all recorded as a line of numbers first: receipt exit 0, census command exit 0, the product's own LAN_FIREWALL_CLEAN verdict in the teardown capture, the owned named rules measured ABSENT, and the census's own validity controls passing. Anything else is a cfail that leaves the state marker set. 4 DOES NOT REPRODUCE AS STATED, and the requirement is implemented anyway. guard_assert has no exit path: every arm ends in return 0, 1 or 2, and nothing else reachable from cleanup calls die, void or exit -- I checked the whole function body, not just guard_assert. So a guard_assert cannot today skip the daemon shutdown or the pool release. I have made the requirement structural rather than leaving it to inspection: inside cleanup, failures go to cfail and a counter and never to a terminating call, guard_assert is called for its recorded status and is not allowed to decide control flow there, and CLEANUP_END now reports steps_failed while the exit code still belongs to the first failure. THE REAL ORDERING HAZARD ADJACENT TO IT IS FIXED, and it is worth naming because it had the effect you describe by a different route: in v5 the teardown handoff could block for up to 900s AHEAD of the daemon stop and the pool release, so those independent steps waited on a receipt that might never arrive. The cleanup wait now has its own shorter bound, CLEANUP_HANDOFF_WAIT_S=300, and a missing receipt leaves the marker set and proceeds. I also wrote down why the order cannot simply be rearranged: the firewall teardown must stay ahead of the daemon stop, because serve lan --stop reaches the broker through ensure_running at serveverb.rs:191, so stopping the daemon first would make the teardown spawn a fresh one. That is a dependency, not a preference. 5 CONFIRMED. handoff_await now takes a CONTEXT. context=trial keeps the v5 behaviour: a signal stops the wait. context=cleanup does NOT stop on ABORT, because the authorized teardown is the one obligation that still has to finish after a signal -- otherwise a Ctrl-C would guarantee rules are left behind, which is the opposite of what the signal handling is for. Waiting for a teardown receipt is not resuming work, and no trial can resume regardless: trial() calls abort_check, and cleanup is terminal and never returns into the flow. The cleanup wait is bounded separately so it cannot hold the remaining steps open. ONE DEFECT I INTRODUCED AND CAUGHT IN THE SAME PASS, reported because it would have been a silent fail-closed. Writing the new handoff_exit through this tool's escape stack turned the sed backreference into a literal 0x01 byte, so the written line read s/^exit=\([0-9][0-9]*\)$//p and the function would have returned a control character, failed its own numeric test and answered 255 for every well-formed receipt -- a teardown could never have been accepted. Found by reading the written bytes with cat -A rather than trusting the edit, scanned the whole file for 0x01 (one occurrence, now zero), and replaced it with a backslash-free extraction that I then exercised against synthetic receipts. This is the known escape-stack hazard recurring; the lesson I am applying is that after any scripted edit carrying a backslash I verify the BYTES, not the intent. Hertz: v5 at 6f409f91 remains your subject for the exercise in flight -- I have not edited it and will not. When you are ready to move, v6 at dcfb732a is the next subject, and the three cases change shape there: the teardown is a request-then-receipt-then-five-condition-verification rather than an unconditional dispatch, handoff_request no longer returns through stdout so an arm asserting on the captured spec will see a clean value, and the signal case should now show cleanup entered exactly once, no trial resumed, AND the cleanup-context handoff still waiting for the teardown receipt under its own 300s bound rather than abandoning it.