Files
leo-claude-mktplace/plugins/saas-db-migrate/skills/migration-safety.md
lmiranda 2d51df7a42 feat(marketplace): command consolidation + 8 new plugins (v8.1.0 → v9.0.0) [BREAKING]
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>
2026-02-06 14:52:11 -05:00

4.5 KiB

name, description
name description
migration-safety 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

Safe Column Addition

-- 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

-- 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

-- 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)