Files
2026-05-27 23:29:53 +01:00

4.1 KiB

Tasks — add @suaveplan/currency-provider-open-exchange-rates

Every checkbox MUST reflect work actually done in this change. No retroactive ticks.

1. Spec authoring

  • 1.1 Read ../suaveplan/enterprise/currency-providers.md end-to-end
  • 1.2 Read slim-core archive at openspec/archive/2026-05-17-slim-currency-providers/
  • 1.3 Read openspec/AGENTS.md Sections 13 and 14
  • 1.4 Draft proposal.md from openspec/templates/proposal.md
  • 1.5 Fill ## Source mapping table — every requirement cites a line range OR appears in the "no source line" table with justification
  • 1.6 Draft specs/currency-provider-open-exchange-rates/spec.md from openspec/templates/spec-delta.md
  • 1.7 Every requirement carries a **Verified by:** line naming concrete it(...) titles

2. Implementation

  • 2.1 package.json with workspace deps on @suaveplan/currency, @suaveplan/currency-providers, @suaveplan/error, @suaveplan/types; tslib from catalog; sideEffects: false; subpath export for ./provider/provider
  • 2.2 vite.config.ts, vitest.config.ts, tsconfig.json, tsconfig.lib.json mirroring slim-core's shape
  • 2.3 tests/setup/polyfills.ts placeholder
  • 2.4 src/provider/provider.ts with OpenExchangeRatesProvider class and OpenExchangeRatesProviderConfig type
  • 2.5 src/index.ts barrel re-exporting OpenExchangeRatesProvider and OpenExchangeRatesProviderConfig
  • 2.6 Constructor validates apiKey !== "" → MISSING_CONFIG
  • 2.7 fetchRates() rejects non-USD base when allowNonUsdBase !== true → UNSUPPORTED_BASE
  • 2.8 fetchRates() routes through httpRequest() from slim core
  • 2.9 Response parsing validates { base, rates, timestamp } shape → PARSE_ERROR on mismatch
  • 2.10 2xx error payload ({ error: true, status, message }) → UPSTREAM_ERROR with upstreamMessage
  • 2.11 options.targets filter — missing target → UNKNOWN_CURRENCY
  • 2.12 Timestamp seconds * 1000 conversion

3. Tests

  • 3.1 src/provider/provider.test.ts covering every scenario in the spec delta
  • 3.2 tests/dep-graph.test.ts pinning dep invariants
  • 3.3 Every it(...) carries { timeout: 5000 }
  • 3.4 All test imports from @suaveplan/testing/runner (CLAUDE.md rule 11)

4. Documentation

  • 4.1 Sibling .md for src/provider/provider.ts (≥200 words, basic + advanced examples, full API reference)
  • 4.2 README.md at package root with ## Modules linking sibling docs
  • 4.3 Update CLAUDE.md package listing (added under finance family)

5. Pre-archive verification (5-gate triple)

  • 5.1 bun run check — Biome 0/0/0
  • 5.2 bunx turbo lint typecheck test --filter=@suaveplan/currency-provider-open-exchange-rates — green
  • 5.3 bunx turbo test:coverage --filter=@suaveplan/currency-provider-open-exchange-rates — 100/100/100/100
  • 5.4 Banned-pattern + barrel-shape + test-runner scans — zero output
  • 5.5 bunx turbo build --filter=@suaveplan/currency-provider-open-exchange-rates — green

6. Pre-archive 8-row checklist

  • 6.1 Generics threaded; expectTypeOf not required (no generic public surface)
  • 6.2 Zod schemas not required (provider parses upstream JSON inline with typed PARSE_ERROR)
  • 6.3 Every error code (HTTP_ERROR, PARSE_ERROR, UPSTREAM_ERROR, MISSING_CONFIG, UNSUPPORTED_BASE, UNKNOWN_CURRENCY) thrown by ≥1 production code path
  • 6.4 Strict-mode behaviors (free-tier base rejection) tested both on and off
  • 6.5 OTel — not in scope per ## Out of scope; deferred to cross-cutting follow-up
  • 6.6 Lifecycle dedup — not in scope
  • 6.7 No retroactive tick
  • 6.8 No export * in feature barrels — only index.ts barrel exists (root) and uses explicit named exports

7. Archive

  • 7.1 Fold spec delta into openspec/specs/currency-provider-open-exchange-rates/spec.md
  • 7.2 Move openspec/changes/add-currency-provider-open-exchange-rates/ → openspec/archive/2026-05-17-add-currency-provider-open-exchange-rates/
  • 7.3 Refresh MANIFEST.md