Files
suaveplan/openspec/archive/2026-05-19-enterprise-react-audio-foundation/tasks.md
2026-05-27 23:29:53 +01:00

6.2 KiB
Raw Blame History

Tasks: enterprise-react-audio-foundation

Change ID: enterprise-react-audio-foundation Package: @suaveplan/react-audio Target path: packages/react/react-audio Phase: 1 of 3 (foundation) Prerequisite packages on disk: @suaveplan/audio-engine-browser, @suaveplan/audio-fx-plugin-base, @suaveplan/audio-controllers, @suaveplan/audio-timeline, @suaveplan/audio-transport, @suaveplan/events, @suaveplan/error, @suaveplan/types, @suaveplan/opentelemetry — all shipped at v0.1.0.

Phase 1 ships provider + hooks + stores + error codes + a11y helpers + hooks-only subpath exports. Components are Phase 2 (enterprise-react-audio-components). MIDI learn-mode panel is Phase 3 (enterprise-react-audio-midi).


1. Scaffold

  • 1.1 Create directory tree per proposal.md "File layout" — src/{provider,hooks,stores,a11y,error-codes} plus tests/.
  • 1.2 Write package.json at 0.1.0, "type": "module", "sideEffects": false, foundation-scoped exports map (root + ./provider, ./hooks, ./hooks/<name> per hook, ./stores, ./a11y, ./error-codes). NO ./components entry yet — reserved for Phase 2. React 19 peer dep.
  • 1.3 Write tsconfig.json, tsconfig.lib.json, vite.config.ts, vitest.config.ts (happy-dom). Scripts.

2. Error codes

  • 2.1 src/error-codes/error-codes.ts — defineCodes("REACT_AUDIO", [...]), ReactAudioError extending SuaveplanError from @suaveplan/error. Export ReactAudioErrorCode, REACT_AUDIO_ERROR_METADATA, registerReactAudioErrorCodes(). Codes: NO_PROVIDER, PROVIDER_PENDING, UNKNOWN_PARAMETER, PRESET_STORE_FAILED, INVALID_OPTIONS.
  • 2.2 error-codes.test.ts + error-codes.md — every code reachable from a real call site (asserted).

3. Provider

  • 3.1 src/provider/provider-options.ts + .schemas.ts — Zod AudioProviderOptionsSchema covering adapter context, transport options, plugin auto-registration, preset store, sample rate, slot renderers (just typed — components consume them in Phase 2).
  • 3.2 src/provider/audio-provider.tsx — strict-mode-safe lifecycle; async init with AbortSignal; double-invoke proof; dispose on unmount; React context exposes { state: ProviderState | null, version: number }.
  • 3.3 audio-provider.test.tsx — strict-mode double-invoke produces exactly one engine; unmount disposes adapter + transport + bus registry exactly once; hook-outside-provider throws REACT_AUDIO.NO_PROVIDER.
  • 3.4 audio-provider.md.

4. Hooks (per src/hooks/<hook-name>/<hook-name>.{ts,test.tsx,md})

For each hook: implement with useSyncExternalStore, write .test.tsx covering happy + error + SSR-snapshot equality, and .md (≥200 words).

  • 4.1 use-engine-state — 'pending' | 'ready' | 'error'.
  • 4.2 use-audio-engine — returns ProviderState.
  • 4.3 use-timeline — TimelineEngine accessor + track CRUD.
  • 4.4 use-transport — Transport accessor + play/pause/stop/seek/setTempo.
  • 4.5 use-transport-time — frame-rate-sampled current time.
  • 4.6 use-track(trackId) — track state + per-track chain accessor.
  • 4.7 use-plugin-chain(trackId) — chain composition + events.
  • 4.8 use-chain-plugin(trackId, slotIndex) — slot accessor.
  • 4.9 use-audio-fx-plugin(pluginId) — plugin by id from registry.
  • 4.10 use-parameter(plugin, paramId) — value + set + curve + scheduleAt; throws REACT_AUDIO.UNKNOWN_PARAMETER for unknown ids.
  • 4.11 use-preset(plugin) — plugin-level preset save/load.
  • 4.12 use-chain-snapshot(chain) — chain-level snapshot save/load via preset store.
  • 4.13 use-bus(name) — bus accessor.

5. Stores

  • 5.1 src/stores/audio-store/audio-store.ts — provider-scoped Zustand store with override hook. Slim shape; no playback state (that's on transport).
  • 5.2 src/stores/ui-store/ui-store.ts — panels, theme, visualization mode, selectedTrackId, dragState. Ports verbatim from main.

6. A11y helpers (non-component-level, foundation-only)

  • 6.1 src/a11y/keyboard-bindings/keyboard-bindings.ts — central keymap export consumed by Phase-2 component knobs/sliders. Pure value table.
  • 6.2 src/a11y/aria-value-text/aria-value-text.ts — unit-aware formatAriaValueText(value, unit, min, max) formatter. Pure function.
  • 6.3 src/a11y/index.ts — explicit named re-exports.

7. Root barrel + tests

  • 7.1 src/index.ts — explicit named re-exports of provider, every hook, both stores, a11y helpers, error-codes surface (rule 10).
  • 7.2 tests/purity.test.ts — built dist/ references no AudioContext/OfflineAudioContext/AudioNode/node:*/process/Buffer; runtime dependencies match the foundation allowlist.
  • 7.3 tests/exports.test.ts — every Phase-1 surface has a subpath entry; ./components is NOT declared.

8. Documentation

  • 8.1 Sibling .md for every .ts/.tsx (except test/types/index — per CLAUDE.md), ≥200 words.
  • 8.2 README.md at package root with quick-start + hook examples + Phase-2/Phase-3 forward-reference.

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

  • 9.1 bun run check — Biome 0/0/0/0 monorepo-wide.
  • 9.2 bunx turbo lint typecheck test --filter=@suaveplan/react-audio — green.
  • 9.3 bunx turbo test:coverage --filter=@suaveplan/react-audio — 100/100/100/100.
  • 9.4 bun scripts/openspec-conformance.ts @suaveplan/react-audio — PASS, exit 0.
  • 9.5 bunx turbo build --filter=@suaveplan/react-audio — green.
  • 9.6 bun scripts/docs-check.ts packages/react/react-audio — 100%.

10. Archive

  • 10.1 Fold the foundation spec delta into NEW openspec/specs/react-audio/spec.md (Phase 1 shipped requirements). The canonical spec will grow with Phase 2 and Phase 3 — leave room.
  • 10.2 git mv openspec/changes/enterprise-react-audio-foundation openspec/archive/2026-05-19-enterprise-react-audio-foundation.
  • 10.3 Refresh MANIFEST.md via bun scripts/folder-reorg/generate-manifest.ts. STATUS.md row for @suaveplan/react-audio stays at – (Phase 1 alone is incomplete relative to the proposal's full scope) — flip to ✅ only when Phase 3 lands. Note Phase 1 progress in the description column ("Phase 1 of 3 shipped: hooks + provider").