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

7.5 KiB

Tasks — @suaveplan/i18n-backend-http (fetch-based translation backend)

Every checkbox MUST reflect work actually done in this change. Do not retroactively tick.

1. Spec authoring

  • 1.1 Read openspec/cross-cutting-designs/2026-05-05-i18n-modular-split.md end-to-end (especially §3, §6, §6.1)
  • 1.2 Read openspec/AGENTS.md Sections 0, 0a, 6a, 7, 9, 13
  • 1.3 Read source: packages/i18n/i18n/src/core/backend/http/http-backend.ts, http-backend.test.ts, http-backend.schemas.ts, http-backend.md, plus packages/i18n/i18n/src/core/backend/backend.types.ts
  • 1.4 Draft proposal.md from openspec/templates/proposal.md
  • 1.5 Fill ## Source mapping table with verified line ranges from monolith
  • 1.6 Draft specs/i18n-backend-http/spec.md from openspec/templates/spec-delta.md
  • 1.7 Every requirement carries a **Verified by:** line naming concrete it(...) titles
  • 1.8 openspec change validate i18n-backend-http exits with no errors

2. Package scaffold

  • 2.1 mkdir -p packages/i18n/i18n-backend-http/src
  • 2.2 Author package.json — name @suaveplan/i18n-backend-http, version 0.1.0, type module, sideEffects false. Deps: @suaveplan/i18n-shared workspace:^, @suaveplan/types workspace:^, @suaveplan/error workspace:^, @opentelemetry/api catalog:observability, tslib catalog:build, zod catalog:forms. devDeps: @suaveplan/testing workspace:^, @suaveplan/typescript-config workspace:^, @vitest/coverage-istanbul catalog:testing, vitest catalog:testing.
  • 2.3 Author tsconfig.json extending @suaveplan/typescript-config/library.json
  • 2.4 Author vite.config.ts using createTestConfig() from @suaveplan/testing/config
  • 2.5 Author README.md (≥200 words, includes Modules table linking to each .md)
  • 2.6 Add package.json exports map with subpaths ., ./backend, ./factory, ./parser, ./url-builder

3. Implementation

  • 3.1 Author src/backend.types.ts — port HttpBackendOptions, ParsePayloadFn, HttpHeadersInit, CustomHeadersFn, HttpBackendRetry from monolith L8-L70 verbatim
  • 3.2 Author src/backend.schemas.ts — port HttpBackendOptionsSchema Zod schema verbatim (40 lines)
  • 3.3 Author src/url-builder.ts — extract #buildUrl body into a standalone buildUrl(loadPath, locale, namespace): string function with URL-encoding
  • 3.4 Author src/payload-parser.ts — extract defaultParsePayload ParsePayloadFn (JSON parse + non-object rejection) as a standalone export
  • 3.5 Author src/observability.ts — inline equivalents of recordRead from packages/i18n/i18n/src/observability/backend-metrics.ts; export i18n.backend.http.read_duration_ms histogram, i18n.backend.http.read_total{outcome} counter, i18n.backend.http.read_errors_total{code,status?} counter
  • 3.6 Author src/backend.ts — port HttpBackend class from monolith L80-L240; rewire imports; emit metrics via src/observability.ts; thread optional signal?: AbortSignal into the RequestInit passed to fetch AND throw I18nError(I18N.BACKEND_TIMEOUT) when the signal aborts during retry; preserve defaultFetch() fallback (L242-L252)

4. Factory function

  • 4.1 Author src/factory.ts — httpBackend(options: HttpBackendOptions): HttpBackend returning new HttpBackend(options)

5. Documentation (sibling .md per implementation file)

  • 5.1 src/backend.md — port from packages/i18n/i18n/src/core/backend/http/http-backend.md; ≥200 words; basic + advanced examples (custom parser, custom headers, retry policy)
  • 5.2 src/factory.md — ≥200 words; basic + advanced examples
  • 5.3 src/url-builder.md — placeholder substitution + URL-encoding semantics
  • 5.4 src/payload-parser.md — JSON-object rejection rules; how to plug a custom parser
  • 5.5 src/observability.md — emitted metrics + units + cardinality
  • 5.6 README.md ## Modules section links every .md

6. Tests (Vitest, runner-neutral imports per CLAUDE.md §11)

  • 6.1 src/backend.test.ts — port every test from packages/i18n/i18n/src/core/backend/http/http-backend.test.ts; same it(...) titles for conformance traceability; cover 200 OK, 404 → BACKEND_LOCALE_NOT_AVAILABLE, 500 → BACKEND_READ_FAILED, TypeError network failure → BACKEND_READ_FAILED, payload-parse failure → BACKEND_READ_FAILED, custom parsePayload, customHeaders callback, crossDomain: true, injected retry policy
  • 6.2 src/backend.spec-conformance.test.ts — one it(...) per spec requirement; titles match **Verified by:** lines exactly
  • 6.3 src/factory.test.ts — httpBackend() returns HttpBackend instance; default name === "http"
  • 6.4 src/url-builder.test.ts — {locale} and {namespace} substitution; URL-encoding for special characters
  • 6.5 src/payload-parser.test.ts — JSON object accepted; array / null / primitive rejected with BACKEND_READ_FAILED
  • 6.6 src/index.test.ts — every documented public export resolves through ., ./backend, ./factory, ./parser, ./url-builder
  • 6.7 Add an AbortSignal cancellation test — pre-aborted signal causes read to throw I18nError(I18N.BACKEND_TIMEOUT); mid-flight abort during retry also throws BACKEND_TIMEOUT
  • 6.8 Every it(...) carries { timeout: 5000 }
  • 6.9 All test imports go through @suaveplan/testing/runner (CLAUDE.md §11) — verified by grep -rnE "from ['\"](vitest|bun:test)['\"]" packages/i18n/i18n-backend-http/src/ returning zero hits
  • 6.10 No // biome-ignore suppressions (CLAUDE.md §9)
  • 6.11 No export * in any non-root barrel (CLAUDE.md §10)

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-backend-http — green
  • 7.3 bunx turbo test:coverage --filter=@suaveplan/i18n-backend-http — 100/100/100/100
  • 7.4 bun scripts/openspec-conformance.ts @suaveplan/i18n-backend-http — exit 0
  • 7.5 bunx turbo build --filter=@suaveplan/i18n-backend-http — green

8. Pre-archive 7-row checklist (AGENTS.md Section 13)

  • 8.1 Generics threaded — HttpBackendRetry.run<T> parametric generic preserved; ParsePayloadFn correctly typed
  • 8.2 Zod schemas wired at the public boundary — HttpBackendOptionsSchema parses constructor input
  • 8.3 Every error code thrown by at least one production path: INVALID_OPTIONS (constructor), BACKEND_LOCALE_NOT_AVAILABLE (404), BACKEND_READ_FAILED (5xx / network / parse failure), BACKEND_TIMEOUT (signal aborted)
  • 8.4 Strict-mode tested — RequestInit shape verified via expectTypeOf
  • 8.5 OTel histograms emitted from production paths: i18n.backend.http.read_duration_ms; counters read_total, read_errors_total{status}
  • 8.6 Lifecycle dedup — N/A (HTTP backend has no async init/dispose)
  • 8.7 No retroactive tick — every box reflects work done in this change

9. Manifest + ecosystem awareness

  • 9.1 Add @suaveplan/i18n-backend-http entry to root CLAUDE.md package listing
  • 9.2 Run bun scripts/folder-reorg/generate-manifest.ts to refresh MANIFEST.md
  • 9.3 Append @suaveplan/i18n-backend-http to STATUS.md Completed list

10. Archive

  • 10.1 Fold spec delta into openspec/specs/i18n-backend-http/spec.md (NEW capability spec — first delta becomes canonical)
  • 10.2 Move openspec/changes/i18n-backend-http/ → openspec/archive/<yyyy-mm-dd>-i18n-backend-http/