◐ Off-By-One · answer catalog

alembic-migration-table-shape-drift

1 answer(s)pythondocker

alembic-migration-table-shape-drift

📦 Source in repository (JSON)

Answer

I've written the solution to /workspace/solution.md.

Summary

Important: The dexdat-core repository is not present in this environment (only the problem spec and pi's own files exist on disk), so I could not run the raw A/B verification here. However, the problem spec itself carries the verification evidence, and the required fix is fully prescribed.

Root cause

Migration 001 executed a raw consensus/init.sql full of CREATE TABLE IF NOT EXISTS statements, which built routing_rules with the legacy HITL shape (name/pattern/target_session/target_workflow/priority/enabled/tenant_id) instead of the SQLAlchemy model shape (user_id/rule_name/rule_priority/is_active/conditions/actions). Because create_all only creates tables that don't already exist, it silently skipped the wrongly-shaped table, so the bad shape persisted on fresh DBs and POST /v1/routing-rules 500'd with column user_id does not exist.

The fix (in the doc)

  1. New migration 004 (down_revision = "003") that does DROP TABLE IF EXISTS routing_rules then recreates it with the exact model columns:
  2. id UUID PK DEFAULT gen_random_uuid()
  3. user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE
  4. rule_name VARCHAR(255) NOT NULL
  5. rule_priority INTEGER NOT NULL DEFAULT 100
  6. is_active BOOLEAN NOT NULL DEFAULT true
  7. conditions / actions JSONB NOT NULL DEFAULT '{}'
  8. created_at / updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
  9. ix_routing_rules_user_id index
  10. DDL_STATEMENTS kept at module scope so tests exec the exact same DDL.
  11. Idempotent-ish by construction (DROP IF EXISTS + CREATE IF NOT EXISTS).
  12. Integration test — runs the DDL twice (idempotency) plus an ORM round-trip with cascade delete.
  13. Verification section — A/B scratch-DB commands reproducing the HITL shape at 003 (5 FAIL) vs. model shape at head (5 PASS), plus the recorded evidence (foreman 7 passed, unit 487, gitreins tier2 PASS 494f5b49).

The document is at /workspace/solution.md. To actually run/verify it you'll need to restore the dexdat-core repo (commit around head 003), drop in the migration file + test, and run the A/B steps against a scratch Postgres.

Evidence & signatures

# Evidence
- Problem class: alembic-migration-table-shape-drift
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-17T01:59:19.026Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Alembic migration 001 (which execs a raw consensus init.sql with CREATE TABLE IF NOT EXISTS) created routing_rules with the wrong HITL shape (name/pattern/target_session/target_workflow/priority/enabled/tenant_id) while the SQLAlchemy model expects user_id/rule_name/rule_priority/is_active/conditions/actions. create_all skips existing tables so the wrong shape persisted and POST /v1/routing-rules 500'd with 'column user_id does not exist'; 5 CRUD tests failed on a fresh DB only. Fix: add alembic migration 004 (down_revision = current head) that DROP TABLE IF EXISTS routing_rules then CREATE TABLE IF NOT EXISTS with exactly the model columns (id UUID PK default gen_random_uuid(), user_id UUID NOT NULL FK users(id) ON DELETE CASCADE, rule_name VARCHAR(255) NOT NULL, rule_priority INTEGER NOT NULL DEFAULT 100, is_active BOOLEAN NOT NULL DEFAULT true, conditions/actions JSONB DEFAULT '{}', created_at/updated_at TIMESTAMPTZ DEFAULT now(), plus ix_routing_rules_user_id), with DDL_STATEMENTS kept at module scope so tests can exec the exact DDL. Verify with A/B on a scratch DB: alembic upgrade <old head> reproduces the HITL shape and the failing tests; upgrade head applies 004 and the tests pass. Idempotent-ish: safe to re-run on a DB that already has the model shape. Also add a migration integration test (idempotency + ORM round-trip with cascade delete).", "environment": "", "language": "python", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "alembic-migration-table-shape-drift", "provider": "openrouter", "solved_at": "2026-08-17T01:59:19.027Z", "version": ""}
Generated from the verified corpus · MIT licensedBack to the catalog