Files
suaveplan/openspec/archive/2026-05-19-wire-notification-channels/tasks.md
2026-05-27 23:29:53 +01:00

5.6 KiB

Tasks — wire-notification-channels

Every checkbox MUST reflect work actually done in this change. No retroactive ticks.

1. Spec authoring

  • 1.1 Read openspec/archive/2026-05-19-add-api-plugin-notifications/proposal.md end-to-end
  • 1.2 Read openspec/specs/api-plugin-notifications/spec.md (existing canonical spec)
  • 1.3 Read openspec/AGENTS.md Sections 6, 13, 14
  • 1.4 Draft proposal.md from openspec/templates/proposal.md
  • 1.5 Fill in ## Source mapping table — every requirement cites archived proposal lines or has a "no source line" justification
  • 1.6 Draft specs/api-plugin-notifications/spec.md with ## ADDED Requirements (dispatcher + channels + tracking) and ## MODIFIED Requirements (plugin lifecycle, options schema)
  • 1.7 Every requirement in the spec delta carries a **Verified by:** line naming concrete it(...) titles

2. Implementation

  • 2.1 Add @suaveplan/notification-channel, @suaveplan/emailer, @suaveplan/delivery-tracking to package.json dependencies via workspace:^
  • 2.2 Add new error codes (DISPATCH_FAILED, DISPATCH_CHANNEL_UNAVAILABLE, DISPATCH_INPUT_INVALID, EMAIL_SERVICE_UNAVAILABLE) to src/error-codes/error-codes.ts
  • 2.3 Add notificationsDispatchedTotal + notificationsDispatchFailedTotal OTel counters
  • 2.4 Create src/channels/apn-channel/ module — ApnDeliveryChannel implementing DeliveryChannel, with sibling .md
  • 2.5 Create src/channels/email-channel/ module — EmailDeliveryChannel implementing DeliveryChannel, with sibling .md
  • 2.6 Create src/dispatcher/notification-dispatcher/ module — wraps NotificationRouter, emits delivery events, optional idempotency adapter, with sibling .md
  • 2.7 Create src/dispatcher/idempotency-adapter/ module — DispatcherIdempotencyAdapter interface + NoopIdempotencyAdapter impl, with sibling .md
  • 2.8 Create src/schemas/dispatch-schemas.ts — Zod DispatchInputSchema + DispatchResultSchema, with sibling .md
  • 2.9 Extend src/schemas/options.ts with enableDispatcher, defaultChannel, delivery fields; existing fields unchanged
  • 2.10 Extend src/services/registry-augmentation.ts with notificationDispatcher, emailService slots
  • 2.11 Extend src/plugin/plugin.ts — onInit registers emailService (if injected) + notificationDispatcher (if enableDispatcher); onClose clears the dispatcher
  • 2.12 Extend src/index.ts to re-export every new public symbol; add per-feature subpath exports in package.json

3. Tests

  • 3.1 src/channels/apn-channel/apn-channel.test.ts — every behavior (success, per-device failure, missing-token rejection, bulk fan-out via metadata.deviceTokens)
  • 3.2 src/channels/email-channel/email-channel.test.ts — success, missing subject, transport failure
  • 3.3 src/dispatcher/notification-dispatcher/notification-dispatcher.test.ts — end-to-end dispatcher: success path, channel-disabled, transport failure, delivery-tracking emission, idempotency dedup, default-channel fallback, OTel emission
  • 3.4 src/dispatcher/idempotency-adapter/idempotency-adapter.test.ts — NoopIdempotencyAdapter and a fake guard adapter
  • 3.5 src/schemas/dispatch-schemas.test.ts — Zod boundary tests
  • 3.6 Extend src/schemas/options.test.ts to cover the three new fields
  • 3.7 Extend src/plugin/plugin.test.ts to cover dispatcher registration + cleanup
  • 3.8 Extend src/error-codes/error-codes.test.ts to pin reachability of the four new codes
  • 3.9 Extend src/otel/instruments.test.ts to pin the two new counters
  • 3.10 Extend src/api-plugin-notifications.spec-conformance.test.ts to pin every new public export
  • 3.11 Every it(...) carries { timeout: 5000 } (or 30000 for genuinely async)

4. Documentation

  • 4.1 Sibling .md for every implementation .ts (≥200 words, basic + advanced examples, full API reference)
  • 4.2 README updated with a ## Dispatcher section linking the new modules

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

  • 5.1 bunx biome check src/ — Biome 0 errors from the package folder
  • 5.2 bunx turbo lint typecheck test --filter=@suaveplan/api-plugin-notifications — green
  • 5.3 bunx turbo test:coverage --filter=@suaveplan/api-plugin-notifications — 100/100/100/100 istanbul
  • 5.4 bun scripts/openspec-conformance.ts @suaveplan/api-plugin-notifications — exit 0
  • 5.5 bunx turbo build --filter=@suaveplan/api-plugin-notifications — green

6. Pre-archive 9-row checklist (AGENTS.md §13)

  • 6.1 Generics threaded; expectTypeOf assertions on every literal-type claim
  • 6.2 Zod schemas wired at every declared boundary (DispatchInput, options extension)
  • 6.3 Every error code in error-codes.ts thrown by at least one production path (incl. the four new codes)
  • 6.4 Strict-mode behaviors tested both on and off where applicable
  • 6.5 OTel instruments emitted from production paths and asserted with a real in-memory MeterProvider
  • 6.6 Lifecycle dedup tested (idempotency adapter exercised)
  • 6.7 No banned patterns — no vi.mock, no export * in feature barrels, no // biome-ignore, test files only import from @suaveplan/testing/runner
  • 6.8 Sibling .md ≥200 words for every implementation file
  • 6.9 No retroactive tick — every box above reflects work done in this change

7. Archive

  • 7.1 Fold ## ADDED + ## MODIFIED Requirements into openspec/specs/api-plugin-notifications/spec.md
  • 7.2 Move openspec/changes/wire-notification-channels/ → openspec/archive/2026-05-19-wire-notification-channels/