Skip to content

CI gate: fail PRs that add a migration without updating schema.py #713

Description

@AndriiPasternak31

Context

Follow-up to #691 / PR #712.

#691 backfilled src/backend/db/schema.py with 11 tables, 14 columns, and ~22 indexes that existed only in src/backend/db/migrations.py. The fix re-encoded the drift class — there is no automated check preventing the next contributor from adding a migration without updating schema.py. In 6 months, the same drift will accumulate again unless we close the loop.

This was raised by both Codex and an independent Claude subagent during the autoplan dual-voice CEO review for #691, and approved at the final approval gate (D2 = B) as a follow-up issue to be filed alongside the implementation PR.

Proposal

Add a CI check that runs the parity verification scripts already documented in #691's plan against every PR that touches src/backend/db/migrations.py:

  1. Spin up an in-memory SQLite database, run init_schema() only, snapshot state.
  2. Run run_all_migrations(), snapshot state again.
  3. Diff tables, columns, indexes. Filter schema_migrations (created internally by run_all_migrations).
  4. Run a strict DDL parity check: normalize whitespace and lowercase the sqlite_master.sql text, compare entry-by-entry. Fail on any MISSING or DIFFERENT line.

Implementation sketch

A small Python check at scripts/check-schema-parity.py (or tests/unit/test_schema_parity.py so it runs with the existing test suite). The verification script from #691's plan is essentially the spec — it works against the current branch (verified during autoplan) and produces empty output when schema.py is faithful.

Wire into CI by:

  • Running it as part of tests/run-core.sh (Tier 2 pre-commit checks)
  • Adding a GitHub Actions job that runs only when src/backend/db/migrations.py or src/backend/db/schema.py changes (path filter)

Acceptance criteria

  • Script lives at a discoverable path and exits non-zero on drift
  • CI runs the script on every PR that touches migrations.py or schema.py
  • Adding a migration without updating schema.py produces a CI failure with a clear "schema.py drift detected" message naming the missing table/column/index
  • The check runs against the same dual-pass behavior as init_database() so it stays consistent with production semantics

Out of scope

  • Collapsing the two-source-of-truth pattern (e.g., migrating to Alembic, generating schema.py from migrations) — separate, larger discussion.

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions