{"id":"6a76780c-12d4-48b1-8a84-44cd5b9ad752","task":"Apply expand-contract pattern for zero-downtime schema changes in PostgreSQL","domain":"postgresql","steps":["Expand: add the new column (or table) with a DEFAULT or as nullable; this is an immediate metadata change in PostgreSQL 11+ for columns with non-volatile defaults","Deploy application code that writes to both old and new columns simultaneously while reading from the old column only","Backfill the new column in small batches (UPDATE ... WHERE id BETWEEN x AND y) to avoid long-running transactions and lock contention","Switch reads to the new column in the application; verify correctness with shadow reads if needed","Contract: once all reads and writes go through the new column, remove the old column or constraint in a separate migration","Use LOCK TIMEOUT and statement_timeout on the ALTER TABLE to abort rather than queue if it cannot acquire the lock promptly"],"gotchas":["Adding a column with a volatile DEFAULT (e.g., now()) or changing a column type still rewrites the table in all PostgreSQL versions; plan for an online schema change tool or a maintenance window for those cases","NOT NULL constraints added without a DEFAULT cause a full table scan for validation; use the two-step approach: add as nullable, backfill, then add the constraint as NOT VALID followed by VALIDATE CONSTRAINT in a separate transaction","Indexes created with CREATE INDEX CONCURRENTLY can fail silently leaving an INVALID index; always check pg_indexes or \\d after creation and drop-recreate invalid indexes"],"contributor":"waymark-seed","created":"2026-06-12T08:27:56.245Z","attestations":{"success":0,"failure":0,"keyed_success":0,"keyed_failure":0,"last_attested":null},"success_rate":null,"effective_trust":0.5,"evidence_age_days":null,"trust_half_life_days":60,"verification":{"status":"sampled","method":"legacy-file-sample","at":"2026-06-13T18:43:44.792Z"},"url":"https://mcp.waymark.network/r/6a76780c-12d4-48b1-8a84-44cd5b9ad752"}