feat(db): zero-downtime migration safety lint + db-migrate skill#5041
Conversation
Add scripts/check-migrations-safety.ts (check:migrations), a CI gate that classifies statements in newly-added migrations into hard errors (rewrite), annotate-to-acknowledge contract ops (`-- migration-safe: <reason>`), and backfill warnings. Wire it into test-build.yml. Add the /db-migrate skill as the judgment half (expand/contract phasing, app-code cross-ref, annotation authoring). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryMedium Risk Overview CI and workflow: Reviewed by Cursor Bugbot for commit 4c3f3fa. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0b278d3. Configure here.
Greptile SummaryThis PR introduces a zero-downtime migration safety linter (
Confidence Score: 4/5Safe to merge with one linter gap to address: ADD CONSTRAINT UNIQUE/PRIMARY KEY on existing tables currently passes CI without any check, despite taking an ACCESS EXCLUSIVE lock identical to the FK case the linter does catch. The linter logic is solid and the new DROP INDEX CONCURRENTLY hardening is correctly implemented. The one remaining gap — ADD CONSTRAINT UNIQUE and PRIMARY KEY on existing tables not being flagged — means a real category of lock-downtime migrations can land undetected. It is an omission in a new tool, not a regression in production code, but it leaves a hole in the safety net the PR is explicitly building. scripts/check-migrations-safety.ts — the constraint-not-valid guard needs to cover UNIQUE and PRIMARY KEY with a dedicated hard-error message pointing to the CONCURRENTLY index + USING INDEX path. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[New migration .sql files\nvia git diff vs base] --> B[parseStatements\nrespects strings / dollar-quotes]
B --> C{classify statement}
C -->|CREATE INDEX\nno CONCURRENTLY| E1[❌ index-not-concurrent]
C -->|CONCURRENTLY\nno IF NOT EXISTS| E2[❌ concurrent-index-not-idempotent]
C -->|CONCURRENTLY\nno COMMIT breakpoint| E3[❌ concurrent-index-no-commit]
C -->|ADD COLUMN NOT NULL\nno DEFAULT| E4[❌ add-not-null-no-default]
C -->|RENAME COLUMN/TABLE| E5[❌ rename]
C -->|ADD CONSTRAINT FK/CHECK\nno NOT VALID| E6[❌ constraint-not-valid]
C -->|DROP INDEX\nno CONCURRENTLY| E7[❌ drop-index-not-concurrent]
C -->|DROP INDEX CONCURRENTLY\nno IF EXISTS| E8[❌ concurrent-drop-index-not-idempotent]
C -->|DROP TABLE/COLUMN\nDROP DEFAULT, SET NOT NULL\nalter-type, drop-constraint| ANN[annotate-tier op]
C -->|UPDATE / DELETE| W[⚠ data-backfill warning]
ANN --> GA{preceding line has\nmigration-safe annotation?}
GA -->|yes, with reason| OK[✓ pass]
GA -->|annotation empty| E9[❌ no reason]
GA -->|missing| E10[❌ unannotated contract op]
C -->|ADD CONSTRAINT UNIQUE\nPRIMARY KEY| MISS[⚠️ NOT CHECKED — gap]
style MISS fill:#f99,stroke:#c00
style E1 fill:#fdd
style E2 fill:#fdd
style E3 fill:#fdd
style E4 fill:#fdd
style E5 fill:#fdd
style E6 fill:#fdd
style E7 fill:#fdd
style E8 fill:#fdd
style E9 fill:#fdd
style E10 fill:#fdd
|
|
@greptile review |
… false-positive, alter-type literal match - Non-concurrent DROP INDEX is now a hard error (ACCESS EXCLUSIVE lock), symmetric with CREATE INDEX; DROP INDEX CONCURRENTLY after a COMMIT passes clean. Removes the false-confidence annotate path. - RENAME rule narrowed to RENAME COLUMN / table RENAME TO; RENAME CONSTRAINT and ALTER INDEX ... RENAME (metadata-only) no longer flagged. - alter-type regex now requires TYPE to follow the column identifier, so it no longer matches TYPE inside a string default. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks @greptile-apps — all three classifier findings were valid and are fixed in 84093a2:
Added regression tests for each (27 tests pass). Skill playbook updated with the DROP INDEX CONCURRENTLY guidance. @greptile review |
…potency Symmetric with the CREATE INDEX CONCURRENTLY rule: a post-COMMIT DROP INDEX CONCURRENTLY replays from the top on failure, so without IF EXISTS it aborts re-dropping an already-gone index. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Fixed in be6d0bc — @greptile review |
…ion base to staging - /ship runs /cleanup only when the diff touches UI code (.tsx or apps/sim/components|hooks|stores); the six passes are React-only. - /ship runs check:migrations against origin/staging (the PR base). - check:migrations default baseRef is now origin/staging instead of origin/main. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rops Establishes a durable, greppable marker (`contract-pending(<precondition>): ...`) left on the legacy column in schema.ts when an expand defers a drop, so the contract phase doesn't rot. The outstanding-work list is `grep -rn contract-pending`; the contract PR's `-- migration-safe:` annotation references the expand and deletes the marker. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Summary
check:migrationslint (scripts/check-migrations-safety.ts) — a CI gate that scans newly-added migrations for backward-incompatible changes that break the previously-deployed app during the blue/green window. Tiers: hard errors (rewrite), annotate-to-acknowledge contract ops (-- migration-safe: <reason>), and backfill warnings. Scoped to new migrations via git-diff; existing corpus grandfathered./db-migrateskill — the judgment half: expand/contract phasing, app-code cross-reference, and authoring the annotation the lint requires.check:migrationsinto test-build.yml, and make/shiprun/cleanup+ the migration-safety review.Type of Change
Testing
bun test scripts/check-migrations-safety.test.ts)DROP COLUMN workspace_idthat caused the SlackTrigger query failure; a context-free agent following the skill independently reached NOT SAFE + the correct expand/contract splitbun run check:api-validation:strictpassed; biome cleanChecklist