The migrated core.md limbs become categorized lesson rows
The other half of the core.md migration: every limb the two source-restatement cards marked migrate becomes a row in the lesson store, so "nothing was lost" is a fact a reader can check rather than a promise.
Read the two core.md sections of RESTATEMENT.md that the gate-checklist card and the planning-rules card wrote. Each migrate row names a destination sourceRef. Give every one of them a disposition, exactly as MOTIR-3305 and MOTIR-3309 did:
- a NEW row in
BASE_LESSONSwhen the takeaway is not already stated; or - MERGED into a row that already says it — named by that row's
sourceRef, with the reason. Thecore.mdgates lean on incidents the MOTIR-3296 backfill has already distilled, so expect most limbs to merge rather than to add.
A second row for a takeaway the store already carries makes the ranker return the same advice twice and crowd something else out; that is why MERGED is a first-class answer here and not a shortcut.
Set the three routing axes deliberately. kinds, types and phases are set-valued and empty means unconstrained — a limb about a bug card's repeat-defect count is kinds: ['bug'], a limb about a migration's call sites is types: ['code', 'chore', 'deploy'], a limb about the repo pin fires on every kind at skeleton and should constrain only phases. Over-constraining is how a good row becomes unreachable, which is the failure this axis was added to fix.
⚠️ sourceRef is the idempotency key AND the totality suite's parser. lessonsBaseSeed.test.ts extracts every #(\d+) and asserts the union of dispositions is exactly 1..CORPUS_HEAD, with nothing above CORPUS_HEAD = 356. The notes.html corpus is FROZEN at 356, so:
- a limb whose incident has a
notes.htmlentry cites that entry's number, and the row joins the existing accounting; - a limb with no entry — anything post-freeze — takes a
sourceRefcarrying no#Nat all (name the pack and the rule), because inventing a number above 356 fails the suite and re-using one below it collides with the key.
Do not raise CORPUS_HEAD. Nothing in this card adds a notes.html entry.
Delivery is a migration, not the seed: pnpm lessons:generate-migration emits a forward-only delta whose inserts are ON CONFLICT ("sourceRef") DO NOTHING, and the release runs migrate deploy then the embedding sweep. A row inserted without an embedding is present, healthy and permanently unrankable until that sweep runs, so the migration is part of this card, not a follow-up.
RESTATEMENT.md lives in the other repository and this card does not touch it. Record in the PR body which row discharged which table row; the closing card sweeps every remaining pending back into that file.
Acceptance criteria
- Every migrate row in
RESTATEMENT.md's twocore.mdsections has a disposition in this PR: a newBASE_LESSONSrow, or a MERGED line naming the covering row'ssourceRefand why it covers. - Each new row carries all of
scope,mistakeType,title,body,why,howToApply,categoriesandsourceRef, and setskinds/types/phasesonly where the lesson genuinely cannot fire off that axis — the PR body states the constraint chosen for each row and why. - No new
sourceRefcontains a#Ngreater than 356, andCORPUS_HEADis unchanged. title,bodyandhowToApplyname no repository, file, symbol, card key or date — the generic-rewrite and date guards intests/lessonsBaseSeed.test.tspass without being weakened.pnpm lessons:generate-migrationis run and its emitted delta migration is committed in the same PR; the PR body names the migration directory and its row count.pnpm typecheck,pnpm format:checkandpnpm testare green,lessonsBaseSeed.test.tsandlessonsMigrationDelivery.test.tsincluded.- The PR body carries a table mapping each
RESTATEMENT.mdmigrate row to its destination row or MERGED target, so a reader can follow any migrated paragraph to where it went. - No file outside
motir-aiis changed.
Context refs
motir-aisrc/seed/lessons.base.ts—BaseLessonSeed,BASE_LESSONS,CORPUS_HEAD,EXCLUDED_ENTRIES, and the merged / dropped disposition tables.motir-aitests/lessonsBaseSeed.test.ts— the totality, uniqueness, generic-rewrite and date guards this card must satisfy.motir-aiscripts/generate-lessons-migration.ts·src/seed/embedMissingLessons.ts— the delta migration and the embedding sweep.motir-aisrc/services/lessonService.ts— how the axes are used at retrieval, which is what decides how far to constrain a row.motir-metaprompts/plan-rules/RESTATEMENT.md— read-only input: the twocore.mdsections listing what to migrate.- MOTIR-3309 — the proof card for this step; its two new rows and five merges are the worked precedent.