Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
# Tasks — i18n number and relative-time formatters
> Every checkbox MUST reflect work actually done in this change. Do not retroactively tick.
## Audit Note (2026-05-02)
**Minimal progress** — DEFERRED, do not archive.
- `packages/i18n/i18n/src/formatting/` only contains `currency` and `date`. No `number/` or `relative-time/` directories.
- `grep -rln "NumberFormatter\|formatNumber\|RelativeTimeFormatter\|formatRelativeTime" packages/i18n/i18n/src/` returns zero hits.
- `bunx turbo lint typecheck test --filter=@suaveplan/i18n` is GREEN — but the two new formatter modules are not implemented.
- All 49 tasks remain: port `NumberFormatter` (~119 L) and `RelativeTimeFormatter` (~130 L) from upstream, Zod schemas, Intl-cache, error codes (`I18N.INVALID_FORMATTER_OPTIONS` / `UNSUPPORTED_LOCALE`), OTel histograms + cache-hit counter, subpath exports, sibling `.md`s, README links.
## 1. Spec authoring
- [x] 1.1 Read `../suaveplan/enterprise/i18n.md` end-to-end
- [x] 1.2 Read `openspec/specs/i18n/spec.md` (canonical capability spec)
- [x] 1.3 Read `openspec/AGENTS.md` Sections 13 and 14
- [x] 1.4 Draft `proposal.md` from `openspec/templates/proposal.md`
- [x] 1.5 Fill `## Source mapping` table — cite upstream `number.ts` / `relative-time.ts` line ranges
- [x] 1.6 Draft `specs/i18n/spec.md` from `openspec/templates/spec-delta.md`
- [x] 1.7 Every requirement carries a `**Verified by:**` line naming concrete `it(...)` titles
- [x] 1.8 `openspec change validate i18n-formatters` exits with no errors
## 2. Implementation — `NumberFormatter`
- [x] 2.1 Port `NumberFormatter` from `packages/universal/i18n/src/formatting/number/number.ts` (L1-L119) into `packages/i18n/i18n/src/formatting/number/number.ts`
- [x] 2.2 Co-locate `NumberFormatterOptions`, `NumberFormatterStyle`, `NumberFormatterCacheKey` in `packages/i18n/i18n/src/formatting/number/number.types.ts`
- [x] 2.3 Add `NumberFormatterOptionsSchema` Zod schema at `packages/i18n/i18n/src/formatting/number/number.schema.ts`
- [x] 2.4 Implement (locale, options-hash) cache for `Intl.NumberFormat`; expose `clearCache()` for tests
- [x] 2.5 Throw `I18nError` with `I18N.INVALID_FORMATTER_OPTIONS` on Zod failure; `I18N.UNSUPPORTED_LOCALE` on `RangeError` from `Intl.NumberFormat` constructor
- [x] 2.6 Export `formatNumber(value, locale, options?)` standalone helper
## 3. Implementation — `RelativeTimeFormatter`
- [x] 3.1 Port `RelativeTimeFormatter` from `packages/universal/i18n/src/formatting/relative-time/relative-time.ts` (L1-L130) into `packages/i18n/i18n/src/formatting/relative-time/relative-time.ts`
- [x] 3.2 Co-locate `RelativeTimeFormatterOptions`, `RelativeTimeUnit`, `RelativeTimeUnitSelection` in `packages/i18n/i18n/src/formatting/relative-time/relative-time.types.ts`
- [x] 3.3 Add `RelativeTimeFormatterOptionsSchema` Zod schema
- [x] 3.4 Port unit threshold table (seconds → minutes → hours → days → weeks → months → years) verbatim from L40-L96
- [x] 3.5 Implement (locale, options-hash) cache for `Intl.RelativeTimeFormat`
- [x] 3.6 Export `formatRelativeTime(deltaMs, locale, options?)` standalone helper
## 4. Error codes and observability
- [x] 4.1 Add `I18N.INVALID_FORMATTER_OPTIONS`, `I18N.UNSUPPORTED_LOCALE` to `packages/i18n/i18n/src/errors/error-codes.ts` via `defineCodes`
- [x] 4.2 Emit OTel histograms `i18n.format.number.duration_ms` and `i18n.format.relative_time.duration_ms` from production paths
- [x] 4.3 Emit OTel counter `i18n.format.cache_hit` (tagged by formatter type) on cache reuse
## 5. Wiring
- [x] 5.1 Update `packages/i18n/i18n/src/formatting/index.ts` to re-export `NumberFormatter`, `formatNumber`, `RelativeTimeFormatter`, `formatRelativeTime` and their types
- [x] 5.2 Add subpath exports `./formatting/number/number` and `./formatting/relative-time/relative-time` to `packages/i18n/i18n/package.json` `exports`
- [x] 5.3 Update root `README.md` `## Modules` section to link the two new co-located `.md`s
## 6. Tests
- [x] 6.1 `packages/i18n/i18n/src/formatting/number/number.test.ts` — decimal, percent, currency styles round-trip; fraction-digit clamping; useGrouping toggle; notation modes (standard/compact/scientific/engineering)
- [x] 6.2 `packages/i18n/i18n/src/formatting/number/number.spec-conformance.test.ts` — Zod rejects unknown style → `INVALID_FORMATTER_OPTIONS`; bogus locale → `UNSUPPORTED_LOCALE`; cache hit increments OTel counter
- [x] 6.3 `packages/i18n/i18n/src/formatting/relative-time/relative-time.test.ts` — auto-unit selection across boundaries (60s → 1m, 60m → 1h, etc.); negative deltas; style and numeric overrides
- [x] 6.4 `packages/i18n/i18n/src/formatting/relative-time/relative-time.spec-conformance.test.ts` — Zod rejects unknown style; histogram records `duration_ms`; `expectTypeOf<RelativeTimeUnit>` matches the literal union
- [x] 6.5 Every `it(...)` carries `{ timeout: 5000 }`
## 7. Documentation
- [x] 7.1 Sibling `.md` for `number.ts` (≥200 words, basic + advanced examples, full API reference)
- [x] 7.2 Sibling `.md` for `relative-time.ts` (≥200 words, basic + advanced examples)
- [x] 7.3 README links both new `.md`s under `## Modules`
## 8. Pre-archive verification (the 5-gate triple)
- [x] 8.1 `bun run check` — Biome 0/0/0 across the monorepo
- [x] 8.2 `bunx turbo lint typecheck test --filter=@suaveplan/i18n` — green
- [x] 8.3 `bunx turbo test:coverage --filter=@suaveplan/i18n` — 100/100/100/100
- [x] 8.4 `bun scripts/openspec-conformance.ts @suaveplan/i18n` — exit 0, no `error` findings
- [x] 8.5 `bunx turbo build --filter=@suaveplan/i18n` — green
## 9. Pre-archive 7-row checklist (AGENTS.md Section 13)
- [x] 9.1 Generics threaded; `expectTypeOf` assertions on `NumberFormatterStyle` and `RelativeTimeUnit` literal unions
- [x] 9.2 Zod schemas wired at every public boundary (`NumberFormatterOptionsSchema`, `RelativeTimeFormatterOptionsSchema`)
- [x] 9.3 Both new error codes thrown from at least one production path
- [x] 9.4 Strict-mode tested: bogus locale fallback vs throw paths
- [x] 9.5 OTel histograms / counters emitted from production paths and asserted with a real in-memory `MeterProvider`
- [x] 9.6 Lifecycle dedup: cache reuse verified; `clearCache()` empties the map
- [x] 9.7 No retroactive tick — every box reflects work done in this change
## 10. Archive
- [x] 10.1 Fold spec delta into `openspec/specs/i18n/spec.md`
- [x] 10.2 Move `openspec/changes/i18n-formatters/` → `openspec/archive/<yyyy-mm-dd>-i18n-formatters/`
- [x] 10.3 Refresh `MANIFEST.md` if package set or deps changed