Data migration safety
Skill pipipip169/fable5-handoff/sources/adamentwistle-fable-skills/data-migration-safety
The retirement handoff of Claude Fable 5 - written by the model itself. Domain-neutral discipline files that transfer flagship working method to any model, any agent framework, any team.
npx -y skills add pipipip169/fable5-handoff --skill data-migration-safetyAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
3 things to look at
- 25 days oldThe repository was created 25 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Schema/data/wire-format changes — old data lives forever, expand→migrate→contract, idempotent dry-run batched bounded backfills, count reconciliation, rollback plan first. Use for schema changes, stored-JSON shape changes, backfills, or renaming/removing persisted or API fields.
SKILL.md
3.5 KB, as published. Nobody here has run it
Data Migration Safety
Code you can roll back; data you often can't. Any change touching persisted or wire formats gets treated as irreversible-by-default and sequenced so no moment exists where running code can't handle the data it meets.
The prime rule: old data lives forever
Every row/document/event written under the old shape still exists after your deploy. Reads must tolerate: missing new fields (default them), present old fields (ignore or map them), and malformed historical values (degrade gracefully, never crash or wipe — a parse failure on one bad record must not take down the collection). New required fields are only "required" for new writes.
Expand → migrate → contract (never in one step)
- Expand: add the new column/field/shape alongside the old. Code writes both (or writes new, reads either). Deploy. Nothing depends on the new shape yet.
- Migrate: backfill old records to the new shape. Verify counts.
- Contract: only after all readers use the new shape and backfill is verified — remove the old field/writes. This step is a separate deploy, days later, not minutes.
Collapsing these into one deploy creates the window where old code meets new schema (or new code meets old data) and errors page you at 2am. The same sequencing applies to API/event contracts: additive first, consumers migrate, then remove — coordinate with every consumer you can enumerate, and assume one you can't.
Backfill / data-fix scripts
- Idempotent: running it twice must be safe (filter to unmigrated rows; upsert, don't blind-insert). Scripts die mid-run; re-runnability is the recovery plan.
- Dry run first: a mode that reports what WOULD change (counts + samples) without writing. Review those counts against expectation — "expected ~2k rows, script says 1.4M" is the disaster caught early.
- Batched with progress: chunked commits, logged progress, resumable. One giant transaction locks the table and loses everything on failure.
- Bounded: an explicit WHERE clause scoping exactly the intended records. Fix scripts without a scope predicate eventually eat a table.
- Capture a before-image of affected rows (backup table, export) when the change is destructive — that's the rollback.
Verification gates
Before: count the affected set; back it up if destructive. After: recount (migrated + remaining + errored must reconcile to the before-count), spot-check samples end-to-end through the real read path (app code, not just SQL), and watch error rates after deploy. A migration is done when the numbers reconcile — not when the script exits 0.
Rollback thinking
Write down, before running: "if this is wrong, how do I get back?" Acceptable answers: restore from the before-image; the old field still exists (expand/contract); the script's inverse is trivial and tested. If the honest answer is "we can't" — that's a flag to surface for explicit sign-off, not a detail to skip past.
Repo-reality check
Migrations live wherever THIS project keeps them (some repos gitignore the migrations dir — then the commit message/docs must carry the SQL). Match the project's migration tooling and naming; never apply ad-hoc schema changes that bypass the project's migration history.