103 lines
5.8 KiB
Markdown
103 lines
5.8 KiB
Markdown
# Row 126 (#1620): bus schema 3h → 3i, for Mos
|
|
|
|
Round 4, under Mos's go (mos-0835, relayed in sage-0972) and Sage's scope (sage-0970). This step
|
|
lands on refactor only. It is not in the 8e7ea89a1 window. It goes live later through
|
|
`stack-release.sh activate ID BUSINESS --migrate` with Jason present, on Mos's go (decision 96,
|
|
conditions 1 and 2).
|
|
|
|
## What the step does
|
|
|
|
3h reserved `usage_records.account` as `account TEXT CHECK (account IS NULL)`
|
|
(`packages/bus/src/migrations/3g-3h.sql:10`). Row 126 writes the run's account name there, so the
|
|
CHECK has to go. SQLite cannot drop a CHECK in place, so `packages/bus/src/migrations/3h-3i.sql`
|
|
rebuilds the table:
|
|
|
|
1. drops the three append-only triggers: `usage_records_no_update`, `_no_delete` and `_no_replace`.
|
|
Mos checked that nothing else references the table: no index, view or foreign key;
|
|
2. renames `usage_records` to `usage_records_3h`;
|
|
3. creates `usage_records` with text byte-identical to `schema.sql`. The only change from 3h is
|
|
`account TEXT,`;
|
|
4. copies every row in seq order, `seq` included;
|
|
5. sets the table's `sqlite_sequence` value to the old table's value. It is not rebuilt from
|
|
`max(seq)`, so a seq that was handed out and then rolled back is never reused;
|
|
6. drops `usage_records_3h`, then recreates the three triggers with their 3h text.
|
|
|
|
Why it renames first: `ALTER TABLE … RENAME` stores the new name quoted in the table's SQL. The
|
|
open-time digest compares `sqlite_master` text, so renaming the new table into place would leave
|
|
`"usage_records"` in its text and fail `migration-target-mismatch` at import.
|
|
|
|
The Store runs each step inside one `BEGIN IMMEDIATE` transaction (`store.mjs`
|
|
`#migrateSchema`): the step's SQL, the meta version and digest rewrite, and the
|
|
`schema-mismatch` digest check before commit. Any failure rolls the whole step back, and the
|
|
store stays at 3h.
|
|
|
|
## The checks behind it
|
|
|
|
`packages/bus/tests/account-migration.test.mjs` works on a 3h store built from
|
|
`tests/fixtures/schema-3h.sql`. That file is pinned from 81f26551b's `schema.sql`, sha256 `bb2ba581…6950`.
|
|
No live store is read or copied.
|
|
|
|
- **Test 1.** The plain open refuses with `schema-mismatch`, and `migrateSchema` then reaches 3i.
|
|
Every table's rows are unchanged, seq 1-3 included, and the sequence stays at 50.
|
|
`sqlite_master` equals 3h's except the account line of usage_records; the three triggers are
|
|
back. quick_check and foreign_key_check are clean. The next insert gets seq 51 and takes an
|
|
account. UPDATE, DELETE, INSERT OR REPLACE and a reused seq all abort with
|
|
`usage_records is append-only`.
|
|
- **Test 2.** A step that fails partway, after the triggers are dropped and the copy is done,
|
|
leaves version 3h, `sqlite_master` and every row as they were. The real step then migrates the
|
|
same store.
|
|
- **Test 3.** A 3h engine (3h schema and SHA, no 3h→3i step) refuses a 3i store with
|
|
`schema-mismatch`, with or without `migrateSchema`. The store is left at 3i, unchanged.
|
|
|
|
## Running it
|
|
|
|
The only supported path is `scripts/stack-release.sh activate ID BUSINESS --migrate`, run by Jason
|
|
or Mos on Mos's go, with Jason present. Run `--plan` first: it prints
|
|
`migration steps: 3h to 3i` from the target copy's `store.mjs`, plus `needs: --migrate` and
|
|
`needs: Jason present`.
|
|
|
|
The activate path takes the pre-migrate backup itself, so nothing extra is needed. In
|
|
`run_steps` (`stack-release.sh:663-669`), with both units stopped and the store clean:
|
|
|
|
1. `in_chain` checks that 3h is in the target's chain, or the run rolls back `store-newer`;
|
|
2. without `--migrate`, the run rolls back `migration-needs-flag`;
|
|
3. `backup_store` copies `bus.sqlite` to `<dataRoot>/backups/stack/<ACTIVATION>/`, together with
|
|
`SOURCE.sha256`, `SHA256SUMS`, `MODES.txt`, `LISTING.txt`, `DATA_ROOT`, `STAMP`, `SCHEMA` (3h)
|
|
and `ROLLBACK_SET`, and checks that the copy's sha equals the source's. It sets TAKEN;
|
|
4. only then does `migrate-schema.mjs` run from the target copy.
|
|
|
|
## The way back
|
|
|
|
There is no 3i → 3h step, and no down-migration will be written. 3h code meeting a 3i store
|
|
refuses:
|
|
|
|
- the 3h Store throws `schema-mismatch` (test 3);
|
|
- `scripts/land-work/read.mjs` in a 3h tree refuses `bus-schema`;
|
|
- `stack-release.sh rollback` to a 3h copy refuses `schema-differs` unless `--restore` is given.
|
|
|
|
The way back is restoring the pre-migrate backup:
|
|
|
|
- **Inside the activate run.** If `migrate-schema.mjs` fails, or a later step or the gate fails,
|
|
`rollback_in_run` restores the backup this run took (TAKEN), puts back the previous units and
|
|
wrapper, and gates the old stack. A failed migration also rolls back its own transaction, so the
|
|
store is still 3h before the restore.
|
|
- **After a successful activate.**
|
|
`stack-release.sh rollback BUSINESS --restore <ACTIVATION> [--events N]`, where `<ACTIVATION>`
|
|
is the activate run's id (the backup directory's name). The backup must be of this data root at
|
|
the target's schema (3h), or the run refuses `restore-mismatch`. If events were written after
|
|
the backup's STAMP, the run needs `--events N` with that count and waits for Jason (decision 96,
|
|
condition 3). The store from before the restore moves aside to the run's post-attempt
|
|
directory; nothing is deleted.
|
|
|
|
Restoring drops whatever the 3i bus wrote after the backup, including any usage records with an
|
|
account. `--events N` counts events only. Usage records written in the same period are lost too.
|
|
|
|
## Between landing and the window
|
|
|
|
`scripts/land-work/read.mjs` imports `SCHEMA_VERSION` from the checkout's
|
|
`packages/bus/src/store.mjs` and refuses `bus-schema` when the store's meta differs. After 3i
|
|
lands on refactor, `scripts/land-work.sh` run from the canonical checkout against the live 3h store
|
|
will refuse `bus-schema` until the 3i window has run. This is the same gap 3g→3h had. Sage decides
|
|
whether land-work runs from a 3h tree in that period, or whether this row lands just before the
|
|
window.
|