Files
2026-05-27 23:29:53 +01:00

11 KiB
Raw Permalink Blame History

Tasks — Migration adapters completion

Every checkbox MUST reflect work actually done in this change. Do not retroactively tick boxes for work that was already in main when this change opened. Do not tick a box for a test that doesn't exist or doesn't pin the requirement it claims to verify.

0. Pre-flight (non-negotiable)

  • 0.1 Confirm clean working tree (git status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in each)
  • 0.2 If any worktrees exist under .claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
  • 0.3 Confirm the package set in MANIFEST.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

Audit Note (2026-05-02)

Status: DEFERRED. None of the proposed additive surfaces exist: no migrationEvents shared bus, no MigrationLockLike / MigrationStoreLike interfaces (existing MigrationLockAdapter / MigrationStoreAdapter shapes are untouched), no BatchTargetProgress / BatchTargetStatus / TargetConfigFactory types, no GetAllRecordsFn, no ValidationError alias, no registerMigrationErrorCodes() named export. Lifecycle event-key aliases (migration:started, migration:applied, migration:completed, migration:rolled-back) are absent — code only emits migration:before / migration:after / migration:failed / migration:plan. 0% of work is done.

1. Spec authoring

  • 1.1 Read ../suaveplan/enterprise/migration.md end-to-end
  • 1.2 Read openspec/specs/migration/spec.md (does not exist yet — confirm and start fresh)
  • 1.3 Read openspec/AGENTS.md Sections 13 and 14
  • 1.4 Draft proposal.md from openspec/templates/proposal.md
  • 1.5 Fill in ## Source mapping table — every requirement cites a line range OR appears in the "no source line" table with justification
  • 1.6 Draft specs/migration/spec.md from openspec/templates/spec-delta.md
  • 1.7 Every requirement in the spec delta carries a **Verified by:** line naming concrete it(...) titles

2. Implementation — lock/migration-lock

  • 2.1 Create packages/database/migration/src/lock/migration-lock/migration-lock.ts exporting the MigrationLockLike interface (acquire(lockId, ttlMs), release(lockId), extend(lockId, ttlMs))
  • 2.2 Re-export the existing MigrationLockAdapter from this module under the same name for back-compat
  • 2.3 Add a migration-lock.md sibling doc covering both interface contracts (≥200 words, basic + advanced examples)
  • 2.4 Update MemoryMigrationLock to implement MigrationLockLike alongside the existing MigrationLockAdapter shape (additive methods only)
  • 2.5 Update lock/index.ts to export MigrationLockLike from the package root via index.ts

3. Implementation — store/migration-store

  • 3.1 Create packages/database/migration/src/store/migration-store/migration-store.ts exporting the MigrationStoreLike interface (list, append, markFailed, markApplied, getLatestVersion)
  • 3.2 Re-export the existing MigrationStoreAdapter from this module under the same name for back-compat
  • 3.3 Add a migration-store.md sibling doc (≥200 words, basic + advanced examples)
  • 3.4 Update MemoryMigrationStore to implement MigrationStoreLike alongside the existing MigrationStoreAdapter shape (additive methods only)
  • 3.5 Update store/index.ts to export MigrationStoreLike from the package root via index.ts

4. Implementation — migration-events

  • 4.1 Create packages/database/migration/src/migration-events/migration-events.ts exporting migrationEvents: EventBus<MigrationEventMap> plus createMigrationEvents() factory
  • 4.2 Extend MigrationEventMap in types/migration.types.ts with the lifecycle keys: "migration:started", "migration:applied", "migration:failed", "migration:completed", "migration:rolled-back" (additive — preserve migration:before / migration:after / migration:plan)
  • 4.3 Update MigrationExecutor to emit both legacy AND canonical lifecycle keys for one release; add // genesis: legacy emit removed in follow-up change comment (no @deprecated per CLAUDE.md rule)
  • 4.4 Add a migration-events.md sibling doc (≥200 words, basic + advanced examples) covering the event-bus subscription pattern
  • 4.5 Wire migrationEvents into index.ts exports

5. Implementation — batch types

  • 5.1 Add BatchTargetStatus = "pending" | "running" | "completed" | "failed" type alias to types/migration.types.ts
  • 5.2 Add BatchTargetProgress interface (targetId, status, results, error?, startedAt?, completedAt?)
  • 5.3 Add TargetConfigFactory = (targetId: string) => MigrationRunnerConfig | Promise<MigrationRunnerConfig> type alias
  • 5.4 Update BatchMigratorConfig to accept either the existing targets array OR a configFactory + targetIds pair (additive)
  • 5.5 Update BatchMigrator to emit BatchTargetProgress updates via an optional onProgress?: (progress: BatchTargetProgress) => void callback
  • 5.6 Re-export the new types from index.ts
  • 5.7 Update batch-migrator.md sibling doc to cover the new factory pattern

6. Implementation — status GetAllRecordsFn

  • 6.1 Add GetAllRecordsFn = () => Promise<MigrationRecord[]> type alias to status/migration-status.ts
  • 6.2 Update MigrationStatusDashboard constructor to accept an optional getAllRecords?: GetAllRecordsFn parameter; falls back to store.list() when absent
  • 6.3 Re-export GetAllRecordsFn from index.ts
  • 6.4 Update migration-status.md sibling doc to describe the injection point

7. Implementation — ValidationError re-export

  • 7.1 Add export type { MigrationValidationError as ValidationError } to types/migration.types.ts
  • 7.2 Update index.ts to export both MigrationValidationError and ValidationError

8. Implementation — MIGRATION_CODES registration

  • 8.1 Confirm the side-effect import in index.ts already triggers defineCodes registration on load
  • 8.2 Export an idempotent registerMigrationErrorCodes() function from errors/migration-error.ts for downstream consumers that bundle without side-effect imports
  • 8.3 Re-running registerMigrationErrorCodes() MUST NOT throw — guard with the registry's existing dedup
  • 8.4 Re-export registerMigrationErrorCodes from index.ts

9. Tests

  • 9.1 lock/migration-lock/migration-lock.test.ts — acquire returns true on uncontested lockId, false when contested; release frees lockId; extend refreshes TTL; multiple lockIds isolated; expired locks auto-release
  • 9.2 lock/migration-lock/migration-lock.spec-conformance.test.ts — pins MigrationLockAdapter back-compat alias; verifies MemoryMigrationLock satisfies BOTH interfaces
  • 9.3 store/migration-store/migration-store.test.ts — empty list initial; append → list returns single; markApplied flips status; markFailed records error; getLatestVersion returns latest by id sort
  • 9.4 store/migration-store/migration-store.spec-conformance.test.ts — pins MigrationStoreAdapter back-compat alias; verifies MemoryMigrationStore satisfies BOTH interfaces
  • 9.5 migration-events/migration-events.test.ts — every lifecycle key emits with the correct payload shape; multiple subscribers receive in registration order
  • 9.6 migration-events/migration-events.spec-conformance.test.ts — listener throwing does not abort emit loop; off() removes specific listener; clear() removes all
  • 9.7 batch/batch-migrator/batch-migrator.test.ts — BatchTargetProgress transitions pending → running → completed; failure transitions to failed and isolates from siblings; onProgress called per transition
  • 9.8 status/migration-status/migration-status.test.ts — GetAllRecordsFn injected source returned from getHistory(); absent factory falls back to store.list()
  • 9.9 errors/migration-error.spec-conformance.test.ts — ErrorCodes.has("MIGRATION.LOCK_HELD") is true after package import; second registerMigrationErrorCodes() call does not throw
  • 9.10 Every it(...) in 9.1–9.9 carries { timeout: 5000 } (or 30000 for genuinely async)

10. Documentation

  • 10.1 Sibling .md for every new implementation .ts (migration-lock.md, migration-store.md, migration-events.md); each ≥200 words with basic + advanced examples
  • 10.2 Update packages/database/migration/README.md — add Modules links for the three new files; add Quick-start snippet showing migrationEvents subscription
  • 10.3 Update CLAUDE.md package listing line for @suaveplan/migration if the public-surface description has changed

11. Pre-archive verification (the 5-gate triple)

  • 11.1 bun run check — Biome 0 errors / 0 warnings / 0 info across the whole monorepo
  • 11.2 bunx turbo lint typecheck test --filter=@suaveplan/migration — green
  • 11.3 bunx turbo test:coverage --filter=@suaveplan/migration — 100/100/100/100
  • 11.4 bun scripts/openspec-conformance.ts @suaveplan/migration — exit 0, no error findings
  • 11.5 bunx turbo build --filter=@suaveplan/migration — green

12. Pre-archive 7-row checklist (AGENTS.md Section 13)

  • 12.1 Generics threaded; expectTypeOf assertions on every literal-type claim (lifecycle key strings, BatchTargetStatus union)
  • 12.2 Zod schemas wired at every declared boundary (MigrationLockLike / MigrationStoreLike consumers do not need Zod — interfaces are TS-only; verify schemas are still wired in MigrationRunnerOptionsSchema etc.)
  • 12.3 Every error code in errors/migration-error.ts thrown by at least one production path
  • 12.4 Strict-mode behaviors tested both on and off (lock TTL expiry honoured under enableTtlEnforcement: true and bypassed when false)
  • 12.5 OTel instruments emitted from production paths and asserted with a real in-memory MeterProvider
  • 12.6 Lifecycle dedup tested where claimed (idempotent registerMigrationErrorCodes)
  • 12.7 No retroactive tick — every box above reflects work done in this change

13. Archive

  • 13.1 Fold spec delta into openspec/specs/migration/spec.md (will be the first time this canonical spec exists)
  • 13.2 Move openspec/changes/migration-adapters-completion/ → openspec/archive/<yyyy-mm-dd>-migration-adapters-completion/
  • 13.3 Refresh MANIFEST.md if package set or deps changed (no expected change here)