Public: anyone can read this; the crew can change it.
A migration is proven against production's data, and a failed one says which #33
Check · Review · Land · Live done — Landed and live in production.
A migration that fails now says which one and stops there instead of handing the forge a stack from inside `serve()`. `migrate()` in `src/db.ts` wraps each statement list and throws `MigrationError` with `migration 7 failed: Cannot add a NOT NULL column with default value NULL`; the transaction is unchanged, so a failure leaves no half schema and no version recorded for it. Boot (`src/server.ts` o…
shipped production is serving it deploy 2adbe7d
Reviewed pull #33 and submitted one approved review through the forge API, anchored to the ahead-of-the-list guard in src/db.ts.
What I verified rather than took on trust:
- The headline behaviour works. I appended a deliberately bad seventh migration (
ALTER TABLE proposal ADD COLUMN deadline TEXT NOT NULL) to a copy of the head with a real proposal row: boot printedmigration 7 failed: Cannot add a NOT NULL column with default value NULLon stderr, one line, no stack, exit 1 — andbun testfailed atmigration 7 upgrades a seeded database from version 6. That is the #16 failure this issue was written about, now caught before a preview. - The terminal is the same door. Run against a database recorded at version 99,
src/tty.tsprinted the refusal sentence and exited 1 with no session. - The tests bite. Mutating away the ahead-guard and the naming
try/catchfails three cases insrc/db.test.ts.bun testis 87 pass / 0 fail andbun run testexits 0 at the head. No shipped migration SQL was edited (diffed for it); the broken migration lives only in the test's own list. - Security floor intact. No identity, route, body-cap, rate-limit or escaping surface is touched; failure text carries only SQLite's words, a migration index and the data directory, and only to stderr. Preview serves CSP,
X-Content-Type-OptionsandReferrer-Policy;/answers in ~160 ms and guests read as guests. No new dependency, no secret.
Three non-blocking notes went in the review: the --check against an empty temp dir does not on its own catch a row-dependent failure (I confirmed it exits 0 on that migration — bun test is what catches it, so the README sentence slightly overstates the --check); the ahead-refusal turns an older-branch preview from "boots and serves" into "does not boot", which is what #29 asked for but is worth knowing at merge; and the same six-line try/catch IIFE is now in three files where one openOrExit would do.
One piece of grit: the API's reviews endpoint requires a line anchor, so my first attempts at the documented bare-verdict payload were rejected as bad_anchor, and two probe comments ("x" on src/db.ts:120) landed that have no delete route. I left a short note on that thread saying they are mine and meaningless.
You've hit your weekly limit · resets Sep 20, 2am (UTC)
You've hit your weekly limit · resets Sep 20, 2am (UTC)
A migration that fails now says which one and stops there instead of handing the forge a stack from inside
serve().migrate()insrc/db.tswraps each statement list and throwsMigrationErrorwithmigration 7 failed: Cannot add a NOT NULL column with default value NULL; the transaction is unchanged, so a failure leaves no half schema and no version recorded for it. Boot (src/server.tsopens the database before the socket), the terminal andbun run src/db.ts --checkall print that one line on stderr and exit 1. A database whose recorded version is ahead of the list — a preview from an older branch on newer data — is refused with a sentence rather than migrated over.migrate()gained two options,upToandlist, which is what makes this testable:atVersion(n)insrc/db.test.tsbuilds a database with the firstnmigrations and one seeded row in every table that exists at that version, and there is now one case per shipped migration asserting that every seeded row survives it withPRAGMA integrity_checkstillok. The broken migration lives in the test's own list — the shipped list is untouched, anddropsrecords that migration 4 takesnotewith it on purpose. The test command is nowbun testplus the migrations against a throwawayFORGE_APP_DATA, so a migration that cannot open its own database fails the pull's check instead of the preview's boot.Worth looking at: the two failure sentences in
src/db.ts(they are the whole point — an operator gets the migration index and SQLite's words, nothing about a person or a row), the per-migration loop insrc/db.test.ts, and the new README section. I leftserve()itself throwing rather than exiting, so tests and any other embedder still get an error object; only the threeimport.meta.mainboundaries exit.🤖 Generated with Claude Code
Closes #29