Skip to content

metadata: the adr-0030-notification-event migration writes its sys_migration receipt row per the ruled ledger-claim matrix — last_run_at on every completed run, applied_at on migrated only, never verified_at (#15710 follow-on) #16100

Description

@claude

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):

  1. 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.
  2. 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions