Skip to content

Fix remote D1 migrations with atomic imports#508

Merged
doodlewind merged 2 commits into
mainfrom
fix/d1-projects-migration
Jul 26, 2026
Merged

Fix remote D1 migrations with atomic imports#508
doodlewind merged 2 commits into
mainfrom
fix/d1-projects-migration

Conversation

@doodlewind

Copy link
Copy Markdown
Contributor

What changed

  • replace production and staging wrangler d1 migrations apply --remote with a checked-in remote migration runner
  • apply each pending migration through D1's atomic file-import endpoint and write d1_migrations in the same transaction
  • validate that the remote ledger is an exact prefix before and after every import
  • add an in-transaction expected-count guard so concurrent/manual runners cannot commit divergent next migrations
  • fail closed on malformed Wrangler output, unsafe migration names, explicit transactions, and unterminated SQL
  • add focused runner and deployment-contract tests

Root cause

0014_projects.sql is valid SQLite (41,414 bytes, 76 statements; largest statement 4,740 bytes), but Wrangler's remote migration command sends the entire migration plus ledger write through D1's /query endpoint, which returns incomplete input. The same file succeeds through D1's /import pipeline. This is an endpoint-specific ingestion/parser divergence, not bad production data or a statement-size violation.

Impact

Production deployment can apply the Project schema safely and reproducibly. Failed imports restore the previous database state, and retries resume from the verified ledger without partial schema/ledger commits.

Validation

  • pnpm exec vp check
  • pnpm vp run --no-cache --filter '@spool/backend^...' build
  • pnpm --filter @spool/backend run schema:smoke (14 migrations)
  • pnpm --filter @spool/backend run typecheck
  • pnpm --filter @spool/backend test (36 files, 542 tests)
  • focused remote-runner suite (12 tests)
  • disposable remote D1: applied 0014, second run no-op, forced SQL failure rolled back both schema and ledger
  • staging D1: expected-count guard succeeds at 14; stale count fails with SQLITE_CONSTRAINT_CHECK, leaving no guard/probe tables and ledger at 14

@doodlewind
doodlewind added this pull request to the merge queue Jul 26, 2026
Merged via the queue into main with commit 1a80ab1 Jul 26, 2026
5 checks passed
@doodlewind
doodlewind deleted the fix/d1-projects-migration branch July 26, 2026 03:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant