## Filbert review, row 166 round 1: approve Candidate manifest `agents/darkwing/work/queue-166/candidate-manifest.sha256`, sha256 `d0c58a37805f82ccae0dcda59b3ed9e8dc4d88663d884e4e1597fd75eb0e64e4` (2 paths). `build.patch` is `f7c22a97c931aaa248df9017f94c2de77f1dc872cc83518b2dc3a61720b191f8`. I applied it with `--index` to `139e28673`. Both manifest lines matched, `git diff --cached --check` is clean, and the diff is +124 -18 over 2 files. The script part of the cached diff is byte-equal to `stack-release-sh.diff` (`490d6c99...88d3`). I read it against the brief `docs/plans/2026-10-18_stack-release-hardening.md` (c70f360ae) and BUILD.md. ### Item 1: unreadable drop-ins `drop_in_override` now matches `install_guard` (`scripts/bus-service.sh:112-129`) line for line: - the absolute-path refusal; - `-e || -L` for the unit path, the drop-in directory and the `.conf`; - `-d && -r && -x` for both directories; - `content="$(cat ...)"` followed by the grep on the content. Each refusal is `drop-in-override` with install_guard's own wording, and all of it runs in the precheck before any stop. T28's three subtests use mode 000 on the unit path, the bus drop-in directory (`${BUS}.d` matches `mosaic-bus@*.service.d`) and a `.conf`. Each one asserts: - exit 3 and the exact stderr; - no start or stop in the stand-in log; - both units still active; - the fingerprint unchanged; - one more log line, with code `drop-in-override`. That is the brief's test, plus the unit path case. ### Item 2: the is-active to read race - **plan_store.** It rechecks `is-active` after `heldversion`, and on a change sets `S_SCHEMA=unknown` with the "run --plan again" reason. `plan()` then drops the note and the whole migration/restore branch (`:653-667`). plan_store is called only from `plan()` (`:647`), so a real run never sees `S_CHANGED`. - **Rollback `--restore`.** It rechecks after `heldcount` and refuses `restore-mismatch` before `run_steps`, so nothing stops. The run already recounted after the stop (`:695-697`, `rollback_in_run post-backup-events`). So this turns a late rollback into an early refusal, which is what the brief asks for. T29 uses the new `bus-stops-after 1` stand-in fault. The first bus `is-active` answers the real state, every later one answers inactive, and units.json is left alone. - The `--plan` subtest asserts the whole stdout, so if any earlier bus check had used up the one real answer, the output would differ. - The rollback subtest asserts the exact `restore-mismatch` message with the STAMP, no start or stop, and no post-attempt dir. ### Item 3: the copy check names the target The gate now captures `stack-copy.sh check`'s stdout and compares its `bus:` line with `copy="$COPIES/$1"` (`:363`, local, as is `out`). On a mismatch it sets `GATE_WHY` with both paths. `check` already requires `bus` to start with the literal `"$COPIES/"` (`stack-copy.sh:102`), and the run passes it the same `--copies`. So a correct install can't fail this compare through a path spelling difference. T30 runs a copy of the repo whose `stack-copy.sh` answers `check` with all three on B and runs the real script otherwise. The test then asserts: - `activate C1` exits 1, and stderr is `rolledBack('copy-check')`; - stdout carries the line "agree on .../B, not .../C1"; - the log line is `gate-failed`, `copy-check`, rollback `ok`; - the pointer stays on B, and the bus runs from B. `run()` taking `e.sr` affects only this test. ### Item 4: quoted units `unquoted` refuses `"`, `'` and `\` in three places: the bus argv, the Console argv and the bus `Environment=`. The three `read -r -a` splits now read those same captured values. T31 covers four forms: `Environment` with double quotes, with single quotes and with a backslash, and the bus `ExecStart` with `"--pm"`. Each form asserts: - activate refuses `unit-flags-drift`; - status prints `unit flags: cannot read the units`; - adopt refuses `check-failed` and writes no pointer; - no stderr names `/a`. That is the brief's test. ### Other checks - **Brief scope.** The diff touches only the script and its test, and no verb's wording changes. Its commit-msg.txt has no attribution line. - **Hash pins.** No 64-hex pin in `packages/*/tests` or `scripts/test-*.sh` names either manifest path. A grep of `packages`, `scripts` and `tools` for `stack-release` also finds `packages/cli/README.md:648`, which BUILD.md's list leaves out. Its text (adopt, activate, rollback, status, a failed gate rolls back) is still true. - **Base drift.** From `139e28673` to HEAD `c9c8c14d4`, nothing changed on the 2 manifest paths, `stack-copy.sh` or `bus-service.sh`. The canonical script is still blob `4b16e848`, and `build.patch` passes `git apply --cached --check` on HEAD in a temporary index. - **Landing order.** This approves the candidate only. It lands after the 8e7ea89a1 window, per mos-0834 via sage-0956. ### Notes (not blocking) 1. **Console ExecStart has no test.** Item 4 covers "the `ExecStart` argv split... used at :153 and :159". The Console argv check is there (`unquoted "$console_argv"`), but T31's only ExecStart form is in the bus unit. A mutant that drops only `&& unquoted "$console_argv"` would, as I read T31, survive. Mutant 4b removes the ExecStart check as a whole. The brief's test line names only the `Environment=` form, so I don't count this as a missing brief-required test. A follow-up could add a fifth T31 form on the Console unit. I didn't run that mutant. 2. **The non-absolute unit path refusal has no test.** It copies install_guard and isn't in the brief, so this is a follow-up only. 3. **TOOLS.md wording.** `docs/TOOLS.md:389-390` lists `stack-copy.sh check` in the gate without saying that the copy must be the one this run installed. TOOLS.md isn't in the manifest, and no test reads that text for this row. Doc-only, follow-up. ### Ran by me Nothing that needed the slot. I applied the patch, ran `sha256sum -c` (2/2), compared the script diff, read install_guard, `stack-copy.sh check` and the run and plan paths, ran greps, and ran the HEAD apply check. ### Not mine Darkwing's slot run (sage-0952) as BUILD.md records it: `stack-release.test.mjs` 71 of 71, `stack-copy.test.mjs` 12 of 12, awk pass 83, fail 0. CONTROL passes, and all 8 mutants (1a, 1b, 1c, 2a, 2b, 3, 4a, 4b) are killed. Its logs are under `~/darkwing-scratch`, which I don't read, so I have not checked them. The full gate is Sage's at landing.