Defective repair

Unsafe
The previous application version reproducibly fails against the proposed schema, and the failure is linked to a specific schema change.

A "repair" for the rename that adds email_address as NOT NULL. v1 never writes it.

Recorded example: genuine engine output generated Sat, 24 Oct 2026 18:30:03 GMT from the committed fixture. Run it again live below.

Baseline schema
Proposed schema
Previous versionshop-v1
2/2 test files passno database errors
0/2 test files passSQLSTATE 23502, identical in all 2 runs
Current versionG-defective-repair
Not needed: ordinary CI covers this
0/1 test files passSQLSTATE 23502

The outlined cell is the compatibility question. The verdict comes only from it, compared against the cell to its left.

Why

  1. test/customers.test.js: SQLSTATE 23502 (not_null_violation) linked to column_added:customers.email_address by R3 not_null_violation ↔ new NOT NULL requirement.
  2. test/orders.test.js: SQLSTATE 23502 (not_null_violation) linked to column_added:customers.email_address by R3 not_null_violation ↔ new NOT NULL requirement.

Next step

Make the migration backward compatible (expand/contract: keep the old shape until the old version is retired), then re-run the gate.

Starts a throwaway PostgreSQL and runs the full experiment, usually in under 15 seconds.

Evidence

Regression test/customers.test.js

Observed
test/customers.test.js passes on the baseline schema and fails in all 2 candidate runs.
Database error
SQLSTATE 23502 not_null_violation — null value in column "email_address" of relation "customers" violates not-null constraint
INSERT INTO customers (name, email) VALUES ($1, $2) RETURNING id
Interpretation
Column customers.email_address now requires a value that the old application's statement does not supply.
Rule
R3 not_null_violation ↔ new NOT NULL requirement (strong correlation)
Linked change
column_added:customers.email_address

Regression test/orders.test.js

Observed
test/orders.test.js passes on the baseline schema and fails in all 2 candidate runs.
Database error
SQLSTATE 23502 not_null_violation — null value in column "email_address" of relation "customers" violates not-null constraint
INSERT INTO customers (name, email) VALUES ($1, $2) RETURNING id
Interpretation
Column customers.email_address now requires a value that the old application's statement does not supply.
Rule
R3 not_null_violation ↔ new NOT NULL requirement (strong correlation)
Linked change
column_added:customers.email_address

Schema changes

1 of 1 risk-bearing schema change(s) were exercised by the old application's tests in the control run.

ChangeRisk to old statementsExercised by previous version
Column customers.email_address added (text NOT NULL)
NOT NULL without a default: inserts from the old application will omit it.
breakingYes, 2 statements in test/customers.test.js, test/orders.test.js

Runs

Proposed migration: 002_rename_email.sql · PostgreSQL 16.15 (Debian 16.15-1.pgdg12+2) · gate blocks the pipeline (exit 1)

RunMigrationsTest filesDatabase errorsStatements logged
control (old app × baseline schema)1/12/2 pass07
candidate #1 (old app × proposed schema)2/20/2 pass2 (23502)2
candidate #2 (old app × proposed schema)2/20/2 pass2 (23502)2
current app × proposed schema (context)2/20/1 pass1 (23502)1

Download this report: JSONMarkdownJUnit XML

What this result does not cover
  • Performance / lock-time analysis (out of scope).
  • Skewcheck only observes code paths that the old application's tests execute; untested paths are reported as coverage gaps, not as safe.
  • Coverage is identifier-level: a statement "touches" a changed object when it names the table (and column, or uses *). It is not a SQL parser.
  • Correlation between an error and a schema change uses a fixed set of deterministic rules (R1–R6). Anything else is reported as ADVISORY, never UNSAFE.
  • Performance, locking and migration runtime on production-sized data are not evaluated.
  • Test files of one run share a database and run sequentially; ordering effects are identical across runs but are not isolated.
  • Data-only migration effects are detected only when a test asserts on the affected data.