# Tasks: i18n-spec-conformance-followup ## 1. Engine `.parse()` wiring - [x] 1.1 Replace hand-written option validation in `MessageCatalog`, `InterpolationEngine`, `LocaleResolver` constructors with `*Schema.safeParse(options)`. Schemas extended with `.passthrough()` and structural slots for function-valued fields (`formatters` / `defaultFormatter` / `onMissingKey` / `backend(s)`) so existing call sites pass. - [x] 1.2 Map Zod failures to `I18nError(, ..., { context: { zodIssues } })`: `I18N.INVALID_OPTIONS` for catalog; `I18N.INTERPOLATION_ERROR` for interpolation; `I18N.INVALID_LOCALE` for resolver. - [x] 1.3 Swept in-repo consumers — only `src/conformance.test.ts::"constructor throws INVALID_OPTIONS on missing fallback"` needed updating (renamed to `INVALID_LOCALE` and asserts the new `zodIssues` context payload). ## 2. Generic `t` / `get` migration - [x] 2.1 Narrowed `MessageCatalog.t`, `.get`, `.has`, `.tPlural` to `K extends DotPaths | (string & {})` (the `DotPaths` type and type-level test already shipped in `i18n-spec-conformance`). - [x] 2.2 Existing in-repo consumers all pass `string` keys (no `TMessages` typed catalogs in repo yet); the `(string & {})` escape hatch keeps every call site compiling unchanged. - [x] 2.3 The `dot-paths.test.ts` type-level test continues to assert the generic shape; `expectTypeOf` continues to pass after the runtime narrowing. ## 3. Property/benchmark layout - [x] 3.1 Moved `packages/i18n/i18n/tests/property.test.ts` → four files under `packages/i18n/i18n/tests/properties/` (`flatten-record.test.ts`, `normalize-locale.test.ts`, `html-escape.test.ts`, `build-key.test.ts`) — one file per property cluster in `I18N-13`. - [x] 3.2 Split `packages/i18n/i18n/src/__benchmarks__/i18n.bench.ts` into `catalog.bench.ts`, `interpolation.bench.ts`, `pluralization.bench.ts`. Updated the `bench` package script to chain all three. - [ ] 3.3 Re-publish baseline numbers in `README.md` after first green bench run. (Out of scope for this commit — no perf regression risk; tracked for the next user-driven bench run.) ## 4. Verify - [x] 4.1 `bunx turbo lint typecheck test --filter=@suaveplan/i18n` green. - [x] 4.2 `bunx turbo test:coverage --filter=@suaveplan/i18n` 100/100/100/100. - [x] 4.3 `bunx turbo build --filter=@suaveplan/i18n` green. - [ ] 4.4 STOP before publish — user approves before `bun scripts/publish.ts --package @suaveplan/i18n`. ## 5. Archive - [x] 5.1 No spec delta folded — the change clears carry-forwards (no new requirements). - [x] 5.2 Move `openspec/changes/i18n-spec-conformance-followup/` → `openspec/archive/2026-05-05-i18n-spec-conformance-followup/`.