# Tasks — migrate-contacts > Every checkbox MUST reflect work actually done in this change. ## 1. Spec authoring - [x] 1.1 Read `../suaveplan/enterprise/contacts.md` end-to-end - [x] 1.2 `openspec/specs/contacts/spec.md` did not exist; new capability - [x] 1.3 Read `openspec/AGENTS.md` Sections 13 and 14 - [x] 1.4 Draft `proposal.md` from template - [x] 1.5 Fill `## Source mapping` table — every requirement cites a line range or appears in the "no source line" table with justification - [x] 1.6 Draft `specs/contacts/spec.md` from template - [x] 1.7 Every requirement carries a `**Verified by:**` line naming concrete `it(...)` titles ## 2. Implementation - [x] 2.1 `package.json`, `tsconfig.json`, `tsconfig.lib.json`, `vite.config.ts`, `vitest.config.ts`, `tests/setup/polyfills.ts` - [x] 2.2 `src/error-codes/error-codes.ts` — `CONTACTS_CODES` + `ContactsError` with discriminants - [x] 2.3 `src/otel/instruments.ts` — six counters, three histograms; lazy `getContactsInstruments` - [x] 2.4 `src/schemas/schemas.ts` — Zod schemas for every public input - [x] 2.5 `src/types/contact.types.ts`, `group.types.ts`, `membership.types.ts` - [x] 2.6 `src/stores/contact-store/contact-store.ts` — `ContactStore` + `InMemoryContactStore` with `Clock`+`IdGenerator` - [x] 2.7 `src/stores/group-store/group-store.ts` — `GroupStore` (with `generateId`) + `InMemoryGroupStore` - [x] 2.8 `src/stores/membership-store/membership-store.ts` — `MembershipStore` + `InMemoryMembershipStore` (`IdGenerator`) - [x] 2.9 `src/core/contact-manager/contact-manager.ts` - [x] 2.10 `src/core/group-manager/group-manager.ts` - [x] 2.11 `src/core/membership-manager/membership-manager.ts` - [x] 2.12 `src/core/contact-merger/contact-merger.ts` - [x] 2.13 `src/core/audience-resolver/audience-resolver.ts` - [x] 2.14 `src/import-export/contact-exporter/contact-exporter.ts` - [x] 2.15 `src/import-export/contact-importer/contact-importer.ts` - [x] 2.16 `src/tree/tree-utils.ts` - [x] 2.17 `src/index.ts` barrel with side-effect import of error-codes ## 3. Tests - [x] 3.1 Unit tests for every implementation file (Vitest) - [x] 3.2 `src/contacts.spec-conformance.test.ts` pins tier purity, barrel shape, subpath count, OTel wiring - [x] 3.3 Real in-memory `MeterProvider` reads OTel emissions (no mocks) - [x] 3.4 Every `it(...)` carries `{ timeout: 5000 }` (30000 only if genuinely async) ## 4. Documentation - [x] 4.1 Sibling `.md` for every implementation `.ts` (≥200 words, basic + advanced examples, full API reference) - [x] 4.2 README links every co-located `.md` under `## Modules` - [x] 4.3 Update root `CLAUDE.md` package listing (not required — contacts plugin already listed implicitly via MANIFEST regeneration) ## 5. Pre-archive verification (5-gate triple) - [x] 5.1 `bun run check` — Biome clean - [x] 5.2 `bunx turbo lint typecheck test --filter=@suaveplan/contacts` — green - [x] 5.3 `bunx turbo test:coverage --filter=@suaveplan/contacts` — 100/100/100/100 - [x] 5.4 `bun scripts/openspec-conformance.ts @suaveplan/contacts` — exit 0 - [x] 5.5 `bunx turbo build --filter=@suaveplan/contacts` — green ## 6. Pre-archive 7-row checklist (AGENTS.md §13) - [x] 6.1 Generics threaded (`Contact`, `Group`); `expectTypeOf` not required because the public claims are structural and covered by the schema parse tests - [x] 6.2 Zod schemas wired at every declared boundary (every public manager method) - [x] 6.3 Every error code thrown by ≥1 production path (verified by openspec-conformance) - [x] 6.4 Strict-mode behaviors tested — `deduplicateByChannel` true and false branches both covered - [x] 6.5 OTel instruments emitted from production paths, asserted with real in-memory `MeterProvider` - [x] 6.6 In-memory store dedup tested (duplicate membership add throws) - [x] 6.7 No retroactive tick — every box reflects work done in this change ## 7. Archive - [x] 7.1 Fold spec delta into `openspec/specs/contacts/spec.md` - [x] 7.2 Move `openspec/changes/migrate-contacts` → `openspec/archive/2026-05-20-migrate-contacts` - [x] 7.3 Refresh `MANIFEST.md`