Reference Migration Standard
What changes when a rename is treated as a graph migration instead of a text rewrite?
A reference migration changes the relationship between named things. A file move, command rename, API path change, folder restructure, skill rename, or metadata relabel is not complete when the text compiles. It is complete when every live edge points to the new node, every generated edge is regenerated by its owner, and every historical note is deliberately left alone or explicitly migrated.
This standard exists because broad search-and-replace can preserve surface consistency while destroying local intent. The failure mode is simple: an agent sees many stale strings, runs a repo-wide rewrite, and edits files that were never part of the migration. The deterministic improvement is a manifest-first protocol.
Skill renames are reference migrations too. The skill directory, name metadata, trigger phrases, NOT-for clauses, registry rows, evals, docs references, settings, hooks, receipts, and historical plans are all edges around the skill node. Classify those edges before editing.
The Rule
Do not run a broad rewrite until the migration manifest exists.
The manifest is the work contract. It names:
- Old token — the exact path, command, import, route, metadata label, or phrase being retired.
- New token — the replacement, or
nonewhen the edge should disappear. - Live surfaces — files whose references affect current execution, navigation, builds, hooks, docs, or agent procedure.
- Historical surfaces — receipts, memories, old plans, archived workcharts, or evidence where old names may remain as history.
- Generated surfaces — files updated only by their generator.
- Do-not-touch surfaces — files with active user edits, external ownership, or deliberate legacy examples.
- Proof — the commands that prove live edges moved and generated edges were rebuilt.
If a file is not in the manifest, do not edit it.
Edge Types
Classify every hit before changing it.
- Live edge — affects a current caller, import, link, hook, package alias, source comment, skill instruction, or operator command. Update it.
- Generated edge — appears in generated artifacts. Regenerate through the owning command; do not hand-edit.
- Historical note — records what happened before. Leave it unless the migration explicitly includes historical normalization.
- Receipt or evidence — proves a past run. Preserve original wording unless it blocks a live gate.
- Do-not-touch — active user work, host-owned config, archived external content, or intentionally broken example. Exclude it.
This classification turns a text list into a relationship map. The important question is not "where does the string appear?" The important question is "what does this edge do?"
Procedure
- Inventory nodes. List every old token and the intended new token. Include casing, shell form, package alias, route form, and import form when they differ.
- Find edges. Use
rg -nfirst. Search likely live surfaces before historical surfaces. - Classify hits. Mark each hit as live, generated, historical, receipt, or do-not-touch.
- Review the write set. Convert only reviewed live hits into an edit list. If the edit list includes unrelated files, stop.
- Rewrite narrowly. Use the reviewed file list, not
find .. Prefer structured edits for code and config. - Regenerate artifacts. Run the owning generator for generated edges.
- Prove closure. Run the manifest proof commands and keep the output in the PR or close note.
Forbidden default:
find . -type f -exec perl -0pi -e 's|old|new|g' {} +
Allowed shape:
rg -l "old-token" package.json scripts .husky .claude/hooks .codex/hooks docs src \
| sort
Then inspect the file list, remove historical and do-not-touch surfaces, and edit only the approved list.
Manifest Template
Reference migration: <name>
Old token(s):
- <old>
New token(s):
- <new>
Live surfaces:
- <path or glob> — <why live>
Generated surfaces:
- <path or glob> — generated by <command>
Historical surfaces:
- <path or glob> — leave|migrate, because <reason>
Do-not-touch:
- <path or glob> — <owner or active-edit reason>
Rewrite method:
- <manual patch | reviewed rg -l list | structured parser>
Proof:
- <command>
- <command>
Proof
A migration is closed only when proof distinguishes live references from historical residue.
Minimum proof:
rg -n "<old-token>" <live-surfaces>
rg -n "<old-token>" <historical-surfaces>
git diff --check
The first command should return no unintended live hits. The second command may return historical hits only if the manifest says they are allowed.
For docs links, run:
node scripts/quality/validate-links.js --format=json
For generated docs navigation or artifacts, run the owning --check command or generator. Generated files are never the first edit surface.
Context
- Standards — why standards make quality depend on the system, not heroics.
- Naming Standards — taxonomy, nomenclature, and ontology for named things.
- Standard Templates — template, procedure, artifact, and readiness gates.
- Process Quality Assurance — build quality into the process before inspection.
- Knowledge Architecture — anchor, concepts, gaps, and schema updates.
- Reality Scoreboard — the Tight Five connection: migration discipline makes broad changes measurable before they ship.
Questions
Which edge type is easiest to confuse with a live edge?
- What would break if this old token remained in a hook, package alias, or skill instruction?
- Which generated files mention the token, and what command owns them?
- Which hits are historical records that should stay true to the past?
- Which files have active user edits and must be excluded from mechanical rewrite?
- What proof would catch a file that escaped the manifest?