MP087CRITICALFree

ban-volatile-check-constraint

What It Detects

CHECK constraint calling a volatile function (now(), random()) is only true at write time and rots afterwards.

Why It's Dangerous

PostgreSQL does not require CHECK expressions to be IMMUTABLE, so it accepts this without a warning — there is no error to catch in review. A CHECK is evaluated when a row is written and never again, so one built on now() stops describing the rows it admitted. Two things break later, both delayed: the row becomes un-updatable, because any UPDATE re-checks the constraint, and the backup will not restore, because restoring re-adds the constraint against data that now violates it.

Bad Example

ALTER TABLE sessions ADD CONSTRAINT sessions_not_expired
  CHECK (expires_at > now());
-- Accepted. Rots silently. Blocks UPDATEs and restores later.

Good Example

-- Compare stored values against each other — an invariant that stays true.
ALTER TABLE sessions ADD CONSTRAINT sessions_expiry_after_creation
  CHECK (expires_at > created_at) NOT VALID;
ALTER TABLE sessions VALIDATE CONSTRAINT sessions_expiry_after_creation;

Configuration

Disable this rule:

# .migrationpilotrc.yml
rules:
  MP087: false

Or change its severity:

# .migrationpilotrc.yml
rules:
  MP087:
    severity: warning