RS-REVERSE-001 — DROP COLUMN loses its data irreversibly
Namespace: RS-REVERSE · Code: RS-REVERSE-001
What it means
Section titled “What it means”Dropping a column permanently removes its values across every row. A down-migration can recreate the column, but not what it held — the rollback is lossy.
Why it matters
Section titled “Why it matters”A down-migration that recreates the column brings it back empty. If the drop was a mistake, or the release has to be rolled back, the values are gone unless you kept a copy.
Example
Section titled “Example”Production shape: public.users has 400,000 rows, most with a legacy_notes value. This migration produces RS-REVERSE-001 against it:
ALTER TABLE public.users DROP COLUMN legacy_notes;The fixture this example is checked against
rowshape_fixture: "1"meta: {id: example, engine: {name: postgres, version: "16"}, privacy: standard, profile: {mode: fast, escalated: []}}tables: public.users: rows: {value: 400000, confidence: exact} columns: id: {type: bigint, nullable: false, unique: {value: true, confidence: exact, via: constraint}} legacy_notes: {type: text, nullable: true, null_fraction: {value: 0.2, confidence: estimated, via: pg_stats}} constraints: [{name: users_pkey, kind: primary_key, columns: [id]}]How to fix
Section titled “How to fix”Drop in two phases across separate deploys: first stop writing and reading the column and ship that, then drop it in a later migration once you are sure it is unused. Take a backup (or snapshot the column into an archive table) before the drop so the data is recoverable.
For the example above. Stop reading and writing the column and ship that first. Keep a copy of the values, then drop the column in a later migration.
CREATE TABLE public.users_legacy_notes_archive AS SELECT id, legacy_notes FROM public.users WHERE legacy_notes IS NOT NULL;SET lock_timeout = '3s';ALTER TABLE public.users DROP COLUMN legacy_notes;Related codes
Section titled “Related codes”RS-REVERSE-002— DROP TABLE loses every row irreversiblyRS-DEPLOY-001— Renaming a column or table breaks running code that still uses the old nameRS-REVERSE-003— Narrowing a column type can truncate data irreversibly
This page is generated from the same catalog rowshape explain RS-REVERSE-001 reads, so the remediation here is byte-identical to the one a verdict carries — they cannot drift. An agent can read it with the explain_finding MCP tool. The example is run against PostgreSQL 16 by rowshape’s test suite: the first migration must produce RS-REVERSE-001 and the fix must not fail.