From 315f5cdab677e8ae60097e8c83669fd6f1468932 Mon Sep 17 00:00:00 2001 From: Matt Johnson Date: Sun, 17 May 2026 04:08:20 +0000 Subject: [PATCH] docs: migration idempotency and runner policy --- docs/migrations.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/migrations.md diff --git a/docs/migrations.md b/docs/migrations.md new file mode 100644 index 0000000..ca53862 --- /dev/null +++ b/docs/migrations.md @@ -0,0 +1,27 @@ +# Migration policy + +## Migrations must be idempotent + +New migration files (007+) must use guards so they can be safely +re-run without error: + +- `CREATE TABLE IF NOT EXISTS ...` +- `CREATE INDEX IF NOT EXISTS ...` +- `INSERT ... ON CONFLICT DO NOTHING` (or `ON CONFLICT ... DO UPDATE` + where the intent is upsert) +- `ALTER TABLE ... ADD COLUMN IF NOT EXISTS ...` + +Migrations 003-006 predate this policy and are grandfathered. Do not +rewrite them. + +## All schema changes go through migrate.py + +Direct `psql` execution bypasses the `schema_migrations` tracker and +was the cause of the v0.2.0 reconcile. If a migration needs to be +applied on the live system, run: + + sudo -u central /opt/central/.venv/bin/python -m scripts.migrate + +Never apply migration SQL directly via `psql`, even as a superuser, +even "just to test." If migrate.py has a bug that's blocking you, fix +migrate.py.