Ships Brief 7 (documentation + verification runbook) of the
reconcile-historical-add-scripts convoy, ~2 months post-hoc. The
6 implementer briefs (B1-B6) landed 2026-06-14 to 2026-07-06 via
PRs #148, #149, #150, #151, #152, #153. This PR closes the loop:
- Brings the architect's parent convoy file + 6 brief files onto
main (they only existed on the stale convoy/reconcile-historical-
add-scripts branch, never merged)
- Adds § As-shipped to the parent convoy file documenting all 6
squash SHAs + PR numbers + merge dates + the reservation-timestamp
rename (1781000000001-006 → 1781442330001-006 in ec9bb2b, except
B3 which kept its original) + the B6 shipped-as-tiny-migration
deviation from the collapse-to-docs plan
- Fixes docs/SCHEMA_MAP.md § user_favorites (was stale
(user_id, card_id); actual polymorphic (item_type, item_id) per
B4's migration)
- Adds docs/MIGRATION_VERIFICATION_RUNBOOK.md — manual
fresh-Neon-branch vs prod pg_dump diff runbook per architect D5
- Flips .convoys/ship-readiness.md entries:
- reconcile-historical-add-scripts → RESOLVED
- retire-graveyard-scripts-after-audit → UNBLOCKED
- Adds two new queued follow-ups surfaced by the architect:
- unify-user-avatar-column (P3 — dual avatar column smell)
- drop-dead-cards-columns (P3 — cards.quantity + cards.favorited)
No source-code changes. Docs only.
Co-authored-by: Cursor <cursoragent@cursor.com>
25 KiB
| convoy | brief_number | depends_on | files | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| reconcile-historical-add-scripts | 7 |
|
|
Brief 7: Documentation + verification runbook
Goal (1 sentence)
Update the four documentation surfaces that describe the post-convoy schema and onboarding state — docs/SCHEMA_MAP.md (correct doc bugs + cross-reference new migrations), docs/MIGRATION_VERIFICATION_RUNBOOK.md (new — manual operator runbook from D5), AGENTS.md Gotcha #6 (cross-reference this convoy as the closing follow-up), .convoys/ship-readiness.md (flip this convoy's queued entry to RESOLVED + unblock retire-graveyard-scripts-after-audit + add new follow-ups) — so the next operator onboarding a fresh Neon branch can do so by npm install → npm run setup-db alone and verify the result.
Scope (files in scope — do not edit anything else)
docs/SCHEMA_MAP.md— modifieddocs/MIGRATION_VERIFICATION_RUNBOOK.md— newAGENTS.md— modified (small Gotcha #6 cross-reference update only).convoys/ship-readiness.md— modified (queued convoys section)
This brief is sequenced last because it cross-references the 5 new migration files that B1-B5 add; it cannot land before B1-B5 are merged. The architect's slice_dependencies block in the convoy file declares depends_on: [1, 2, 3, 4, 5].
Per-file scope
1. docs/SCHEMA_MAP.md — modified
Targeted edits (keep all other content as-is):
-
Preamble update. The current preamble (lines 1-18) notes that "the initial backfill captures only the post-
setup-neon-db.jsshape. … A follow-up convoy (reconcile-historical-add-scripts) will fold the historical effects into the migration history; until then this file remains the curated reference for the full prod shape." Replace with a sentence noting the convoy has landed, the migration history now captures the full prod shape, and the operator verification runbook lives atdocs/MIGRATION_VERIFICATION_RUNBOOK.md. Bump the "Last reviewed" date. -
### usersnotes column updates (lines 43-57): each row referencesadd-user-profile-columns.js/add-user-profile-fields.js— leave those references in place (they're historical context); ADD a single line at the end of the table noting "All columns above are now captured bymigrations/1781000000005_reconcile-user-profile.js(B5 ofreconcile-historical-add-scripts, 2026-06-14)." -
### cardsnotes column updates (lines 78-79): for thequantityandfavoritedrows, change the "Unused; consider dropping" annotation to "Unused; captured bymigrations/1781000000001_reconcile-cards-columns.jsfor fresh-env parity. Drop tracked as queueddrop-dead-cards-columnsfollow-up." -
### user_cardsindex/constraint notes (lines 90-102): add a brief note clarifying the canonical constraint isUNIQUE(user_id, card_id, is_foil)(3-col) from initial-schema, and thatscripts/fix-user-cards-constraints.js's stricter 2-col variant was either never-applied or reverted (Finding 1 of the reconcile convoy → Outcome A, 2026-06-14). This is the SCHEMA_MAP equivalent of the Drift Finding 1 resolution. -
### user_favoritestable (lines 104-111): FIX THE DOC BUG. Current shape lists only(user_id, card_id). Replace with the actual polymorphic shape per the runtime inpages/api/favorites.js:### user_favorites | Column | Type | Notes | | --- | --- | --- | | `id` | `SERIAL PK` | | | `user_id` | `INTEGER FK users(id) ON DELETE CASCADE` | | | `item_type` | `VARCHAR(50) NOT NULL` | `'card' | 'collection' | 'deck'` — polymorphic | | `item_id` | `INTEGER NOT NULL` | FK depends on `item_type`; not enforced at DB level | | `created_at` | `TIMESTAMP` | | | | | **UNIQUE(user_id, item_type, item_id)** | Indexes: `idx_user_favorites_user_id`, `idx_user_favorites_item_type`, `idx_user_favorites_item_id`, `idx_user_favorites_user_type (user_id, item_type)` — all in `migrations/1781000000004_reconcile-favorites-system.js`. -
### collectionsnotes: add a line at the bottom noting "visibility,tcg,tags,slug(+idx_collections_slugunique +check_slug_formatCHECK),imageare now captured bymigrations/1781000000002_reconcile-collections-columns.js." -
### collection_permissions+### collection_activitysections: add a line at the bottom of each noting "Captured bymigrations/1781000000003_reconcile-collaboration-tables.js." -
NEW SECTION:
### user_settings(currently a one-liner at line 217). Expand to a proper column table matching the actual schema:### user_settings Per-user key/value store for settings that don't warrant a column on `users`. Captured by `migrations/1781000000005_reconcile-user-profile.js`. | Column | Type | Notes | | --- | --- | --- | | `id` | `SERIAL PK` | | | `user_id` | `INTEGER FK users(id) ON DELETE CASCADE` | | | `setting_key` | `VARCHAR(100) NOT NULL` | | | `setting_value` | `JSONB NOT NULL` | | | `created_at`, `updated_at` | `TIMESTAMP` default now | | | | | **UNIQUE(user_id, setting_key)** | Indexes: `idx_user_settings_user_id`, `idx_user_settings_key`. -
### user_avatarsexpansion (currently one paragraph at lines 222-223). Replace with:### user_avatars Tracks uploaded avatar history. Captured by `migrations/1781000000005_reconcile-user-profile.js`. Older avatars are typically deleted from blob storage; verify the cleanup job runs. | Column | Type | Notes | | --- | --- | --- | | `id` | `SERIAL PK` | | | `user_id` | `INTEGER FK users(id) ON DELETE CASCADE` | | | `filename` | `VARCHAR(255) NOT NULL` | | | `original_name` | `VARCHAR(255)` | | | `mime_type` | `VARCHAR(100)` | | | `file_size` | `INTEGER` | | | `file_path` | `TEXT NOT NULL` | | | `is_active` | `BOOLEAN DEFAULT true` | | | `created_at`, `updated_at` | `TIMESTAMP` default now | | Indexes: `idx_user_avatars_user_id`, `idx_user_avatars_active (user_id, is_active)`. -
## Known schema smellssection updates (lines 226-232):- Smell #2 (
is_publicvsvisibility): add a sentence noting both columns are now captured by separate migrations (initial-schema foris_public, B2 forvisibility); resolution lives in a futureunify-collection-visibilityfollow-up. - Smell #3 (
cards.quantity+cards.favorited): add the cross-reference to the queueddrop-dead-cards-columnsfollow-up. - NEW: Smell #7 —
users.profile_image_urlvsusers.avatar_url(the parity smell that B5 perpetuates intentionally). Both columns are present for prod parity; cleanup is the queuedunify-user-avatar-columnfollow-up.
- Smell #2 (
-
## Regenerationsection update (lines 234-245): the manual-regeneration instructions can be removed entirely since the migration history is now authoritative. Replace with:## Regeneration The migration history under `migrations/` is the authoritative source of truth. To verify this file matches a live env (prod, preview, or a fresh Neon branch), use the operator runbook at [`docs/MIGRATION_VERIFICATION_RUNBOOK.md`](MIGRATION_VERIFICATION_RUNBOOK.md). When you add a new migration, update the relevant table section here in the same PR. New tables get a new `###` section with the same column-table shape.
2. docs/MIGRATION_VERIFICATION_RUNBOOK.md — new
Lift verbatim from .convoys/reconcile-historical-add-scripts.md § Verification plan (D5), with a small intro framing it as the canonical operator runbook (not just a convoy artifact). Suggested skeleton:
# Migration verification runbook
How to verify that the migration history under `migrations/` produces
the same schema as a long-lived environment (prod, preview, or
similar). Use this runbook:
- **After this repo's `reconcile-historical-add-scripts` convoy** (the
initial reconciliation), to confirm a fresh Neon branch reaches
parity with prod via `npm install` → `npm run setup-db` alone.
- **After any new migration lands on `main`**, to spot-check that
applying the migration to prod (via the operator's
`POSTGRES_URL=<prod> npm run migrate up`) produced the intended
effect.
- **When suspecting drift** between an env's actual schema and the
migration history (rare; the migration history is authoritative).
This runbook is the manual precursor to the automated check planned
in the queued `wire-migrate-into-ci` follow-up (see
`.convoys/ship-readiness.md` § "Queued convoys").
## Prerequisites
- `pg_dump` (PostgreSQL 16+) installed locally.
- `POSTGRES_URL` for the env you're verifying.
- `ADMIN_INITIAL_PASSWORD` (for the fresh-branch onboarding step) —
see `AGENTS.md` § 5 "Running locally".
- A Neon account with permission to create a branch (or any other
way to spin up a fresh Postgres DB on the same major version as
prod).
## Procedure
### Step 1 — Snapshot the reference env's structural shape
Run against the env you consider canonical (usually prod):
\`\`\`bash
POSTGRES_URL=<reference-url> pg_dump --schema-only --no-owner --no-acl \
--schema=public > /tmp/reference-schema.sql
\`\`\`
### Step 2 — Create a fresh DB and onboard via `setup-db`
Create a clean Neon branch from an **empty** parent (or any other
fresh Postgres DB on the same major version):
\`\`\`bash
POSTGRES_URL=<fresh-branch-url> \
ADMIN_INITIAL_PASSWORD=$(openssl rand -base64 24) \
npm run setup-db
\`\`\`
`setup-db` runs `npm run migrate up` (applying every migration in
`migrations/` in timestamp order) and seeds the admin user.
### Step 3 — Snapshot the fresh DB's structural shape
\`\`\`bash
POSTGRES_URL=<fresh-branch-url> pg_dump --schema-only --no-owner --no-acl \
--schema=public > /tmp/fresh-schema.sql
\`\`\`
### Step 4 — Diff
\`\`\`bash
diff <(sort /tmp/reference-schema.sql) <(sort /tmp/fresh-schema.sql)
\`\`\`
**Expected non-material differences** (acceptable; do not chase):
- Constraint or index NAME differences. Prod constraints created via
the historical `scripts/add-*` / `scripts/fix-*` jobs may have
autogenerated tuple-UNIQUE names that differ from the migrations'
explicit names.
- Column-ORDER differences. Prod has columns in historical-script-ALTER
order; fresh envs have them in migration-order.
**Material differences** (bug — fix before declaring verified):
- A column type, default, or NULL/NOT NULL state that differs.
- A missing or extra table.
- A missing or extra CHECK constraint that changes accepted values.
- A missing or extra index that changes query plan shape.
## Supplementary spot-checks
For the highest-risk surfaces (frequently-edited tables), run these
information-schema queries against both envs and confirm the
column-count / constraint-count / index-count totals match exactly:
\`\`\`sql
-- Every column on every table
SELECT table_name, column_name, data_type, is_nullable, column_default
FROM information_schema.columns
WHERE table_schema = 'public'
ORDER BY table_name, ordinal_position;
-- Every constraint
SELECT table_name, constraint_name, constraint_type
FROM information_schema.table_constraints
WHERE table_schema = 'public'
ORDER BY table_name, constraint_name;
-- Every index
SELECT tablename, indexname, indexdef
FROM pg_indexes
WHERE schemaname = 'public'
ORDER BY tablename, indexname;
\`\`\`
A mismatch in column count, constraint count, or index count is a
material difference and indicates a bug.
## What to do if you find a material difference
1. **Identify which env is canonical.** Usually prod. If the diff
surfaces a missing column on prod that's in the migration history,
the migration was never applied to prod — run
`POSTGRES_URL=<prod> npm run migrate up` to catch up.
2. **If the diff surfaces a column on prod that's NOT in the
migration history**, you've found a drift bug. Write a new
reconciliation migration (under `migrations/`) that captures the
prod column, following the pattern in `.convoys/reconcile-historical-add-scripts/`.
3. **Do not edit existing migrations** — they're pinned by
`pgmigrations` rows. Always write a new dated migration to correct
schema.
## Cross-references
- `AGENTS.md` § 4 Gotcha #6 — migration tool adoption history.
- `.convoys/migration-tool.md` — the convoy that adopted `node-pg-migrate`.
- `.convoys/reconcile-historical-add-scripts.md` — the convoy that folded
the 13 historical scripts into the migration history.
- `.cursor/rules/db-and-schema.mdc` — schema-change conventions.
3. AGENTS.md — modified (small Gotcha #6 cross-reference)
Gotcha #6 is already "RESOLVED" per migration-tool (2026-05-26). This brief adds one sentence to the end of Gotcha #6 cross-referencing this convoy as the closing follow-up. Verbatim addition (insert immediately before the - **#7** line at AGENTS.md line 120):
Post-
reconcile-historical-add-scripts(2026-06-14), the migration history additionally captures the full effect of the 13 historicalscripts/add-*.js/scripts/fix-*.js/scripts/seed-*.jsjobs (where applicable — pure-DML seed scripts stay out per D4 of that convoy). A brand-new Neon branch can now be onboarded bynpm install→npm run setup-dbalone. Operator verification runbook atdocs/MIGRATION_VERIFICATION_RUNBOOK.md. The 13 historical scripts remain no-go-zones until the queuedretire-graveyard-scripts-after-audit(P3) cleanup convoy lands; that convoy is now unblocked.
Do NOT flip Gotcha #6's RESOLVED marker — it's already RESOLVED by the right convoy (migration-tool). Just append the cross-reference.
4. .convoys/ship-readiness.md — modified (queued convoys section)
Find the existing line under § "Queued convoys" that reads:
reconcile-historical-add-scripts(priority: P1 quality — needed for fresh-env onboarding). Surfaced 2026-05-26 bymigration-tool(PR #32). Fold the effects of the 27 historicalscripts/add-*.js/fix-*.js/seed-*.jsjobs … Documented in.convoys/migration-tool.md§ R1.
Replace with:
reconcile-historical-add-scripts— RESOLVED 2026-06-14 by convoy (PRs #XX-#XX). Captured 7 of the 13 historical scripts' effects into 5 new migrations undermigrations/(B1-B5); 2 scripts were already captured byinitial-schema+1780378340194_system-collection-description; 3 are DML-only and stay as dev fixtures; 1 (fix-user-cards-constraints.js) is a no-op on prod per Finding 1 (Outcome A — the canonical 3-colUNIQUE(user_id, card_id, is_foil)frominitial-schemais what prod has, andfix-user-cards-constraints.js's stricter 2-col variant is not present). A brand-new Neon branch now onboards vianpm install→npm run setup-dbalone. Operator verification atdocs/MIGRATION_VERIFICATION_RUNBOOK.md. Entry kept (not deleted) for audit trail.
Find the existing line:
retire-graveyard-scripts-after-audit(priority: P3 polish; blocked onreconcile-historical-add-scripts). …
Replace the **blocked on reconcile-historical-add-scripts** marker with **UNBLOCKED 2026-06-14** and leave the rest of the description intact.
Add two new queued entries (driven by Findings 2 + 3 of the reconcile convoy):
unify-user-avatar-column(priority: P3 hygiene). Surfaced 2026-06-14 byreconcile-historical-add-scriptsFinding 2.users.profile_image_url(added byscripts/add-user-profile-columns.js) andusers.avatar_url(added byscripts/add-user-profile-fields.js) coexist on prod and in the migration history (both columns are needed for parity per B5). Pick one canonical column, migrate the other's data to it, drop the loser, and sweep runtime readers inpages/api/user/avatar*.js+ UI surfaces. Requires a query-trace audit first.drop-dead-cards-columns(priority: P3 hygiene). Surfaced 2026-06-14 byreconcile-historical-add-scriptsFinding 3.cards.quantity INTEGERandcards.favorited BOOLEANare documented unused (perdocs/SCHEMA_MAP.md§ "Known schema smells" #3); reconciled into the migration history by B1 for parity, but the actual semantics live onuser_cards/user_favorites. After a query-trace audit confirms zero runtime readers, ship a migration that DROPs both columns with a realdown()that recreates them.
(Do NOT add the withdrawn add-system-collection-on-register or unify-user-cards-foil-tracking entries — both were withdrawn during the reconcile convoy. See .convoys/reconcile-historical-add-scripts.md § Follow-ups.)
Conventions to follow
.cursor/rules/no-go-zones.mdc— no edits toscripts/add-*/fix-*/seed-*..cursor/rules/db-and-schema.mdc— schema-change conventions; SCHEMA_MAP is updated alongside any migration.- Markdown style: match the existing tone of
docs/SCHEMA_MAP.md(compact tables, "Notes" column explains intent not type semantics) andAGENTS.md(numbered Gotchas, cross-reference convoy files). - For
.convoys/ship-readiness.md: match the existing entry style under § "Queued convoys" (one bullet per convoy, leading- **name**, RESOLVED entries get the "Entry kept (not deleted) for audit trail" closer when applicable).
Acceptance criteria
docs/SCHEMA_MAP.mdpreamble bumped (post-convoy state); "Last reviewed" date is 2026-06-14.docs/SCHEMA_MAP.md§user_favoritesshape is the polymorphic(item_type, item_id)— NOT the previous(card_id)shape.- Every reconciled table/column has a "captured by
migrations/<file>" cross-reference. ### user_settingsand### user_avatarssections are expanded from one-liners to full column tables matching B5's migration.- New schema smell #7 (
profile_image_urlvsavatar_url) is added to § "Known schema smells". docs/MIGRATION_VERIFICATION_RUNBOOK.mdexists with the 4-step procedure from D5 + the spot-check queries + the "material vs non-material differences" guidance.AGENTS.mdGotcha #6 gains a single appended paragraph cross-referencing this convoy + the new runbook + the unblockedretire-graveyard-scripts-after-auditfollow-up. Gotcha #6's existing "RESOLVED bymigration-tool" marker is NOT changed..convoys/ship-readiness.md§ "Queued convoys" →reconcile-historical-add-scriptsentry is flipped to RESOLVED 2026-06-14 with a one-paragraph summary;retire-graveyard-scripts-after-auditis marked UNBLOCKED 2026-06-14; two new entries (unify-user-avatar-column,drop-dead-cards-columns) are added.- No edits to any file under
scripts/,migrations/,pages/,lib/,components/,test/, orpackage.json. npm run lintmatches baseline (these are markdown-only edits; lint should be unaffected).npm run test:runreports 21/21 passing (these are markdown-only edits; no test surface).
Verification
npm run lint
npm run test:run
Both must match baseline / be green. No additional verification for this brief — the migrations themselves are exercised by Brief 7's verification runbook AFTER an operator runs it manually post-merge.
For the SCHEMA_MAP edits, eyeball the diff against the prior state and confirm every cross-reference to a migration file is accurate (the file actually exists, and the timestamp matches the assigned reservation).
Commit message
docs(reconcile): update SCHEMA_MAP, verification runbook, AGENTS, ship-readiness (brief 7/7)
Closes the reconcile-historical-add-scripts convoy:
- docs/SCHEMA_MAP.md: cross-reference 5 new migrations from B1-B5;
fix user_favorites doc bug (polymorphic shape, not (card_id));
expand user_settings + user_avatars one-liners to full column tables;
add schema smell #7 (profile_image_url vs avatar_url redundancy).
- docs/MIGRATION_VERIFICATION_RUNBOOK.md (new): canonical operator
runbook for verifying fresh-env vs prod schema parity (lifted from
D5 of the convoy).
- AGENTS.md Gotcha #6: append cross-reference to this convoy + the
new runbook + the now-unblocked retire-graveyard-scripts-after-audit
follow-up. Existing "RESOLVED by migration-tool" marker unchanged.
- .convoys/ship-readiness.md: flip reconcile-historical-add-scripts
entry to RESOLVED 2026-06-14; mark retire-graveyard-scripts-after-audit
UNBLOCKED; add new queued unify-user-avatar-column (Finding 2) +
drop-dead-cards-columns (Finding 3).
Per .convoys/reconcile-historical-add-scripts.md § Brief outline → B7.
Depends on B1-B5 having merged (this brief cross-references their files).
PR shape
Title: docs(reconcile): update SCHEMA_MAP, verification runbook, AGENTS, ship-readiness (brief 7/7)
Body template:
Brief 7 (final) of the `reconcile-historical-add-scripts` convoy.
See [`.convoys/reconcile-historical-add-scripts.md`](../.convoys/reconcile-historical-add-scripts.md)
for the full plan and rationale.
This is the closing brief — depends on B1-B5 having merged (PR
references below).
## What this PR does
- **`docs/SCHEMA_MAP.md`** — cross-reference all 5 new migrations from
B1-B5; fix the `user_favorites` doc bug (the table uses the
polymorphic `(item_type, item_id)` shape, not `(card_id)`); expand
`user_settings` + `user_avatars` from one-liners to full column
tables matching the B5 migration; add a new "Known schema smell" #7
for the `profile_image_url` / `avatar_url` redundancy.
- **`docs/MIGRATION_VERIFICATION_RUNBOOK.md`** (new) — canonical
operator runbook for verifying fresh-env vs prod schema parity.
Pulls verbatim from D5 of the convoy file. Useful both for the
one-time reconciliation verification and for ongoing post-migration
spot-checks.
- **`AGENTS.md`** — append one paragraph to Gotcha #6 cross-referencing
this convoy as the closing follow-up. The "RESOLVED by `migration-tool`"
marker is unchanged (that's still the right resolution attribution
for the gotcha itself).
- **`.convoys/ship-readiness.md`** § "Queued convoys" — flip the
`reconcile-historical-add-scripts` entry to RESOLVED 2026-06-14;
flip `retire-graveyard-scripts-after-audit` from "blocked on
reconcile-historical-add-scripts" to UNBLOCKED 2026-06-14; add two
new queued entries (`unify-user-avatar-column` from Finding 2,
`drop-dead-cards-columns` from Finding 3).
## Prerequisite PRs (all must be merged first)
- B1 #XX — reconcile cards columns
- B2 #XX — reconcile collections columns
- B3 #XX — reconcile collaboration tables
- B4 #XX — reconcile favorites system
- B5 #XX — reconcile user profile
## What this PR does NOT do
- Does **NOT** edit any file under `migrations/`, `scripts/`, `pages/`,
`lib/`, `components/`, `test/`, or `package.json`.
- Does **NOT** run the verification runbook itself — that's the
operator's post-merge job; see the runbook's "Procedure" section.
## Verification checklist
- [ ] `npm run lint` matches baseline
- [ ] `npm run test:run` reports 21/21 passing
- [ ] Every "captured by `migrations/<file>.js`" cross-reference in
SCHEMA_MAP points at a file that actually exists in `migrations/`
(eyeballed against `ls migrations/`)
- [ ] `AGENTS.md` Gotcha #6 still has its original RESOLVED marker
(we only APPEND to it, not rewrite it)
- [ ] `.convoys/ship-readiness.md` § "Queued convoys" has the flipped
`reconcile-historical-add-scripts` entry, the UNBLOCKED
`retire-graveyard-scripts-after-audit` marker, and the two new
follow-up entries
- [ ] Operator post-merge: run `docs/MIGRATION_VERIFICATION_RUNBOOK.md`
against prod + a fresh Neon branch and confirm the diff is
non-material
## Cross-references
- Convoy file: `.convoys/reconcile-historical-add-scripts.md`
- Per-brief files: `.convoys/reconcile-historical-add-scripts/brief-{1,2,3,4,5}-*.md`
DO NOT
- DO NOT edit any file under
scripts/,migrations/,pages/,lib/,components/,test/. - DO NOT edit
package.json, README,next.config.js, or any rule under.cursor/rules/. - DO NOT change
AGENTS.mdGotcha #6's "RESOLVED bymigration-tool" marker — append the new paragraph; don't rewrite the existing resolution attribution. - DO NOT add a
B6reference anywhere — that brief was removed (Finding 1 → Outcome A). - DO NOT add
add-system-collection-on-registerorunify-user-cards-foil-trackingto the ship-readiness queued list — both were withdrawn during this convoy. - DO NOT remove the existing
wire-migrate-into-cientry from ship-readiness — it's still queued and unrelated to this convoy. - DO NOT run the verification runbook itself (that's the operator's post-merge step).
Rationale (≤3 sentences)
Sequencing this brief last lets every documentation cross-reference point at a real file under migrations/ rather than a placeholder. Bundling all four doc surfaces into one PR keeps the convoy's "as-shipped" record consistent (the migrations, the operator runbook, the AGENTS gotcha, and the ship-readiness ledger all flip together). The docs/MIGRATION_VERIFICATION_RUNBOOK.md extraction promotes a one-time convoy artifact into an evergreen operator tool that future migrations can reuse.