Public: anyone can read this; the crew can change it.
Preview boots fail on their own schema migration ("table already exists"): 11 of 12 failed deploys #580
Check · Review · Land · Live done — Landed and live in production.
Preview boots no longer fail on "table already exists". Migrations used to be counted by `user_version`, which is just their position in the list. A preview keeps its data across redeploys, so once a rebase renumbered a branch's migration, the next boot ran the same `CREATE` again. Now `src/kernel/migrate.ts` records each applied migration in a `schema_migration` table, keyed by a hash of its text…
shipped production is serving it deploy 9f16946
Sign in to join this conversation.
new above
offline
Preview boots no longer fail on "table already exists". Migrations used to be counted by
user_version, which is just their position in the list. A preview keeps its data across redeploys, so once a rebase renumbered a branch's migration, the next boot ran the sameCREATEagain. Nowsrc/kernel/migrate.tsrecords each applied migration in aschema_migrationtable, keyed by a hash of its text, and a boot runs only the ones it hasn't seen. A second boot does nothing.migrate()moved out ofsrc/kernel/db.tsinto the new module. A migration that moves position is still recognised.user_versionis still written as the count of applied migrations.user_versionmigrations are taken as applied once, as the number always meant. The exception is a migration whose table or added column is missing, which means the branch's migration sat at that number instead. Tables that a later migration in that range drops or renames are left out of that check (migration 29 rebuildslookthat way).CREATE TABLE/INDEX/TRIGGER/VIEWruns withIF NOT EXISTS, and anALTER TABLE … ADD COLUMNwhose column already exists is skipped.migration N failed at "<statement>": <sqlite message>, and that line becomes the deploy's failure summary shown on the pull. Nothing from the failed migration is applied.forge.db: the empty file #433 committed is removed, and.gitignorenow ignores/.db,/.db-waland/*.db-shmat the repo root.CLAUDE.mdanddocs/ARCHITECTURE.mdnow describe the tracking.test/schema-migrations.test.tsis new and in the gate. It boots a preview on copied production data twice, boots a branch whose migration a rebase renumbered, and boots a rebased branch on data the old runner wrote with the branch's table already there. It also covers a column that is already there, adoption of production's own pre-tracking data, refusal of data ahead of the build, the one-line failure throughfailureReason, and statement splitting. No existing test was changed.Not done: a build still refuses to run on data that has applied more migrations than it knows (e.g. a branch not rebased onto newer production data). That behaviour is deliberate and unchanged; per
docs/APPS.mda preview then retries once on empty data.Verification:
tsc --noEmitpass locally./tmp), which broke 179 tests. None of those were assertion failures. The forge check is the real verdict.test/usage.test.ts(not in the gate) fails the same way onmain.To try it:
bun test test/schema-migrations.test.ts.🤖 Generated with Claude Code
Closes #558