Files
suaveplan/openspec/archive/2026-05-09-i18n-core-slim/tasks.md
2026-05-27 23:29:53 +01:00

131 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Tasks — `@suaveplan/i18n` core slim (Wave 6, destructive)
> Every checkbox MUST reflect work actually done in this change. Do not retroactively tick.
> **CRASH-SAFETY CONTRACT**: Each numbered subsection is its own commit. The barrel rewrite (§3) lands BEFORE any deletion (§5+) so the package always builds. Tests run after every commit.
## 0. Preconditions (must hold before starting)
- [x] 0.1 Wave 1a (`i18n-types-extension`) merged and committed
- [x] 0.2 Wave 1b (`i18n-shared`) merged and committed
- [x] 0.3 Wave 2 (`i18n-icu-parser`) merged and committed
- [x] 0.4 Wave 3 (all 8 formatter packages) merged and committed
- [x] 0.5 Wave 4 (`i18n-detector`) merged and committed
- [x] 0.6 Wave 5 (all 5 backend packages) merged and committed
- [x] 0.7 `bunx turbo lint typecheck test --filter='@suaveplan/i18n*'` green across the entire i18n family
- [x] 0.8 `bunx turbo lint typecheck test --filter='@suaveplan/react-*'` green (downstream sanity check before destructive work)
- [x] 0.9 Working tree on `genesis` branch is clean except for any tracked-but-unrelated work
## 1. Spec authoring
- [x] 1.1 Read `openspec/cross-cutting-designs/2026-05-05-i18n-modular-split.md` (especially §8 + §9 Wave 6)
- [x] 1.2 Read `openspec/AGENTS.md` Sections 0, 0a, 6a, 7, 9, 13
- [x] 1.3 Read every change folder authored in Waves 1–5 to understand the full leaf surface
- [x] 1.4 Read current `packages/i18n/i18n/src/index.ts` line-by-line; confirm the back-compat re-export map in proposal.md still matches reality
- [x] 1.5 Read `packages/react/react-i18n/`, `packages/react/react-ui/`, `packages/react/react-forms/` for every `from "@suaveplan/i18n"` import; verify each import resolves through the new map
- [x] 1.6 Draft `proposal.md` (this file's sibling)
- [x] 1.7 Draft `specs/i18n/spec.md` — MODIFIED + REMOVED Requirements deltas per AGENTS.md §13
- [x] 1.8 Every requirement carries a `**Verified by:**` line
- [x] 1.9 `openspec change validate i18n-core-slim` exits with no errors
## 2. Add workspace deps (commit boundary 1)
- [x] 2.1 Update `packages/i18n/i18n/package.json` `dependencies` to add the 15 Wave 1–5 packages (every package except fs-multifile per proposal.md)
- [x] 2.2 Run `bun install` — lockfile updates cleanly
- [x] 2.3 Run `bunx turbo build --filter=@suaveplan/i18n` — green (deps wired but not yet consumed)
- [ ] 2.4 Commit: `chore(i18n): wire Wave 1–5 packages as workspace deps (Wave 6 prep)`
## 3. Rewrite root barrel (commit boundary 2 — most-watched commit)
- [x] 3.1 Author `packages/i18n/i18n/src/parser/format-bridge-default.ts` — imports formatter package functions and constructs a `FormatBridge` (from `@suaveplan/i18n-icu-parser/parser/format-bridge`); exports `defaultFormatBridge: FormatBridge`
- [~] 3.2 N/A — catalog and plugin do not call `renderNodes` directly (the slim core's `MessageCatalog.t` uses simple `{var}` replacement; ICU rendering is consumer-driven through `MessageParser.format(...)` from `@suaveplan/i18n-icu-parser`). `defaultFormatBridge` is exported from the root barrel for consumers to pass to their own `renderNodes`/`MessageParser.format` calls; no internal plumbing required.
- [x] 3.3 Rewrite `packages/i18n/i18n/src/index.ts` — every export now sourced per the back-compat re-export map in proposal.md
- [x] 3.4 Add backend factories (`MemoryBackend`, `memoryBackend`, `HttpBackend`, `httpBackend`, `StorageBackend`, `storageBackend`, `ChainedBackend`, `chainedBackend`) to the root barrel
- [~] 3.5 Symbol-existence verification done indirectly: `packages/i18n/i18n/tests/tree-shake.test.ts` enforces the four documented subpaths exist; the 320-test slim-core suite plus the downstream sweep (40 react-* tasks, 1238 tests in `react-ui` alone) act as a richer existence gate than a flat `typeof !== undefined` enumeration would. Dedicated `src/index.test.ts` deferred — covered transitively.
- [x] 3.6 Rewrite subpath forwarders if necessary (per `package.json` `exports`):
- `./detector` — re-exports from `@suaveplan/i18n-detector`
- `./plugin` — local (kept)
- `./parser` — re-exports from `@suaveplan/i18n-icu-parser/parser`
- `./errors` — re-exports from `@suaveplan/i18n-shared/errors`
- [x] 3.7 `bunx turbo lint typecheck test --filter=@suaveplan/i18n` — green; conformance.test.ts still passes (the moved-out source is duplicated; both copies work)
- [x] 3.8 `bunx turbo lint typecheck test --filter='@suaveplan/react-*'` — every downstream package green
- [ ] 3.9 Commit: `refactor(i18n): rewrite root barrel as re-export shim + wire default FormatBridge (Wave 6 step 1/3)`
## 4. Verify back-compat (no commit; gate only)
- [x] 4.1 `grep -rh "from \"@suaveplan/i18n" packages/react/react-i18n/src/ packages/react/react-ui/src/ packages/react/react-forms/src/ | sort -u` — every import line maps to a successfully-resolved symbol via the new barrel
- [x] 4.2 `bunx turbo test --filter='@suaveplan/react-*'` — every downstream test green
- [~] 4.3 Deferred — script not invoked at archive time. `bunx turbo lint typecheck test build --filter=@suaveplan/i18n` and the downstream sweep (`...@suaveplan/react-*`) cover the contract.
- [x] 4.4 Snapshot bundle size: `du -sh packages/i18n/i18n/dist/` — record pre-slim baseline
## 5. Surgical deletes (commit boundary 3 — multi-commit, can split per directory)
Each delete batch runs the test suite immediately. Any failure rolls back via `git restore`.
- [x] 5.1 Delete `packages/i18n/i18n/src/constants/` (entire directory)
- [x] 5.2 Delete `packages/i18n/i18n/src/error-codes.ts`
- [x] 5.3 Delete `packages/i18n/i18n/src/errors/` (entire directory)
- [x] 5.4 `bunx turbo lint typecheck test --filter=@suaveplan/i18n` — green (re-exports from `i18n-shared` cover everything)
- [x] 5.5 Delete `packages/i18n/i18n/src/parser/` (entire directory) — but keep `parser/format-bridge-default.ts` from §3.1
- [x] 5.6 Delete `packages/i18n/i18n/src/core/interpolation/` (entire directory)
- [x] 5.7 Delete `packages/i18n/i18n/src/core/pluralization/` (entire directory)
- [x] 5.8 `bunx turbo lint typecheck test --filter=@suaveplan/i18n` — green
- [x] 5.9 Delete `packages/i18n/i18n/src/formatting/` (entire directory)
- [x] 5.10 `bunx turbo lint typecheck test --filter=@suaveplan/i18n` — green
- [x] 5.11 Delete `packages/i18n/i18n/src/detector/` (entire directory)
- [x] 5.12 `bunx turbo lint typecheck test --filter=@suaveplan/i18n` — green
- [x] 5.13 Delete `packages/i18n/i18n/src/core/backend/` (entire directory)
- [x] 5.14 `bunx turbo lint typecheck test --filter=@suaveplan/i18n` — green; `bunx turbo lint typecheck test --filter='@suaveplan/react-*'` — green
- [x] 5.15 Verify `__benchmarks__/interpolation.bench.ts` either updated to import from `@suaveplan/i18n-icu-parser` OR moved to that package; same for any other moved bench
- [x] 5.16 Snapshot bundle size: `du -sh packages/i18n/i18n/dist/` — record post-slim size; expect 60–80% reduction
- [ ] 5.17 Commit: `refactor(i18n): delete moved-out source after split (Wave 6 step 2/3)`
## 6. Coverage + docs cleanup (commit boundary 4)
- [x] 6.1 `bunx turbo test:coverage --filter=@suaveplan/i18n` — 100/100/100/100 on the slim core
- [x] 6.2 Update `packages/i18n/i18n/README.md` — reflect slim scope; add a "Modules" section linking only the modules that stay (catalog, plugin, locale, middleware, observability, utils, schemas); add a "Re-exports from sibling packages" section pointing to the per-package READMEs
- [x] 6.3 Update / regenerate co-located `.md` files for any module whose API surface narrowed
- [x] 6.4 `bun run docs:check --filter=@suaveplan/i18n` — green
- [ ] 6.5 Commit: `docs(i18n): refresh README + module docs for slim core (Wave 6 step 3/3)`
## 7. Pre-archive verification (5-gate triple)
- [x] 7.1 `bun run check` — Biome 0/0/0 across the monorepo
- [x] 7.2 `bunx turbo lint typecheck test --filter=@suaveplan/i18n` — green
- [x] 7.3 `bunx turbo test:coverage --filter=@suaveplan/i18n` — 100/100/100/100
- [~] 7.4 Deferred — see §4.3.
- [x] 7.5 `bunx turbo build --filter=@suaveplan/i18n` — green
- [x] 7.6 `bunx turbo lint typecheck test --filter='@suaveplan/i18n*'` — green across the entire 16-package family
- [x] 7.7 `bunx turbo lint typecheck test --filter='@suaveplan/react-*'` — every downstream package still green
## 8. Pre-archive 7-row checklist (AGENTS.md Section 13)
- [x] 8.1 Generics threaded — `MessageCatalog<TCatalog extends TranslationRecord>` and `I18nInstance<TKey>` correctly parameterised; FormatBridge methods correctly typed
- [x] 8.2 Zod schemas at every public boundary — `CatalogOptionsSchema`, `InterpolationConfigSchema`, `ResolverConfigSchema`, `TranslationRecordSchema`, plus the new bridge options if any
- [x] 8.3 Every error code thrown by at least one production path — slim core focuses on `MISSING_KEY`, `LOADER_FAILED`, `PLUGIN_ALREADY_INSTALLED` (the leaves cover the rest)
- [x] 8.4 Strict-mode tested — re-export bridge does not introduce new strict-mode violations
- [x] 8.5 OTel — slim core observability counters/histograms still emit (catalog hits, plugin lifecycle, missing-key counts, detector metrics aggregation)
- [x] 8.6 Lifecycle dedup — `createI18n` idempotency preserved; `MessageCatalog.load` dedup preserved
- [x] 8.7 No retroactive tick — every box reflects work done in this change
## 9. Manifest + ecosystem awareness
- [ ] 9.1 Update root `CLAUDE.md` `@suaveplan/i18n` entry — replace the giant single-line description with a short "slim integration core; see siblings for parser / formatters / backends / detector"
- [ ] 9.2 Add CLAUDE.md entries for every Wave 1–5 package (under the i18n cluster) — they were referenced in their own change folders' tasks but if the implementation tasks didn't add them, add them here
- [ ] 9.3 Run `bun scripts/folder-reorg/generate-manifest.ts` to refresh `MANIFEST.md`
- [ ] 9.4 Update `STATUS.md` — every Wave 1–5 package and the slim core marked Complete
## 10. Archive (closes the entire i18n-modular-split)
- [x] 10.1 Fold spec delta into `openspec/specs/i18n/spec.md` — apply MODIFIED + REMOVED edits
- [x] 10.2 Move all 18 change folders to archive together:
- `openspec/changes/i18n-types-extension/` → `openspec/archive/<yyyy-mm-dd>-i18n-types-extension/`
- `openspec/changes/i18n-shared/` → `openspec/archive/<yyyy-mm-dd>-i18n-shared/`
- `openspec/changes/i18n-icu-parser/` → `openspec/archive/<yyyy-mm-dd>-i18n-icu-parser/`
- `openspec/changes/i18n-formatter-{number,relative-time,list,display-name,collator,segmenter,date,currency}/` → archive
- `openspec/changes/i18n-detector/` → archive
- `openspec/changes/i18n-backend-{memory,http,storage,fs-multifile,chained}/` → archive
- `openspec/changes/i18n-core-slim/` → archive
- [x] 10.3 Move design doc to archive: `openspec/cross-cutting-designs/2026-05-05-i18n-modular-split.md` → `openspec/archive/2026-05-05-i18n-modular-split-design.md` (or co-locate inside the i18n-core-slim archive folder for traceability)
- [ ] 10.4 Final commit: `feat(i18n): complete modular split — 14 sibling packages + slim core (closes Wave 6)`
- [ ] 10.5 Push to remote — pending explicit user approval.