11 KiB
11 KiB
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)
- 0.1 Wave 1a (
i18n-types-extension) merged and committed - 0.2 Wave 1b (
i18n-shared) merged and committed - 0.3 Wave 2 (
i18n-icu-parser) merged and committed - 0.4 Wave 3 (all 8 formatter packages) merged and committed
- 0.5 Wave 4 (
i18n-detector) merged and committed - 0.6 Wave 5 (all 5 backend packages) merged and committed
- 0.7
bunx turbo lint typecheck test --filter='@suaveplan/i18n*'green across the entire i18n family - 0.8
bunx turbo lint typecheck test --filter='@suaveplan/react-*'green (downstream sanity check before destructive work) - 0.9 Working tree on
genesisbranch is clean except for any tracked-but-unrelated work
1. Spec authoring
- 1.1 Read
openspec/cross-cutting-designs/2026-05-05-i18n-modular-split.md(especially §8 + §9 Wave 6) - 1.2 Read
openspec/AGENTS.mdSections 0, 0a, 6a, 7, 9, 13 - 1.3 Read every change folder authored in Waves 1–5 to understand the full leaf surface
- 1.4 Read current
packages/i18n/i18n/src/index.tsline-by-line; confirm the back-compat re-export map in proposal.md still matches reality - 1.5 Read
packages/react/react-i18n/,packages/react/react-ui/,packages/react/react-forms/for everyfrom "@suaveplan/i18n"import; verify each import resolves through the new map - 1.6 Draft
proposal.md(this file's sibling) - 1.7 Draft
specs/i18n/spec.md— MODIFIED + REMOVED Requirements deltas per AGENTS.md §13 - 1.8 Every requirement carries a
**Verified by:**line - 1.9
openspec change validate i18n-core-slimexits with no errors
2. Add workspace deps (commit boundary 1)
- 2.1 Update
packages/i18n/i18n/package.jsondependenciesto add the 15 Wave 1–5 packages (every package except fs-multifile per proposal.md) - 2.2 Run
bun install— lockfile updates cleanly - 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)
- 3.1 Author
packages/i18n/i18n/src/parser/format-bridge-default.ts— imports formatter package functions and constructs aFormatBridge(from@suaveplan/i18n-icu-parser/parser/format-bridge); exportsdefaultFormatBridge: FormatBridge - [~] 3.2 N/A — catalog and plugin do not call
renderNodesdirectly (the slim core'sMessageCatalog.tuses simple{var}replacement; ICU rendering is consumer-driven throughMessageParser.format(...)from@suaveplan/i18n-icu-parser).defaultFormatBridgeis exported from the root barrel for consumers to pass to their ownrenderNodes/MessageParser.formatcalls; no internal plumbing required. - 3.3 Rewrite
packages/i18n/i18n/src/index.ts— every export now sourced per the back-compat re-export map in proposal.md - 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.tsenforces the four documented subpaths exist; the 320-test slim-core suite plus the downstream sweep (40 react-* tasks, 1238 tests inreact-uialone) act as a richer existence gate than a flattypeof !== undefinedenumeration would. Dedicatedsrc/index.test.tsdeferred — covered transitively. - 3.6 Rewrite subpath forwarders if necessary (per
package.jsonexports):./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
- 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) - 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)
- 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 - 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/i18nand the downstream sweep (...@suaveplan/react-*) cover the contract. - 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.
- 5.1 Delete
packages/i18n/i18n/src/constants/(entire directory) - 5.2 Delete
packages/i18n/i18n/src/error-codes.ts - 5.3 Delete
packages/i18n/i18n/src/errors/(entire directory) - 5.4
bunx turbo lint typecheck test --filter=@suaveplan/i18n— green (re-exports fromi18n-sharedcover everything) - 5.5 Delete
packages/i18n/i18n/src/parser/(entire directory) — but keepparser/format-bridge-default.tsfrom §3.1 - 5.6 Delete
packages/i18n/i18n/src/core/interpolation/(entire directory) - 5.7 Delete
packages/i18n/i18n/src/core/pluralization/(entire directory) - 5.8
bunx turbo lint typecheck test --filter=@suaveplan/i18n— green - 5.9 Delete
packages/i18n/i18n/src/formatting/(entire directory) - 5.10
bunx turbo lint typecheck test --filter=@suaveplan/i18n— green - 5.11 Delete
packages/i18n/i18n/src/detector/(entire directory) - 5.12
bunx turbo lint typecheck test --filter=@suaveplan/i18n— green - 5.13 Delete
packages/i18n/i18n/src/core/backend/(entire directory) - 5.14
bunx turbo lint typecheck test --filter=@suaveplan/i18n— green;bunx turbo lint typecheck test --filter='@suaveplan/react-*'— green - 5.15 Verify
__benchmarks__/interpolation.bench.tseither updated to import from@suaveplan/i18n-icu-parserOR moved to that package; same for any other moved bench - 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)
- 6.1
bunx turbo test:coverage --filter=@suaveplan/i18n— 100/100/100/100 on the slim core - 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 - 6.3 Update / regenerate co-located
.mdfiles for any module whose API surface narrowed - 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)
- 7.1
bun run check— Biome 0/0/0 across the monorepo - 7.2
bunx turbo lint typecheck test --filter=@suaveplan/i18n— green - 7.3
bunx turbo test:coverage --filter=@suaveplan/i18n— 100/100/100/100 - [~] 7.4 Deferred — see §4.3.
- 7.5
bunx turbo build --filter=@suaveplan/i18n— green - 7.6
bunx turbo lint typecheck test --filter='@suaveplan/i18n*'— green across the entire 16-package family - 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)
- 8.1 Generics threaded —
MessageCatalog<TCatalog extends TranslationRecord>andI18nInstance<TKey>correctly parameterised; FormatBridge methods correctly typed - 8.2 Zod schemas at every public boundary —
CatalogOptionsSchema,InterpolationConfigSchema,ResolverConfigSchema,TranslationRecordSchema, plus the new bridge options if any - 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) - 8.4 Strict-mode tested — re-export bridge does not introduce new strict-mode violations
- 8.5 OTel — slim core observability counters/histograms still emit (catalog hits, plugin lifecycle, missing-key counts, detector metrics aggregation)
- 8.6 Lifecycle dedup —
createI18nidempotency preserved;MessageCatalog.loaddedup preserved - 8.7 No retroactive tick — every box reflects work done in this change
9. Manifest + ecosystem awareness
- 9.1 Update root
CLAUDE.md@suaveplan/i18nentry — 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.tsto refreshMANIFEST.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)
- 10.1 Fold spec delta into
openspec/specs/i18n/spec.md— apply MODIFIED + REMOVED edits - 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}/→ archiveopenspec/changes/i18n-detector/→ archiveopenspec/changes/i18n-backend-{memory,http,storage,fs-multifile,chained}/→ archiveopenspec/changes/i18n-core-slim/→ archive
- 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.