PG.L4.DROP_WITHOUT_DEPLOY_WINDOW — The previous release is still running
- Category: safety
- Level: 4
- Confidence: heuristic
- Downtime class:
online - Stability: stable
- Suites: lint
- Applies to: PostgreSQL 18
PG.L1.DROP_TABLE and PG.L1.DROP_COLUMN are about permanence. This rule is about timing, which
is why the same statement can produce both findings and they are not duplicates.
A drop takes effect the moment the migration commits. During a rolling deploy that moment lands in the middle of a period where the previous release is still serving traffic — and still selecting the object that just stopped existing. The errors start immediately, they come from instances that were healthy a second ago, and they stop only when the last old instance is replaced.
Why heuristic
The rule cannot see your deploy process. A project that stops all traffic, migrates, then starts the new release has no overlap window and no problem. A project doing blue/green or a rolling restart does. The finding names the risk; whether it applies is something only your pipeline knows, and it is a perfectly reasonable one to accept with a reason.
Flagged
DB::statement('DROP TABLE legacy_events');
Preferred
// An irreversible drop belongs in a scheduled maintenance window, after a release that
// stopped reading the table, in a migration annotated #[SqlensAllowDestructive]:
Schema::rename('legacy_events', 'legacy_events_pending_drop');
The rename is the useful part of the pattern. It makes the object unusable by accident — so anything still reading it fails loudly and immediately, in a way you can find — while keeping the data recoverable until somebody deliberately finishes the job.
The expand–contract sequence
- Expand. Add the new shape. Both releases work.
- Migrate. Move readers and writers to it. Ship. Wait for the old release to be gone.
- Contract. Drop the old shape, in its own migration, with the destructive annotation.
Steps 1 and 3 in one deploy is the whole failure this rule describes.
The maintenance-window field
Findings that need one carry a maintenance_window note in the report — machine-readable, so a
deploy script can branch on it rather than a human having to remember. That field is why the rule
exists at level 4 rather than being folded into the level-1 destructive gate.
Sources
- PostgreSQL 18 —
ALTER TABLE— dropping a table or column takes effect immediately on commit; an application instance still running the previous release fails from that moment
The fix material this rule carries
A finding from this rule carries machine-readable fix material, using this sequence:
deploy_window_drop— Drop across two deploy windows so a rollback in between still finds what it needs.
The payload is material for you or an agent to apply. SQLens writes no migration and runs no DDL. See the remediation payload for every field, the placeholder semantics, and the version rules a consumer has to follow.