Unclaimed files left in the canonical checkout. Inventory: canonical-cleanup-inventory.md (commit-as-evidence groups). detect-secrets scan clean on 2026-11-02: hits are sha256 pins, git object ids, test sentinels already in tracked tests and unit-file lines.
178 lines
9.5 KiB
Markdown
178 lines
9.5 KiB
Markdown
# Row 185: every activate backs up the stopped store
|
|
|
|
Brief: `docs/plans/2026-10-20_activate-always-backs-up.md` (blob 2877ca401c2f, 52ce57dfe). Gitea #1683, P19
|
|
task 403. Owner Darkwing, reviewer Filbert, gate owner Sage. It is the precondition for mos-0928 Part A
|
|
(`agents/sage/work/window-plan/repin-rows-177-185.md`).
|
|
|
|
## Files
|
|
|
|
| File | What |
|
|
|---|---|
|
|
| `build.patch` | the change, `git diff 52ce57dfe` over the paths below |
|
|
| `candidate-manifest.sha256` | one line per changed path |
|
|
|
|
- Base: 52ce57dfe. Line numbers are at the base unless marked as the candidate's. `scripts/stack-release.sh`
|
|
has not changed since 9f5153deb, so the brief's numbers match.
|
|
- Changed: `scripts/stack-release.sh`, `packages/cli/tests/stack-release.test.mjs` and `docs/TOOLS.md`. Nothing
|
|
outside the brief's list.
|
|
|
|
## Design
|
|
|
|
### The run (change 1)
|
|
|
|
The migrate branch of `run_steps` (:835-842) now reads:
|
|
|
|
```bash
|
|
if [ "$STORE_SCHEMA" != "$T_SCHEMA" ]; then
|
|
in_chain "$STORE_SCHEMA" || rollback_in_run store-newer
|
|
[ "$MIGRATE" = 1 ] || rollback_in_run migration-needs-flag
|
|
fi
|
|
backup_store || rollback_in_run backup
|
|
if [ "$STORE_SCHEMA" != "$T_SCHEMA" ]; then
|
|
TAKEN="$ACT"
|
|
node .../migrate-schema.mjs ... || rollback_in_run migrate-failed
|
|
say "migrated the store to $T_SCHEMA"
|
|
fi
|
|
```
|
|
|
|
It sits inside `if [ -e "$STORE" ]`, after the `store_unclean` and schema reads (:831-833), so:
|
|
- a store with a `-wal` or `-shm` still rolls back `store-unclean` with no backup;
|
|
- a missing store takes no backup;
|
|
- a failed backup rolls back with `backup` as before. TAKEN is still empty then, so nothing is restored.
|
|
|
|
`store-newer` and `migration-needs-flag` still roll back before the backup. Those runs never touch the store,
|
|
so a backup there would only add a directory, and T6 and T9 keep asserting that no `backups/stack` appears. I
|
|
chose this over "backup first, then the checks" because it keeps the backup tied to a run that goes on to
|
|
install the target. The cost is one more `if` on the schema test.
|
|
|
|
### TAKEN and BACKUP (change 2)
|
|
|
|
Before this row `backup_store` set both (:367), because the only backup was a migration's. They now mean two
|
|
things:
|
|
|
|
- `BACKUP` is the backup the run names. `backup_store` sets it on every backup, so `log_line` (:52) writes it
|
|
into every line after the backup, and `from_log backup` (:146) finds it on the ok line that made the copy
|
|
live. `rollback_failed` (:571) names it too.
|
|
- `TAKEN` is the backup `rollback_in_run` (:543) restores. Only the migrate branch sets it, right before the
|
|
migration. After a gate failure on a same-schema activate the store is the one the run started from, plus
|
|
whatever the target's bus wrote while it ran. Restoring would throw those writes away for no reason, and
|
|
every restore moves the live store to a post-attempt directory. So that rollback puts back the units and
|
|
the wrapper and leaves the store.
|
|
|
|
The two comments at `backup_store` and `rollback_in_run` say this.
|
|
|
|
### `--plan` (change 3)
|
|
|
|
`plan` prints one line after the migration or restore block, for activate only:
|
|
|
|
- with a store file: `backup: the run backs up the stopped store to <dataRoot>/backups/stack/<activation>/
|
|
before any migration`, with the real data root;
|
|
- with no store file: `backup: none; there is no store file`.
|
|
|
|
The activation id is made by the run, so the plan prints `<activation>` as written. The migration lines are
|
|
unchanged. They already say "after a backup of the stopped store". The line is printed on the `S_CHANGED`
|
|
path too (the bus stopped during the read), since a store file is there. For `store-newer` and
|
|
`migration-needs-flag` the plan already says the run would roll back. I did not add a third form for those.
|
|
|
|
### Rollback and pm-on (change 4)
|
|
|
|
Unchanged. `do_rollback` already lets a same-schema rollback take `--restore` (:891-922): it checks the
|
|
backup's SCHEMA against the target's, its DATA_ROOT and STAMP, and the restore guard. A same-schema activate's
|
|
backup has SCHEMA equal to the store's, so test 3 needed no script change. pm-on does not call `run_steps
|
|
migrate`.
|
|
|
|
### docs/TOOLS.md (change 5)
|
|
|
|
"Pinned stack update" steps 5 to 7:
|
|
- step 5: every activate takes the backup before any migration, the log line names it, a missing store takes
|
|
none, and `store-newer` or a migration without `--migrate` rolls back first;
|
|
- step 6: the backup is taken on every activate and restored only when a migration ran; after a same-schema
|
|
activate the store stays as the failed run left it;
|
|
- step 7: a same-schema rollback can take `--restore` with the activate's backup.
|
|
|
|
Step 3 lists what the plan names and does not mention the new line. The brief assigns steps 5 to 7 only, so
|
|
I left step 3 for Sage.
|
|
|
|
## Existing tests that change
|
|
|
|
| Test | Why |
|
|
|---|---|
|
|
| T5 | asserted no `backups/stack` after the same-schema B to C1 activate. Now asserts the directory holds exactly the activation's backup (brief test 1 says to update it). |
|
|
| T11 | the `rollback-failed` message now ends `, backup <path>` after a same-schema activate. Also asserts the log's backup and that no post-attempt store appears. |
|
|
| T26 | exact plan output for B to C: the backup line after the `needs:` lines. The same-schema `includes` check has the line between `migration: none` and `commits:`. |
|
|
| T29 | exact plan output for the stopped-during-read case: the backup line after `target schema: 3h`. |
|
|
|
|
T6 and T9 are unchanged (above). T7, T8, T13, T14, T14b, T43 and T45 do migrating activates and still pass
|
|
as written: T8's migration case still restores. T23, T27, T36 and T44 read plan lines by offset from a line
|
|
the backup line comes after, or from the end. T43's `[c, c-1]` listing has only migrating activates, since
|
|
rollbacks take no backup.
|
|
|
|
The fixture gets one fault, `start-writes-row-<copy>`: the copy's bus start writes one event before the holder
|
|
opens the store. T48 uses it so the store after the failed gate differs from the backup, which makes a restore
|
|
visible by sha.
|
|
|
|
## New tests (candidate lines, after T46)
|
|
|
|
1. T47: a same-schema B to C1 activate leaves `backups/stack/<act>/` with SHA256SUMS, DATA_ROOT equal to the
|
|
data root, SCHEMA equal to the store's (3g) and a STAMP. The backup's sum is the store's sha before the run.
|
|
The run prints `backup: <dir>`, and the ok log line's `backup` is the activation.
|
|
2. T48: a gate failure (`healthz-C1`) on the same activate, with the target's start writing one row. It rolls
|
|
back `healthz`. The store sha after the rollback equals the store at the stop after the failed gate (the
|
|
fixture's stop snapshot), that sha differs from the backup's, and no post-attempt store appears. Units,
|
|
wrapper and pointer are back.
|
|
3. T49: a same-schema `rollback --restore <act>` with no rows after STAMP restores and goes live on B at 3g.
|
|
The store is the backup and the C1 store is kept as the post-attempt store. With one `instance_names` row
|
|
after STAMP it refuses `post-backup-events` with `0 event(s), 1 instance_names row(s)` and changes nothing,
|
|
and `--events 1` restores.
|
|
4. T50: `activate C1 --plan` prints exactly one `backup:` line, the store-file form, and writes nothing (units,
|
|
wrapper, pointer, store, the data tree and the log). A rollback plan has no backup line.
|
|
5. T51: with the bus stopped and the store files removed, the plan prints `backup: none; there is no store
|
|
file`, and the activate passes with no `backups` directory, no `backup:` line and a null `backup` in the log.
|
|
|
|
## Mutants
|
|
|
|
`run185.sh` runs `stack-release.test.mjs` whole, then each mutant against T5, T11 and T47 to T51
|
|
(`--test-name-pattern='^(T5|T11) |row 185'`). Each edits the worktree script after a checked backup and puts it
|
|
back by the backup's sha.
|
|
|
|
| Mutant | Expected killers |
|
|
|---|---|
|
|
| m1: the backup only when the schemas differ (today's code) | T5, T47, T49, T11 |
|
|
| m2: TAKEN set by every backup | T48, T11 |
|
|
| m3: BACKUP left empty on a same-schema activate | T47, T48, T11 |
|
|
|
|
## Runs
|
|
|
|
Slot from sage-1233, 2026-10-20T06:46:32.784Z to 06:51:52.217Z. TMPDIR `~/darkwing-scratch/r185/tmp`.
|
|
|
|
| Run | Result | Failing tests |
|
|
|---|---|---|
|
|
| `stack-release.test.mjs` | 125 tests, 125 pass, 0 fail | none |
|
|
| m1: the backup only when the schemas differ | killed | T5, T11, T47, T48, T49 (both subtests) |
|
|
| m2: TAKEN set by every backup | killed | T11, T48 |
|
|
| m3: BACKUP empty on a same-schema activate | killed | T11, T47, T48 |
|
|
|
|
T48 also fails under m1, at its log assertion: the line's `backup` is null. `stack-release.sh` was back at its
|
|
candidate sha after the mutants.
|
|
|
|
## Readers and hash pins
|
|
|
|
`git grep` over `packages/*/tests/**` and `scripts/test-*.sh` for `stack-release` and `TOOLS.md`, full output:
|
|
the only reader of `scripts/stack-release.sh` is `stack-release.test.mjs` itself (`SR`, :273, and the copied
|
|
script at :838). Nothing reads `docs/TOOLS.md`, and no test pins a sha256 of any of the three paths.
|
|
|
|
## Candidate
|
|
|
|
- Base 52ce57dfe. `52ce57dfe..origin/refactor` (b5d662cab) touches only
|
|
`agents/sage/work/window-plan/repin-rows-177-185.md`. `build.patch` applies cleanly to both
|
|
(`git apply --cached --check` on a scratch index).
|
|
- `build.patch`: sha256 8f2293de151c1c3b4d96ac6d494f7d9f67e849d8f51b804c6cdad799c4269ae6, patch-id (stable)
|
|
774cd23186d54eda08be028f7c39b5212cd1ed75, 3 files, 121 insertions, 16 deletions.
|
|
- `candidate-manifest.sha256`: sha256 bf87dbba645b5c4443670e4a81f44a99afedad6ab16ae0f125d6ab8de27bce3b.
|
|
|
|
| Path | sha256 |
|
|
|---|---|
|
|
| `scripts/stack-release.sh` | dccb4a10d5b9a6f680a5bdc06277abf39f7d438c0500cb44d5b1c45012de21bc |
|
|
| `packages/cli/tests/stack-release.test.mjs` | 94b398246cd87cec282e13147b244cdfa85ea5c98a7bf06a468e1b387692df08 |
|
|
| `docs/TOOLS.md` | a0ea0f560cd2683c2dd38bdeb88fd4bf339be771e0436e623ba554fcb34d6d54 |
|