Fix M7 clip-columns migration failing against a populated database - #27
Merged
Merged
Conversation
batch_alter_table's SQLite "recreate the table" strategy drops the original `asset` table, and SQLite enforces foreign keys on DROP TABLE too (an implicit "as if every row were deleted" check). Every connection here runs with PRAGMA foreign_keys=ON, so the drop was refused the moment any other table (assettag, suggestion) held a real row referencing an asset — which any populated database has and an empty one never does, so no existing test caught it. Disable the pragma for just this table rebuild, in both directions since downgrade() recreates asset too. Verified against a seeded SQLite db reproducing the exact production failure (FOREIGN KEY constraint failed on DROP TABLE asset), confirmed the fix resolves it with no data loss and an intact foreign_key_check, and added a regression test that seeds a real cross-reference before migrating so this can't silently regress. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KzCKjg6yBtAwMFwZmezuw1
davior
marked this pull request as ready for review
September 18, 2026 06:35
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
M7 (davior/gam#26) took production down on deploy:
alembic upgrade headfailed inside the newadd_clip_columns_to_assetmigration withsqlite3.IntegrityError: FOREIGN KEY constraint failedonDROP TABLE asset, and since migrations run before uvicorn binds a port (entrypoint.sh), the backend container never came up — crash-looping underrestart: unless-stopped.Root cause:
batch_alter_table's SQLite "recreate the table" strategy (needed to add a real foreign key to an already-existing table) drops the originalassettable and renames a rebuilt copy into place. SQLite enforces foreign keys onDROP TABLEtoo — an implicit "as if every row were deleted" check — and every connection here runs withPRAGMA foreign_keys=ON(app/database.py's connect listener, whichalembic/env.pyinherits since it reuses the app's own engine). The drop was refused the instant another table (assettag,suggestion) held a real row referencing anassetrow.No existing test caught this because every migration test runs against a freshly-created, empty database — there's nothing yet in
assettag/suggestionto violate at the moment schema migrations run. Any populated database — i.e. every real deployment — hits this every time.Changes
backend/alembic/versions/20260918_0900_add_clip_columns_to_asset.py: disablePRAGMA foreign_keysfor the duration of the table rebuild, in bothupgrade()anddowngrade()(downgrade recreatesassettoo).backend/tests/test_migrations.py: new regression test that seeds a realasset→assettagcross-reference before running this migration (mirroring what any populated database actually has), then asserts the upgrade succeeds andPRAGMA foreign_key_checkreports zero violations afterward.Verification
FOREIGN KEY constraint failedonDROP TABLE asset).PRAGMA foreign_key_checkclean.downgrade()also works cleanly against the same populated database, and that upgrade is repeatable.cd backend && pytest -q— 830 passed.cd frontend && npm test -- --run— 264 passed (no frontend files touched by this change).Deploy notes for this environment
Production (
/opt/gamondebian-flight-tracker-01) currently has an orphaned_alembic_tmp_assettable left over from the failed migration attempts, and the backend container is crash-looping. Recovery, once this PR is merged and pulled:The real
assettable itself was never touched by the failed attempts (confirmed: 15 rows, all present) — only the leftover temp copy needs clearing.🤖 Generated with Claude Code
https://claude.ai/code/session_01KzCKjg6yBtAwMFwZmezuw1
Generated by Claude Code