Files
suaveplan/openspec/archive/2026-05-16-add-storage-uri/tasks.md
2026-05-27 23:29:53 +01:00

6.5 KiB

Tasks — add-storage-uri

Every checkbox MUST reflect work actually done in this change.

1. Spec authoring

  • 1.1 Read openspec/specs/types/spec.md and confirm StorageLike is the right structural target
  • 1.2 Read openspec/AGENTS.md §0c, §13, §14
  • 1.3 Read openspec/archive/2026-05-16-add-storage-http/ end-to-end as the closest precedent
  • 1.4 Read packages/core/types/src/storage-like.ts to confirm the structural surface available
  • 1.5 Draft proposal.md from openspec/templates/proposal.md
  • 1.6 Draft design.md covering tier, file layout, dispatch, stream/write fallback, per-scheme parse contract, OTel surface
  • 1.7 Draft specs/storage-uri/spec.md — every requirement carries a **Verified by:** line at authoring time
  • 1.8 Build the numbered Requirement/Scenario implementation checklist (per §0c step 6)

2. Scaffolding

  • 2.1 Create packages/storage/storage-uri/ mirroring packages/storage/storage-http/ conventions
  • 2.2 Write package.json v0.0.0, "sideEffects": false, subpath exports for every feature module
  • 2.3 Wire deps: @suaveplan/error, @suaveplan/types, @opentelemetry/api, tslib (all workspace:^ / catalog:)
  • 2.4 Wire devDeps: @suaveplan/testing, @suaveplan/storage-file, @suaveplan/storage-http, @vitest/coverage-istanbul, fast-check, typescript, vite, vite-plugin-dts, vitest
  • 2.5 Write tsconfig.json, tsconfig.lib.json, vite.config.ts, vitest.config.ts (via createTestConfig)
  • 2.6 Write tests/setup/polyfills.ts and README.md skeleton

3. Core implementation

  • 3.1 src/error-codes/error-codes.ts — defineCodes("STORAGE_URI", [...]) with 8 codes, StorageUriError class, uri/scheme discriminants
  • 3.2 src/types/plugin.types.ts — UriPlugin, ParsedUri interfaces
  • 3.3 src/types/resolver.types.ts — StorageUriResolver shape, StatResult, ListResult
  • 3.4 src/parse-uri/parse-uri.ts — RFC 3986 scheme+authority+path split, INVALID_URI mapping, 4096-char cap, null-byte rejection
  • 3.5 src/otel/otel.ts — meter+tracer wiring, recordOp(op, scheme, outcome, ms), URI redaction (drop query string)
  • 3.6 src/resolver/resolver.ts — registry construction, frozen map, scheme dispatch (case-insensitive), AbortSignal short-circuit, ADAPTER_ERROR wrap, exists/remove/stat delegates
  • 3.7 src/resolver/resolver.streams.ts — open() with createReadStream forwarding + one-chunk fallback + counter
  • 3.8 src/resolver/resolver.writes.ts — write() accepting Uint8Array | ReadableStream, createWriteStream forwarding + drain fallback + counter
  • 3.9 src/resolver/resolver.list.ts — prefix list, plugin.build re-serialise, LIST_UNSUPPORTED for plugins without build
  • 3.10 src/conformance/conformance.ts — runUriPluginConformance(plugin, fixtures) harness
  • 3.11 src/index.ts — explicit named re-exports per §6a (no export * in non-root barrels)

4. Tests (every it(...) carries { timeout: 5000 })

  • 4.1 src/parse-uri/parse-uri.test.ts — valid scheme set, malformed inputs → INVALID_URI, null-byte rejection, 4096-char cap, case-insensitive scheme
  • 4.2 src/error-codes/error-codes.test.ts — every code reachable, discriminants populated, cause preserved
  • 4.3 src/resolver/resolver.test.ts — scheme dispatch, UNKNOWN_SCHEME, case-insensitive scheme match, SCHEME_CONFLICT, idempotent re-registration, AbortSignal pre/forward, ADAPTER_ERROR wrap, exists/remove/stat delegation
  • 4.4 src/resolver/resolver.streams.test.ts — native forwarding, one-chunk fallback + counter, NOT_FOUND on undefined
  • 4.5 src/resolver/resolver.writes.test.ts — Uint8Array forwarding, stream drain + counter, WRITE_UNSUPPORTED re-wrap
  • 4.6 src/resolver/resolver.list.test.ts — re-serialisation via build, LIST_UNSUPPORTED when build absent, continuation token round-trip
  • 4.7 src/resolver/resolver.spec-conformance.test.ts — type conformance against StorageLike, every STORAGE_URI code reachable, capability probing
  • 4.8 src/otel/otel.test.ts — duration histogram on success, errors_total on failure, query-string redaction in span attributes (via in-memory MeterProvider + SpanExporter)
  • 4.9 src/conformance/conformance.test.ts — harness passes for a good plugin, fails for broken round-trip
  • 4.10 tests/integration/cross-scheme.test.ts — real storage-file + real storage-http composition, read both via the same resolver
  • 4.11 No imports from vitest or bun:test in test files — all via @suaveplan/testing/runner (§7)

5. Sibling adapter plugins (additive — each in its own package)

  • 5.1 storage-file: add src/uri-plugin/uri-plugin.ts exporting fileUriPlugin(options), sibling .md, conformance test using runUriPluginConformance
  • 5.2 storage-http: add httpUriPlugin(adapter) and httpsUriPlugin(adapter) exports + conformance test
  • 5.3 storage-cdn-rackspace: add rackspaceUriPlugin(adapter, container) export + conformance test
  • 5.4 storage-cdn-bunnycdn: add bunnyUriPlugin(adapter, zone) export + conformance test
  • 5.5 (deferred) storage-s3: s3UriPlugin(adapter, bucket) — gated on s3 package landing

6. Documentation

  • 6.1 Sibling .md for every implementation .ts (≥200 words, basic + advanced examples, full API reference)
  • 6.2 README.md links every module under ## Modules
  • 6.3 README documents the cross-scheme media-pipeline composition recipe
  • 6.4 README documents how to author a third-party UriPlugin

7. Gates

  • 7.1 bun run check
  • 7.2 bunx turbo lint typecheck test --filter=@suaveplan/storage-uri
  • 7.3 bunx turbo test:coverage --filter=@suaveplan/storage-uri (100/100/100/100 Istanbul)
  • 7.4 bun scripts/lint/check-test-runner-imports.ts (rule 11)
  • 7.5 Tier-purity grep — grep -rnE "from ['\"](node:|bun:)" packages/storage/storage-uri/src/ returns empty
  • 7.6 bun scripts/openspec-conformance.ts @suaveplan/storage-uri
  • 7.7 Every sibling adapter package still green under its own pre-publish gate after adding its uriPlugin

8. Manifest & archival

  • 8.1 Add package to MANIFEST.md via bun scripts/folder-reorg/generate-manifest.ts
  • 8.2 Update STATUS.md (genesis-original — add to "Completed" once shipped)
  • 8.3 Fold specs/storage-uri/spec.md into openspec/specs/storage-uri/spec.md
  • 8.4 Move openspec/changes/add-storage-uri/ → openspec/archive/<yyyy-mm-dd>-add-storage-uri/