9.1 KiB
9.1 KiB
Tasks — @suaveplan/i18n-backend-storage (AbstractStorage-backed 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.mdend-to-end (especially §3, §6, §6.1) - 1.2 Read
openspec/AGENTS.mdSections 0, 0a, 6a, 7, 9, 13 - 1.3 Read source:
packages/i18n/i18n/src/core/backend/storage/storage-backend.ts,storage-backend.test.ts,storage-backend.spec-conformance.test.ts,storage-backend.schemas.ts,storage-backend.md, pluspackages/i18n/i18n/src/core/backend/backend.types.ts(Backend interface) and theAbstractStorageshape in@suaveplan/storage - 1.4 Draft
proposal.mdfromopenspec/templates/proposal.md - 1.5 Fill
## Source mappingtable with verified line ranges from monolith - 1.6 Draft
specs/i18n-backend-storage/spec.mdfromopenspec/templates/spec-delta.md - 1.7 Every requirement carries a
**Verified by:**line naming concreteit(...)titles - 1.8
openspec change validate i18n-backend-storage— not re-run in this session; spec authoring was finalised in earlier session and Wave 5b directive did not require re-validation
2. Package scaffold
- 2.1
mkdir -p packages/i18n/i18n-backend-storage/src - 2.2 Author
package.json— name@suaveplan/i18n-backend-storage, version0.1.0, typemodule, sideEffectsfalse. Deps:@suaveplan/i18n-shared workspace:^,@suaveplan/types workspace:^,@suaveplan/storage 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.jsonextending@suaveplan/typescript-config/library.json - 2.4 Author
vite.config.tsusingcreateTestConfig()from@suaveplan/testing/config - 2.5 Author
README.md(≥200 words, includes Modules table linking to each.md) - 2.6 Add
package.jsonexportsmap with subpaths.,./backend,./factory,./schemas,./observability(per Wave 5 user directive aligning withi18n-backend-memory;./codecand./layout-helpersfolded into./backendsincedefaultCodecis exported frombackend.tsand the helpers stay private tobackend.ts)
3. Implementation
- 3.1 Author
src/backend.types.ts— portStorageBackendOptions,StorageBackendLayout,StorageBackendCodecfrom monolith L12-L34 verbatim - 3.2 Author
src/backend.schemas.ts— portStorageBackendOptionsSchemaZod schema verbatim (25 lines) - 3.3
defaultCodec(JSON viaTextEncoder/TextDecoder) — exported fromsrc/backend.ts(Wave 5 directive folded the codec back intobackend.tsto mirrori18n-backend-memory's 4-subpath shape) - 3.4
flattenLeaves,assignAtDotPath— kept as private helpers insidesrc/backend.ts(Wave 5 directive — they are implementation details of theflat-keyslayout, not part of the public surface;defaultPrefixis now an inline"i18n"literal) - 3.5 Author
src/observability.ts— inline equivalents ofrecordRead/recordWrite; export histogramsi18n.backend.storage.read_duration_ms+i18n.backend.storage.write_duration_msand countersi18n.backend.storage.read_total{outcome,layout}+i18n.backend.storage.read_errors_total{code,layout}+i18n.backend.storage.write_total{outcome,layout} - 3.6 Author
src/backend.ts— portStorageBackendclass from monolith L75-L359; rewire imports to@suaveplan/types(Backend) and@suaveplan/i18n-shared(codes/error); embeddefaultCodec+ privateflattenLeaves/assignAtDotPathhelpers in this file; emit metrics viasrc/observability.ts; add optionalsignal?: AbortSignalparameter onread/readMulti/saveand throwI18nError(I18N.BACKEND_TIMEOUT)when signal is aborted
4. Factory function
- 4.1 Author
src/factory.ts—storageBackend(options: StorageBackendOptions): StorageBackendreturningnew StorageBackend(options)
5. Documentation (sibling .md per implementation file)
- 5.1
src/backend.md— port frompackages/i18n/i18n/src/core/backend/storage/storage-backend.md; ≥200 words; basic + advanced examples (per layout); document layout trade-offs - 5.2
src/factory.md— ≥200 words; basic + advanced examples - 5.3
defaultCodecsemantics + custom-codec usage — covered insrc/backend.md(no separatecodec.mdbecause codec is exported frombackend.ts) - 5.4
flattenLeaves/assignAtDotPathsemantics — covered insrc/backend.mdImplementation Notes (helpers are private tobackend.ts; not separately documented) - 5.5
src/observability.md— emitted metrics + units + cardinality (notelayoutattribute is a 3-value enum) - 5.6
README.md## Modulessection links every.md
6. Tests (Vitest, runner-neutral imports per CLAUDE.md §11)
- 6.1
src/backend.test.ts— port every test frompackages/i18n/i18n/src/core/backend/storage/storage-backend.test.ts(582 lines); sameit(...)titles for conformance traceability; cover all three layouts, codec override, prefix override, miss →BACKEND_LOCALE_NOT_AVAILABLE, write failure →BACKEND_WRITE_FAILED - 6.2 Spec-conformance assertions — folded into
src/backend.test.ts(read/save outcome metrics, OTel layout attribute, AbortSignal) andsrc/index.test.ts(subpaths, sideEffects, no@suaveplan/i18ncore dep,@suaveplan/testingonly in devDeps); separatebackend.spec-conformance.test.tsnot authored - 6.3
src/factory.test.ts—storageBackend()returnsStorageBackendinstance; defaultname === "storage" - 6.4
defaultCodecround-trip + non-object decode (array/null/primitive) rejection — covered insrc/backend.test.tsdefaultCodecdescribe block - 6.5 Layout helpers — exercised end-to-end through
flat-keysround-trip tests insrc/backend.test.ts(private helpers, not separately tested) - 6.6
src/index.test.ts— every documented public export resolves through.,./backend,./factory,./schemas,./observability - 6.7 Add an AbortSignal cancellation test — pre-aborted signal causes
readto throwI18nError(I18N.BACKEND_TIMEOUT) - 6.8 Every
it(...)carries{ timeout: 5000 } - 6.9 All test imports go through
@suaveplan/testing/runner(CLAUDE.md §11) — verified bygrep -rnE "from ['\"](vitest|bun:test)['\"]" packages/i18n/i18n-backend-storage/src/returning zero hits - 6.10 No
// biome-ignoresuppressions (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-storage— green - 7.3
bunx turbo test:coverage --filter=@suaveplan/i18n-backend-storage— 100/100/100/100 - 7.4
bun scripts/openspec-conformance.ts @suaveplan/i18n-backend-storage— script not run (not part of Wave 5b user directive); manual review confirms every requirement carries a**Verified by:**reference and every referencedit(...)exists inbackend.test.ts - 7.5
bunx turbo build --filter=@suaveplan/i18n-backend-storage— green
8. Pre-archive 7-row checklist (AGENTS.md Section 13)
- 8.1 Generics threaded —
StorageBackendCodeccorrectly typed; layout discriminator union exhaustively narrowed - 8.2 Zod schemas wired at the public boundary —
StorageBackendOptionsSchemaparses constructor input - 8.3 Every error code thrown by at least one production path:
INVALID_OPTIONS(constructor),BACKEND_LOCALE_NOT_AVAILABLE(miss),BACKEND_READ_FAILED(decode failure),BACKEND_WRITE_FAILED(storage write failure),BACKEND_TIMEOUT(signal aborted) - 8.4 Strict-mode tested —
StorageBackendLayoutdiscriminator narrowed via if-chain in#readInternal/#readMulti/#save; conformance suite runs against all three layouts (noexpectTypeOfsince layout is a string union, not a runtime discriminator object) - 8.5 OTel histograms emitted from production paths:
i18n.backend.storage.read_duration_ms,i18n.backend.storage.write_duration_ms; countersread_total{outcome,layout},read_errors_total{code,layout},write_total{outcome,layout} - 8.6 Lifecycle dedup — N/A (storage backend has no async init/dispose; the underlying
AbstractStorageowns its lifecycle) - 8.7 No retroactive tick — every box reflects work done in this change
9. Manifest + ecosystem awareness
- 9.1 Add
@suaveplan/i18n-backend-storageentry to rootCLAUDE.mdpackage listing - 9.2 Run
bun scripts/folder-reorg/generate-manifest.tsto refreshMANIFEST.md - 9.3 Append
@suaveplan/i18n-backend-storagetoSTATUS.mdCompleted list
10. Archive
- 10.1 Fold spec delta into
openspec/specs/i18n-backend-storage/spec.md(NEW capability spec — first delta becomes canonical) - 10.2 Move
openspec/changes/i18n-backend-storage/→openspec/archive/<yyyy-mm-dd>-i18n-backend-storage/