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

6.9 KiB
Raw Permalink Blame History

Tasks — complete-storage-mux

Every checkbox MUST reflect work actually done in this change.

0. Pre-flight (non-negotiable)

  • 0.1 Confirm clean working tree (git status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in each)
  • 0.2 If any worktrees exist under .claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
  • 0.3 Confirm the package set in MANIFEST.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

1. Spec authoring

  • 1.1 Read openspec/specs/storage/spec.md and confirm AbstractStorage surface
  • 1.2 Read openspec/AGENTS.md §0c, §13, §14
  • 1.3 Read archived openspec/archive/2026-05-16-add-storage-cdn/ for the deferral and family conventions
  • 1.4 Read packages/flow/retry/src/ to confirm runWithRetry + RetryStrategy surface
  • 1.5 Read packages/events/events/src/ to confirm EventBusLike shape
  • 1.6 Draft proposal.md, design.md, specs/storage-mux/spec.md, tasks.md
  • 1.7 Numbered Requirement/Scenario checklist per §0c step 6

2. Scaffolding

  • 2.1 Create packages/storage/storage-mux/ mirroring packages/storage/storage-cdn/ conventions
  • 2.2 package.json v0.0.0, "sideEffects": false, subpath exports per feature directory
  • 2.3 Deps: @suaveplan/error, @suaveplan/events, @suaveplan/retry, @suaveplan/storage, @suaveplan/types, @opentelemetry/api, zod, tslib
  • 2.4 DevDeps: @suaveplan/testing, @vitest/coverage-istanbul, fast-check, mitata, typescript, vite, vite-plugin-dts, vitest
  • 2.5 tsconfig.json, vite.config.ts, vitest.config.ts via createTestConfig with thresholds: 100/100/100/100
  • 2.6 Root README.md with Modules section linking every co-located .md

3. Error registry

  • 3.1 src/error-codes/error-codes.ts — defineCodes("STORAGE_MUX", [...]) with all 14 codes: ALL_BACKENDS_DOWN, NO_BACKENDS_CONFIGURED, HEALTHCHECK_FAILED, BACKEND_TIMEOUT, INVALID_MODE, INVALID_WEIGHT, WRITE_FANOUT_PARTIAL, BACKEND_ABORTED, BACKEND_NOT_FOUND, BACKEND_NAME_CONFLICT, BACKEND_DRAINING, WEIGHTED_REQUIRES_WEIGHTS, MIRROR_ORIGIN_REQUIRED, RECURSION_DEPTH_EXCEEDED
  • 3.2 StorageMuxError extends SuaveplanError<StorageMuxErrorCode> with backendName, attemptIndex, attemptCount, mode discriminants
  • 3.3 error-codes.md + error-codes.test.ts — reachability sweep proving every code is thrown from a real call site

4. Types & schemas

  • 4.1 src/types/backend-entry.types.ts — BackendEntry (name, storage, weight?, healthcheck?, tags?)
  • 4.2 src/types/mux-options.types.ts — MuxMode union, StorageMuxOptions, BackendStats, MuxStats
  • 4.3 src/types/mux-options.schemas.ts — Zod schemas: non-empty backends, mode whitelist, weight >= 0, cooldownMs >= 0, unique names

5. Classification

  • 5.1 src/classify/classify.ts + .md + .test.ts — pure classify(err) => "transient" | "semantic" | "abort" per design §4

6. Bulkhead

  • 6.1 src/bulkhead/bulkhead.ts + .md + .test.ts — Promise.race timeout, AbortSignal.any composition, hung-promise non-blocking

7. Health

  • 7.1 src/health/health.ts + .md + .test.ts — BackendHealth tracker, exponential cooldown capped at maxCooldownMs, recovery probe, active healthcheck scheduling via injected Clock, draining accounting

8. Stats

  • 8.1 src/stats/stats.ts + .md + .test.ts — per-backend counters, Vitter Algorithm R reservoir-sampled latencies (256 slots), mux.stats() snapshot API

9. Modes (six)

  • 9.1 src/modes/selector.types.ts — BackendSelector + BackendExecutor interfaces
  • 9.2 src/modes/failover/failover.ts + .md + .test.ts — fall-through + retry composition + ALL_BACKENDS_DOWN
  • 9.3 src/modes/round-robin/round-robin.ts + .md + .test.ts — atomic counter, skip down/draining
  • 9.4 src/modes/weighted/weighted.ts + .md + .test.ts — Walker alias-method, rebuild on mutation, weight validation
  • 9.5 src/modes/sticky-by-key/sticky-by-key.ts + .md + .test.ts — FNV-1a, deterministic, redistribution on backend removal
  • 9.6 src/modes/shield/shield.ts + .md + .test.ts — origin-first reads, fan-out writes, WRITE_FANOUT_PARTIAL opt-in
  • 9.7 src/modes/mirror/mirror.ts + .md + .test.ts — Promise.any reads, Promise.allSettled writes, symmetric peers

10. Runtime mutation

  • 10.1 src/mutate/mutate.ts + .md + .test.ts — addBackend, removeBackend, setWeight, drain with in-flight accounting

11. Observability

  • 11.1 src/observability/events.ts + .md + .test.ts — event topic constants and emit helpers consuming EventBusLike
  • 11.2 src/observability/otel.ts + .md + .test.ts — per-attempt child-span helper with attribute set

12. Mux core

  • 12.1 src/mux/mux.ts + .md — StorageMux extends AbstractStorage, per-op routing through selector + bulkhead + runWithRetry, AbortSignal.any composition, recursion depth guard
  • 12.2 src/mux/mux.test.ts — construction validation, mode dispatch, abort surfacing, recursion cap
  • 12.3 src/mux/mux.spec-conformance.test.ts — runStorageConformance × 6 modes × 3-backend MemoryStorage fleet, plus one two-level recursive mux

13. Barrel + exports

  • 13.1 src/index.ts — explicit named re-exports per §6a (NO export *)
  • 13.2 package.json subpath exports — one entry per feature directory; verify count matches

14. Documentation

  • 14.1 Sibling .md for every implementation .ts (≥ 200 words, all required sections, real-import examples)
  • 14.2 README.md documents each of the six modes with a usage example + a section on runtime mutation + stats

15. Gates

  • 15.1 bun run check
  • 15.2 bunx turbo lint typecheck test --filter=@suaveplan/storage-mux
  • 15.3 bunx turbo test:coverage --filter=@suaveplan/storage-mux (100/100/100/100)
  • 15.4 bun scripts/lint/check-test-runner-imports.ts → zero output
  • 15.5 Tier-purity grep grep -rnE "from ['\"](node:|bun:)" packages/storage/storage-mux/src/ → empty
  • 15.6 Banned-pattern scan → empty
  • 15.7 bun scripts/openspec-conformance.ts @suaveplan/storage-mux

16. Manifest & archival

  • 16.1 bun scripts/folder-reorg/generate-manifest.ts
  • 16.2 bun scripts/generate-missing.ts
  • 16.3 Update STATUS.md and SUMMARY.md
  • 16.4 bunx markdownlint-cli2 --fix
  • 16.5 Fold specs/storage-mux/spec.md → openspec/specs/storage-mux/spec.md
  • 16.6 Move change folder → openspec/archive/<yyyy-mm-dd>-complete-storage-mux/