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

111 lines
6.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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/`