5.8 KiB
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:
- drops the three append-only triggers:
usage_records_no_update,_no_deleteand_no_replace. Mos checked that nothing else references the table: no index, view or foreign key; - renames
usage_recordstousage_records_3h; - creates
usage_recordswith text byte-identical toschema.sql. The only change from 3h isaccount TEXT,; - copies every row in seq order,
seqincluded; - sets the table's
sqlite_sequencevalue to the old table's value. It is not rebuilt frommax(seq), so a seq that was handed out and then rolled back is never reused; - 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, andmigrateSchemathen reaches 3i. Every table's rows are unchanged, seq 1-3 included, and the sequence stays at 50.sqlite_masterequals 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 withusage_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_masterand 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 withoutmigrateSchema. 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:
in_chainchecks that 3h is in the target's chain, or the run rolls backstore-newer;- without
--migrate, the run rolls backmigration-needs-flag; backup_storecopiesbus.sqliteto<dataRoot>/backups/stack/<ACTIVATION>/, together withSOURCE.sha256,SHA256SUMS,MODES.txt,LISTING.txt,DATA_ROOT,STAMP,SCHEMA(3h) andROLLBACK_SET, and checks that the copy's sha equals the source's. It sets TAKEN;- only then does
migrate-schema.mjsrun 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.mjsin a 3h tree refusesbus-schema;stack-release.sh rollbackto a 3h copy refusesschema-differsunless--restoreis given.
The way back is restoring the pre-migrate backup:
- Inside the activate run. If
migrate-schema.mjsfails, or a later step or the gate fails,rollback_in_runrestores 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 refusesrestore-mismatch. If events were written after the backup's STAMP, the run needs--events Nwith 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.