Follow-on filed by the domain:spec seat (session_01M59rPZZFzqhfMUPFqqZTkf, 2026-09-06T00:54Z) on the landing of PR #16068 (#15710, merged 2026-09-06T00:52:16Z as a7da4de6f), per the ruling's execution paragraph on #15710 (comment 5550131736): "The runtime side — which caller writes the receipt row when the migration runs — is contract-first and is its own follow-on card in the lane that owns the runner (packages/metadata / engine), filed by the spec seat when this lands."
Lane: the runner lives in packages/metadata/src/migrations/migrate-sys-notification-to-event.ts (its result type at :58 is 'migrated' | 'already_done' | 'not_applicable' | 'error'), invoked from packages/metadata/src/migrations/driver-exec.ts and packages/cli/src/commands/serve.ts (read on origin/main at a7da4de6f, 2026-09-06T00:53Z) — packages/metadata* is the engine lane per the triage table; triage adds the domain:* label. Reader: the engine seat at candidate selection. Clause-②: no — the contract is already on main; this card makes the runtime honour it. No Blocked-by: — the spec half landed.
The contract now on main (packages/spec/src/system/migration.zod.ts, the docblock on NOTIFICATION_EVENT_MIGRATION_ID, landed a7da4de6f), quoted from the ruling (maintainer verbatim 「同意」 to decision batch #47 item 5):
- Columns.
last_run_at is set on every completed non-error run (migrated, already_done, not_applicable); applied_at only on migrated; verified_at is never set by this migration — it has no self-check, and verified_at means a self-check passed. details.outcome carries the four-valued result; an error run writes no ledger claim.
- Receipt, not gate. Nothing gates on the row; it is what an operator reads, in the shape
sys-migration.object.ts already documents for the seed-tenancy repair (verified_at: null, blocking: 0 by construction). A gate would need a self-check that does not exist.
What to do: after a completed non-error run of the migration, the caller that owns the datastore handle writes or updates the sys_migration row for NOTIFICATION_EVENT_MIGRATION_ID exactly as the matrix says — last_run_at now; applied_at now only when the outcome is migrated; verified_at untouched (null on a store that never attested; on a store created after the cut-over attestFreshDatastore set it at birth, and this writer must neither clear nor set it); blocking: 0; details carrying { outcome } verbatim. An error outcome writes nothing. Which caller — driver-exec.ts (the migration door) or serve.ts (the boot-time invocation) — is decided by reading and stated in the PR; the seed-tenancy repair's receipt writer in the same package is the precedent shape. Pin it: one case per outcome, the error no-write case, and the fresh-store case where the attestation row pre-exists (its birth verified_at survives the run untouched while last_run_at / applied_at update). The spec pin packages/spec/src/system/notification-event-migration-ledger.pin.test.ts already proves the receipt shape answers false to isDataMigrationFlagVerified; ⛔ do not add a gate on the row.
Not in scope: the id's membership in CREATION_ATTESTED_MIGRATION_IDS (landed), the docblock (landed), finding #16067 (the contradiction-warning remedy text in attestFreshDatastore).
Size: S.
Generated by Claude Code
Follow-on filed by the
domain:specseat (session_01M59rPZZFzqhfMUPFqqZTkf, 2026-09-06T00:54Z) on the landing of PR #16068 (#15710, merged 2026-09-06T00:52:16Z asa7da4de6f), per the ruling's execution paragraph on #15710 (comment 5550131736): "The runtime side — which caller writes the receipt row when the migration runs — is contract-first and is its own follow-on card in the lane that owns the runner (packages/metadata/ engine), filed by the spec seat when this lands."Lane: the runner lives in
packages/metadata/src/migrations/migrate-sys-notification-to-event.ts(its result type at:58is'migrated' | 'already_done' | 'not_applicable' | 'error'), invoked frompackages/metadata/src/migrations/driver-exec.tsandpackages/cli/src/commands/serve.ts(read onorigin/mainata7da4de6f, 2026-09-06T00:53Z) —packages/metadata*is the engine lane per the triage table; triage adds thedomain:*label. Reader: the engine seat at candidate selection. Clause-②: no — the contract is already onmain; this card makes the runtime honour it. NoBlocked-by:— the spec half landed.The contract now on
main(packages/spec/src/system/migration.zod.ts, the docblock onNOTIFICATION_EVENT_MIGRATION_ID, landeda7da4de6f), quoted from the ruling (maintainer verbatim 「同意」 to decision batch #47 item 5):What to do: after a completed non-
errorrun of the migration, the caller that owns the datastore handle writes or updates thesys_migrationrow forNOTIFICATION_EVENT_MIGRATION_IDexactly as the matrix says —last_run_atnow;applied_atnow only when the outcome ismigrated;verified_atuntouched (nullon a store that never attested; on a store created after the cut-overattestFreshDatastoreset it at birth, and this writer must neither clear nor set it);blocking: 0;detailscarrying{ outcome }verbatim. Anerroroutcome writes nothing. Which caller —driver-exec.ts(the migration door) orserve.ts(the boot-time invocation) — is decided by reading and stated in the PR; the seed-tenancy repair's receipt writer in the same package is the precedent shape. Pin it: one case per outcome, theerrorno-write case, and the fresh-store case where the attestation row pre-exists (its birthverified_atsurvives the run untouched whilelast_run_at/applied_atupdate). The spec pinpackages/spec/src/system/notification-event-migration-ledger.pin.test.tsalready proves the receipt shape answersfalsetoisDataMigrationFlagVerified; ⛔ do not add a gate on the row.Not in scope: the id's membership in
CREATION_ATTESTED_MIGRATION_IDS(landed), the docblock (landed), finding #16067 (the contradiction-warning remedy text inattestFreshDatastore).Size: S.
Generated by Claude Code