docs: brief for two stack-release rows after the merged B+C window: row A (P19 391 activation ids, Dewey row 176 N1/N2), row B (P19 390 restore guard, after row A)
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
# Two stack-release.sh rows after the merged B+C window
|
||||
|
||||
Sage, 2026-10-20. Both rows come out of the merged B+C window and its rehearsals, and both change
|
||||
`scripts/stack-release.sh`. Row A goes first. Row B starts from row A's landing, so neither one builds
|
||||
on a stale base (the row 68 drift rule). Line numbers are at c5ae4d7ac.
|
||||
|
||||
Nothing here runs against the live stack. Every test uses the stand-in `systemctl`, units, stores and
|
||||
data root that `packages/cli/tests/stack-release.test.mjs` already builds. Q173 makes the live stack a
|
||||
test system, but these rows don't need it.
|
||||
|
||||
# Brief: activation ids and plan-mode refusals (row A)
|
||||
|
||||
Vikunja P19 391, plus N1 and N2 from Dewey's row 176 review. Owner Darkwing, reviewer Dewey, gate owner
|
||||
Sage. Base: the refactor head when the row moves to briefed.
|
||||
|
||||
## Items
|
||||
|
||||
1. Unique activation ids within one second (P19 391). `new_activation()` (:662) names the activation
|
||||
`$(date -u +%Y%m%dT%H%M%SZ)-<12-char copy prefix>`, and the post-attempt store path uses the same
|
||||
second. An activate followed by a pm-on on the same copy in the same second makes the second run's
|
||||
`mkdir -m 0700 "$RS"` (:373) fail, and capture refuses `capture-failed` (exit 3). It fails closed,
|
||||
but it failed row 176 gate run 1 in T34 (stack-release.test.mjs:931, subtest :955), and a pinned clock
|
||||
reproduces it every time.
|
||||
The fix keeps the id sortable by time and keeps the current shape as its prefix, so the ids
|
||||
already in `stack-rollback/`, `backups/stack/` and the pointer still parse. Either add milliseconds
|
||||
or add a suffix on collision. A suffix is chosen while holding the lock, against both
|
||||
`stack-rollback/` and `backups/stack/`. The POST path follows the same rule. Adopt's id (:680)
|
||||
uses the same helper. `--restore ACTIVATION` accepts both the old and the new form, and
|
||||
`docs/TOOLS.md` describes the new one.
|
||||
Test: a `date` stand-in on the test PATH that prints one fixed second. Activate, then pm-on on
|
||||
the same copy, both pass with distinct ids, rollback dirs and POST paths. A `--restore` of an
|
||||
old-form id from the fixture still works.
|
||||
|
||||
2. Plan-mode refusals in `console_for_target()` (N1). Under `--plan`, `valid_tester_port ... || usage`
|
||||
(:636) and `refuse tester-port-target` (:637) end the run at the first problem. Every other
|
||||
precheck under `--plan` goes through `check_refuse` (:265), so the plan lists all refusals. With
|
||||
PLAN=1, both lines report through `check_refuse` with a named code. A bad port uses a new code,
|
||||
`tester-port-invalid`, and gives the same reason text usage gives today. Without `--plan`,
|
||||
behavior doesn't change.
|
||||
Test: `--plan --tester-port 80` and `--plan` against a copy whose Console lacks `--tester-port`
|
||||
each list their refusal next to a second, independent refusal from the same run, and exit as a
|
||||
plan with refusals does today. The same flags without `--plan` give today's output byte for byte.
|
||||
|
||||
3. Tester port length before zero stripping (N2). `tester_port_ok()` in `scripts/webui-service.sh`
|
||||
(:123) strips leading zeros and only then checks for five digits, so
|
||||
`render --tester-port 007333` passes and `serve` refuses the same value. Check the raw length
|
||||
first (at most five digits), then strip and compare, which is what `valid_tester_port` (:62) in
|
||||
stack-release.sh already does.
|
||||
Test: in packages/webui/tests/service.test.mjs, `render --tester-port 007333` refuses with the
|
||||
usage text and `07333` still renders.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Each item has the test above and a mutant that the gate kills (mos-0862: any gate test may kill it).
|
||||
- Suites green on Sage's gate, run from a git worktree of the candidate.
|
||||
- Dewey approves the manifest.
|
||||
- Touched files: `scripts/stack-release.sh`, `scripts/webui-service.sh`, their test files,
|
||||
`docs/TOOLS.md`, and the packet under `agents/darkwing/work/queue-<row>/`. Anything else gets named
|
||||
in BUILD.md with the reason.
|
||||
|
||||
## Out of scope
|
||||
|
||||
The restore guard (row B). Any change to the pointer format, the backup layout or a refusal code
|
||||
other than the new `tester-port-invalid`. Any run against `~/.mosaic-dev` or the live units.
|
||||
|
||||
# Brief: the restore guard counts every row a restore drops (row B)
|
||||
|
||||
Vikunja P19 390. Owner Darkwing, reviewer Filbert, gate owner Sage. Base: row A's landing. The row
|
||||
waits on row A done.
|
||||
|
||||
## Why
|
||||
|
||||
`rollback --restore` refuses `post-backup-events` unless `--events N` names the number of events
|
||||
written after the backup STAMP (:875 before the stop, :805 again in the run). The count in STORE_JS
|
||||
(:289, `count` and `heldcount` at :298) reads only `events WHERE at > ?`. Some writers skip events.
|
||||
`usage_records` (usage.mjs:92) and `instance_names` (broker.mjs:2237) do, per mos-0838 D3. Darkwing's
|
||||
P3 rehearsal on 8e888014d ran a `name --tester` after the stamp. It got instance_names rowsAfter 1
|
||||
and eventsAfter 0. The restore printed "0 event(s)" and dropped the row from the live store with no
|
||||
refusal, and only the post-attempt copy kept it. The merged window stopped before any restore on a
|
||||
nonzero snapshot rowsAfter as a stand-in for this fix.
|
||||
|
||||
## Items
|
||||
|
||||
1. Find every table a restore can lose rows from without an event. Read the writers in
|
||||
`packages/bus/src/` at the base and list, in BUILD.md, each table that has rows written without an
|
||||
event in the same transaction, with the writer's file and line. usage_records and instance_names
|
||||
are on that list. The threads tables from rows 175 and 177 get checked too. The list goes in
|
||||
stack-release.sh as one constant next to STORE_JS.
|
||||
2. Count them. STORE_JS `count` and `heldcount` return the rows after STAMP for events and for each
|
||||
listed table, keyed by table name, from the same read in the same open as today (immutable on a
|
||||
stopped store, readOnly on a held one, with the row 166 is-active recheck kept). A listed table
|
||||
the store doesn't have counts 0, because stores before 3g have no instance_names and stores
|
||||
before 3h have no usage_records. A table that exists but can't be read is `restore-mismatch`, as
|
||||
a failed count is now.
|
||||
Test: a fixture store with one event, one usage_records row and one instance_names row after the
|
||||
STAMP gets counts 1, 1 and 1 from both modes. A 3f fixture store with no usage_records table
|
||||
counts 0 for it and doesn't refuse.
|
||||
3. Refuse on any of them. The guard refuses `post-backup-events` unless every count is zero or
|
||||
`--events N` equals the total. The message names each nonzero table, for example
|
||||
`1 event(s), 1 usage_records row(s), 1 instance_names row(s) were written after the backup`. The
|
||||
flag and the code keep their names, so no caller breaks. TOOLS.md and the usage text say that N
|
||||
counts rows in all listed tables. The in-run recount (:805) compares the same total and refuses
|
||||
`post-backup-events` the same way.
|
||||
Test: instance_names rowsAfter 1 with events 0 refuses before any `systemctl stop` in the
|
||||
stand-in log, the stack stays up, and `--events 1` then restores. The same holds for one
|
||||
usage_records row. T14 (:565) passes unchanged for an events-only store.
|
||||
4. A guard test for new tables. A test reads every table with an `at` column from the target
|
||||
store's schema. It fails when a table is neither events, nor in the constant, nor in a short
|
||||
reviewed list of tables whose rows always come with an event (deliveries, for example, named in
|
||||
BUILD.md with the writer that shows it). A later schema row that adds such a table then has to
|
||||
classify it.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Each item 2 to 4 has its test and a killed mutant: one per listed table that drops it from the
|
||||
count, one that compares only events in the in-run recount, and one that adds a table with an
|
||||
`at` column to the fixture schema without classifying it.
|
||||
- Suites green on Sage's gate, run from a git worktree of the candidate.
|
||||
- Filbert approves the manifest.
|
||||
- Touched files: `scripts/stack-release.sh`, `packages/cli/tests/stack-release.test.mjs`,
|
||||
`docs/TOOLS.md`, and the packet. Anything else gets named in BUILD.md with the reason.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Restoring the dropped rows into the restored store, or merging the post-attempt copy back. A new
|
||||
refusal code or flag name. Any change to the bus writers so they also write events. Any run against
|
||||
`~/.mosaic-dev` or the live units.
|
||||
Reference in New Issue
Block a user