plans: D1 brief item 8 re-pinned to the held or stopped store read; stack-release hardening brief (row 162 follow-up)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
f5b5aa509f
commit
c70f360ae7
2 files changed
+72
-5
No files matched your search
@@ -0,0 +1,64 @@
|
||||
# Brief: stack-release.sh hardening after D1
|
||||
|
||||
Follow-up to row 162 (D1, #1659), from Filbert's non-blocking notes on round 1
|
||||
(#1659 comment 28997). Darkwing drafted it (agents/darkwing/work/queue-162/followup-brief.md).
|
||||
Sage folded it in here and made the fifth note, the brief item 8 re-pin, a doc change in
|
||||
docs/plans/2026-10-18_stack-release.md.
|
||||
|
||||
Owner Darkwing, reviewer Filbert, gate owner Sage. Starts after row 162 lands and builds on
|
||||
that landing. Line numbers below are `scripts/stack-release.sh` as landed by row 162.
|
||||
|
||||
None of the four is a known failure today. Each one fails closed or can't be reached with the
|
||||
current pin. The fix makes each one refuse earlier, or tell the truth sooner, with codes row
|
||||
162 already has. No new refusal code. Nothing here runs against the live stack: every test
|
||||
uses the stand-in `systemctl`, units and stores the row 162 tests already use.
|
||||
|
||||
## Items
|
||||
|
||||
1. Precheck unreadable drop-ins. `drop_in_override` (:503) scans the same three directories
|
||||
as `install_guard` in `scripts/bus-service.sh` (:100), but skips a directory or file it
|
||||
can't read (`[ -d ]`, `grep 2>/dev/null`). `install_guard` dies on that same path after the
|
||||
stop, so the run rolls back and the live stack stopped for nothing. The precheck refuses
|
||||
`drop-in-override` with the path when a unit path, drop-in directory or `.conf` file exists
|
||||
but can't be read, using `install_guard`'s own tests (`-r`, `-x`, a failed read).
|
||||
Test: a drop-in file with mode 000, and a directory with mode 000, each refuse before any
|
||||
`systemctl stop` in the stand-in log, and the units stay active.
|
||||
|
||||
2. Close the `is-active` to read race. `plan_store` (:573, check at :577) and the `--restore`
|
||||
event count (:716) choose the held-store read or the stopped-store read from one
|
||||
`is-active` call. If the bus stops between the check and the readOnly open, the open can
|
||||
leave `-wal` or `-shm` beside a stopped store, and the next run refuses `store-unclean`.
|
||||
After a held-store read, check `is-active` again. If the bus stopped meanwhile, say so:
|
||||
`--plan` prints that the store state changed during the read and prints no migration
|
||||
line; rollback refuses `restore-mismatch` before anything stops.
|
||||
Test: a stand-in `systemctl` that answers active, then inactive.
|
||||
|
||||
3. Compare the copy check with the target. The `copy-check` gate step (:373) runs
|
||||
`stack-copy.sh check --business`, which proves the bus, Console and CLI agree on one copy,
|
||||
not that it is the copy this run installed. Pass the expected copy id, or compare the
|
||||
check's reported id with the target, and fail the gate with `copy-check` on a mismatch.
|
||||
Test: a stand-in check that reports agreement on another copy fails the gate and rolls
|
||||
back.
|
||||
|
||||
4. Don't split a quoted `Environment=`. `read_units` (:148) splits the `systemctl show`
|
||||
`Environment=` line (`show` at :144) on spaces with `read -r -a` (:157). systemd quotes a
|
||||
value that holds a space, so a `MOSAIC_CLAUDE_BIN` path with a space reads as a prefix of
|
||||
itself. Smallest fix: `read_units` returns 1 when that line holds a quote or backslash, so
|
||||
its callers refuse as they do for an unreadable unit (`unit-flags-drift` at :535,
|
||||
`check-failed` at :561; the status view at :743 then skips its unit flags line). Cover the
|
||||
`ExecStart` argv split (`argv_of`, :145, used at :153 and :159) the same way.
|
||||
Test: a stand-in unit with `Environment="MOSAIC_CLAUDE_BIN=/a b/claude"` refuses by name
|
||||
and never reads `/a`.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Each item's test, plus a mutant per item that removes the new check and fails that test.
|
||||
- `packages/cli/tests/stack-release.test.mjs` and every `scripts/test-*.sh` green on Sage's
|
||||
gate; Filbert approves the candidate manifest.
|
||||
- The diff touches only `scripts/stack-release.sh`, its test file and, if a verb's wording
|
||||
changes, the TOOLS.md "Pinned stack update" section.
|
||||
|
||||
## Out of scope
|
||||
|
||||
The bus-side PM marker, parsing systemd quoting, anything in Mos's live window, and any run
|
||||
of `adopt`, `activate` or `rollback` against the live stack.
|
||||
@@ -178,11 +178,14 @@ start has no gate that puts the old copy back.
|
||||
refuses `post-backup-events` unless `--events N` repeats the printed
|
||||
count.
|
||||
8. `activate ID BUSINESS --plan` and `rollback BUSINESS --plan` print
|
||||
the target, whether a migration or a restore is expected (from the
|
||||
pointer's `schema` and the target copy's `SCHEMA_VERSION`, with no
|
||||
store read) and the flags that would be installed. They change
|
||||
nothing and write no log line, so the window knows beforehand
|
||||
whether Jason must be present.
|
||||
the target, whether a migration or a restore is expected and the
|
||||
flags that would be installed. The store schema comes from a
|
||||
read-only read of the store the running bus holds, or of the stopped
|
||||
store when the bus is down. With no store file it falls back to the
|
||||
pointer's `schema` and says so (sage-0745, mos-0741; this replaced
|
||||
the first draft's "pointer only, no store read"). The target side is the
|
||||
copy's `SCHEMA_VERSION`. They change nothing and write no log line,
|
||||
so the window knows beforehand whether Jason must be present.
|
||||
9. `status BUSINESS` prints the pointer, the last five log lines, the
|
||||
live units' copies, the result of `stack-copy.sh check`, `bus status`
|
||||
and the drift from `refactor`. It only reads.
|
||||
|
||||
Reference in new issue
Block a user