Phase 1b: Rename all ~94 commands across 12 plugins to /<noun> <action> sub-command pattern. Git-flow consolidated from 8→5 commands (commit variants absorbed into --push/--merge/--sync flags). Dispatch files, name: frontmatter, and cross-reference updates for all plugins. Phase 2: Design documents for 8 new plugins in docs/designs/. Phase 3: Scaffold 8 new plugins — saas-api-platform, saas-db-migrate, saas-react-platform, saas-test-pilot, data-seed, ops-release-manager, ops-deploy-pipeline, debug-mcp. Each with plugin.json, commands, agents, skills, README, and claude-md-integration. Marketplace grows from 12→20. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
120 lines
4.5 KiB
Markdown
120 lines
4.5 KiB
Markdown
---
|
|
name: migration-safety
|
|
description: Rules for detecting destructive operations, data loss risks, and long-running locks
|
|
---
|
|
|
|
# Migration Safety
|
|
|
|
## Purpose
|
|
|
|
Defines safety rules for analyzing database migrations. This skill is loaded by both the `migration-planner` (during generation) and `migration-auditor` (during validation) agents to ensure migrations do not cause data loss or operational issues.
|
|
|
|
---
|
|
|
|
## Destructive Operations
|
|
|
|
### FAIL-Level (Block Migration)
|
|
|
|
| Operation | Risk | Detection Pattern |
|
|
|-----------|------|-------------------|
|
|
| `DROP TABLE` | Complete data loss | `DROP TABLE` without preceding backup/export |
|
|
| `DROP COLUMN` | Column data loss | `DROP COLUMN` without verification step |
|
|
| `ALTER COLUMN` type narrowing | Data truncation | VARCHAR(N) to smaller N, INTEGER to SMALLINT |
|
|
| `ALTER COLUMN` SET NOT NULL | Failure if NULLs exist | `SET NOT NULL` without DEFAULT or backfill |
|
|
| `TRUNCATE TABLE` | All rows deleted | `TRUNCATE` in migration file |
|
|
| `DELETE FROM` without WHERE | All rows deleted | `DELETE FROM table` without WHERE clause |
|
|
| Missing transaction | Partial migration risk | DDL statements outside BEGIN/COMMIT |
|
|
|
|
### WARN-Level (Report, Continue)
|
|
|
|
| Operation | Risk | Detection Pattern |
|
|
|-----------|------|-------------------|
|
|
| `RENAME TABLE` | App code must update | `ALTER TABLE ... RENAME TO` |
|
|
| `RENAME COLUMN` | App code must update | `ALTER TABLE ... RENAME COLUMN` |
|
|
| `ALTER COLUMN` type widening | Usually safe but verify | INTEGER to BIGINT, VARCHAR to TEXT |
|
|
| `CREATE INDEX` (non-concurrent) | Table lock during build | `CREATE INDEX` without `CONCURRENTLY` |
|
|
| Large table ALTER | Extended lock time | Any ALTER on tables with 100K+ rows |
|
|
| Mixed schema + data migration | Complex rollback | DML and DDL in same migration file |
|
|
| Missing downgrade/rollback | Cannot undo | No downgrade function or DOWN section |
|
|
|
|
### INFO-Level (Suggestions)
|
|
|
|
| Operation | Suggestion | Detection Pattern |
|
|
|-----------|-----------|-------------------|
|
|
| No-op migration | Remove or document why | Empty upgrade function |
|
|
| Missing IF EXISTS/IF NOT EXISTS | Add for idempotency | `CREATE TABLE` without `IF NOT EXISTS` |
|
|
| Non-concurrent index on PostgreSQL | Use CONCURRENTLY | `CREATE INDEX` could be `CREATE INDEX CONCURRENTLY` |
|
|
|
|
---
|
|
|
|
## Lock Duration Rules
|
|
|
|
### PostgreSQL
|
|
|
|
| Operation | Lock Type | Duration |
|
|
|-----------|-----------|----------|
|
|
| ADD COLUMN (no default) | ACCESS EXCLUSIVE | Instant (metadata only) |
|
|
| ADD COLUMN with DEFAULT | ACCESS EXCLUSIVE | Instant (PG 11+) |
|
|
| ALTER COLUMN TYPE | ACCESS EXCLUSIVE | Full table rewrite |
|
|
| DROP COLUMN | ACCESS EXCLUSIVE | Instant (metadata only) |
|
|
| CREATE INDEX | SHARE | Proportional to table size |
|
|
| CREATE INDEX CONCURRENTLY | SHARE UPDATE EXCLUSIVE | Longer but non-blocking |
|
|
| ADD CONSTRAINT (CHECK) | ACCESS EXCLUSIVE | Scans entire table |
|
|
| ADD CONSTRAINT NOT VALID + VALIDATE | Split: instant + non-blocking | Recommended for large tables |
|
|
|
|
### MySQL
|
|
|
|
| Operation | Lock Type | Duration |
|
|
|-----------|-----------|----------|
|
|
| Most ALTER TABLE | Table copy | Proportional to table size |
|
|
| ADD COLUMN (last position) | Instant (8.0+ some cases) | Depends on engine |
|
|
| CREATE INDEX | Table copy or instant | Engine-dependent |
|
|
|
|
---
|
|
|
|
## Recommended Patterns
|
|
|
|
### Safe Column Addition
|
|
```sql
|
|
-- Good: nullable column, no lock
|
|
ALTER TABLE users ADD COLUMN middle_name VARCHAR(100);
|
|
|
|
-- Then backfill in batches (separate migration):
|
|
UPDATE users SET middle_name = '' WHERE middle_name IS NULL;
|
|
|
|
-- Then add constraint (separate migration):
|
|
ALTER TABLE users ALTER COLUMN middle_name SET NOT NULL;
|
|
```
|
|
|
|
### Safe Column Removal
|
|
```sql
|
|
-- Step 1: Remove from application code first
|
|
-- Step 2: Verify column is unused (no queries reference it)
|
|
-- Step 3: Drop in migration
|
|
ALTER TABLE users DROP COLUMN IF EXISTS legacy_field;
|
|
```
|
|
|
|
### Safe Type Change
|
|
```sql
|
|
-- Step 1: Add new column
|
|
ALTER TABLE orders ADD COLUMN amount_new NUMERIC(10,2);
|
|
-- Step 2: Backfill (separate migration)
|
|
UPDATE orders SET amount_new = amount::NUMERIC(10,2);
|
|
-- Step 3: Swap columns (separate migration)
|
|
ALTER TABLE orders DROP COLUMN amount;
|
|
ALTER TABLE orders RENAME COLUMN amount_new TO amount;
|
|
```
|
|
|
|
---
|
|
|
|
## Pre-Migration Checklist
|
|
|
|
Before applying any migration in production:
|
|
|
|
1. Database backup completed and verified
|
|
2. Migration validated with `/db-migrate validate`
|
|
3. Execution plan reviewed with `/db-migrate plan`
|
|
4. Rollback strategy documented and tested
|
|
5. Maintenance window scheduled (if required by lock analysis)
|
|
6. Application deployment coordinated (if schema change affects code)
|