Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 12s
Build ErsatzTV Image / decisions.md append-only (pull_request) Successful in 14s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 20s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 20s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 4m25s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 5m36s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
CI's migrations job only proves a migration is well-formed against a fresh, empty DB. It never exercises the migration — or ErsatzTV's startup data steps (DatabaseMigratorService -> DbInitializer + PopulatePathHashes over the real MediaFile table) — against the accumulated prod SQLite, so a migration green on a fresh DB can still fail/corrupt on prod, found only mid-deploy. scripts/migration-smoke.sh rehearses it on a THROWAWAY copy of the latest prod backup: boots the new image against the copy, gates PASS on the "Done applying database migrations" log line (the migrator is a BackgroundService running concurrently with Kestrel, so HTTP readiness alone doesn't prove migrations finished), FAILs on early container exit / migration exception / timeout / not serving afterwards. Always operates on a copy, never the live DB; tears down its container + temp dir (incl. the container's root-owned config files) on exit. Validated live 2026-07-12: :latest vs a copy of the 283MB prod backup -> migrations applied cleanly, app booted+served, temp dir removed. Home split: this repo owns the script + docs; wiring it into the Komodo pre-deploy step is server-management#589 (cross-repo). Docs: docs/ci-cd.md (Migration integrity), docs/decisions.md (new entry, pure insertion). fixes #315 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>