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