Files
suaveplan/openspec/archive/2026-05-15-superseded-enterprise-browser-audio-engine/tasks.md
2026-05-27 23:29:53 +01:00

8.1 KiB

Tasks: enterprise-browser-audio-engine

Change ID: enterprise-browser-audio-engine Package: @suaveplan/audio-engine Target path: browser/audio/audio-engine Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/types, @suaveplan/events


1. Scaffold

  • Create browser/audio/audio-engine/ with src/, tests/, src/__benchmarks__/ and all feature subdirectories per the layout in proposal.md.
  • Write package.json at version 0.1.0:
    • "type": "module", "sideEffects": false
    • exports map with top-level "." plus subpath per feature module
    • dependencies: @suaveplan/error workspace:^, @suaveplan/types workspace:^, @suaveplan/events workspace:^, standardized-audio-context catalog:browser, zod catalog:forms, @opentelemetry/api catalog:observability, tslib catalog:build
    • devDependencies: vitest catalog:testing, @vitest/coverage-istanbul catalog:testing, mitata catalog:testing, @suaveplan/testing workspace:^
  • Write tsconfig.json extending @suaveplan/typescript-config/library-browser.json.
  • Write vitest.config.ts using createTestConfig() from @suaveplan/testing/config with pool: 'forks'.
  • Add lint, typecheck, test, test:coverage, build, docs:check, bench scripts.

2. Error codes (src/error-codes.ts)

  • Define AudioEngineErrorCode union: AUDIO_ENGINE_STATE_INVALID, AUDIO_PLUGIN_NOT_FOUND, AUDIO_PLUGIN_LOAD_FAILED, AUDIO_WORKLET_LOAD_FAILED, AUDIO_WORKLET_URL_REJECTED, AUDIO_GRAPH_CONNECT_FAILED, AUDIO_CONTEXT_UNAVAILABLE.
  • Define AUDIO_ENGINE_ERROR_METADATA with severity, retryable, httpStatus, userMessageKey, category, description per code.
  • Export registerAudioEngineErrorCodes() calling ErrorCodes.registerMany(...). Call it eagerly at module scope.
  • Re-export AudioEngineError extends SuaveplanError (not a local subclass).

3. Types (src/types/common.ts + common.md)

  • Define all shared interfaces: AudioEngineConfig, AudioEngineState, AudioEngineStateInfo, AudioEngineMetrics, AudioEngineEventMap, AudioGraphSnapshot, ParameterCurve, PerformanceMetrics.
  • Write common.md (≥200 words, simple + advanced examples, API reference).

4. Plugin system (src/plugin/)

4a. plugin/plugin.ts

  • Implement abstract AudioPlugin class with full lifecycle: state machine uninitialized → initializing → initialized → active ↔ inactive → destroyed, quarantine on error.
  • Implement parameter get/set with automatable support.
  • Write plugin.test.ts: state transitions, quarantine on thrown init, parameter CRUD.
  • Write plugin.md, plugin.types.ts.

4b. plugin-registry/plugin-registry.ts

  • Implement PluginRegistry: register, unregister, get, list, instantiate.
  • Add Zod schema AudioPluginDescriptorSchema; validate descriptor on register.
  • Write plugin-registry.test.ts, plugin-registry.md, plugin-registry.types.ts.

5. EventBus (src/event-bus/event-bus/)

  • Implement EventBus thin wrapper around @suaveplan/events EventEmitter with AudioEngineEventMap type parameter.
  • Write event-bus.test.ts, event-bus.md, event-bus.types.ts.

6. Audio graph (src/graph/)

6a. graph/graph.ts

  • Implement AudioGraph: add/remove/get nodes, connect/disconnect, traverse DFS, snapshot/restore.
  • Write graph.test.ts, graph.md, graph.types.ts.

6b. graph-connect/graph-connect.ts

  • Extract connection management logic (connect/disconnect with index params, validation, AUDIO_GRAPH_CONNECT_FAILED).
  • OTel histogram audio.graph_connect_ms.
  • Write graph-connect.test.ts, graph-connect.md.

6c. graph-traverse/graph-traverse.ts

  • Extract DFS traversal with cycle detection.
  • Write graph-traverse.test.ts, graph-traverse.md.

7. Queue engine (src/queue-engine/)

7a. queue-engine/queue-engine.ts

  • Implement AudioQueueEngine: enqueue/dequeue/play/stop, manage cue and sequence collections.
  • Write queue-engine.test.ts, queue-engine.md, queue-engine.types.ts.

7b. cue/cue.ts

  • Implement AudioCue scheduling logic (start time, offset, gain, loop via AudioBufferSourceNode).
  • Write cue.test.ts, cue.md.

7c. scheduler/scheduler.ts

  • Implement sequence scheduling with tempo and loop support.
  • Write scheduler.test.ts, scheduler.md.

8. Worklet manager (src/worklet/)

8a. worklet-loader/worklet-loader.ts

  • Implement addModule(url, options) with allow-list gate — throw AUDIO_WORKLET_URL_REJECTED on non-allowed URLs.
  • Cache loaded module URLs; avoid double-load.
  • OTel histogram audio.worklet_roundtrip_ms.
  • Write worklet-loader.test.ts, worklet-loader.md.

8b. worklet-messaging/worklet-messaging.ts

  • Implement postMessage / onMessage wiring per processor name.
  • Write worklet-messaging.test.ts, worklet-messaging.md.

8c. worklet-registry/worklet-registry.ts

  • Track loaded processors and their associated AudioWorkletNode factory.
  • Write worklet-registry.test.ts, worklet-registry.md.

9. Engine (src/engine/)

9a. engine-state/engine-state.ts

  • Implement state machine: uninitialized → starting → running → suspended → stopping → stopped → error. Validate transitions; throw AUDIO_ENGINE_STATE_INVALID on illegal transition.
  • Write engine-state.test.ts, engine-state.md.

9b. engine-metrics/engine-metrics.ts

  • Collect CPU load estimate via BaseAudioContext.baseLatency + analyzer node.
  • Wire OTel counters audio.plugin_loaded_total, audio.plugin_failed_total; histograms audio.engine_latency_ms.
  • Write engine-metrics.test.ts, engine-metrics.md.

9c. engine/engine.ts

  • Implement AudioEngine: constructor with injected BaseAudioContext, plugin map, load/unload with quarantine, start/stop lifecycle, offline render, expose AudioGraph, AudioQueueEngine, AudioWorkletManager as members.
  • Wire quarantine: catch plugin errors, mark ERROR, disconnect, emit plugin:error, continue.
  • Write engine.test.ts (no globalThis touch — use injected context), engine.md, engine.types.ts.

10. Integration tests (tests/integration.test.ts)

  • Full AudioEngine lifecycle: start → load plugin → active → unload → stop using standardized-audio-context.
  • Graph: connect/disconnect, snapshot/restore, traverse.
  • Queue: enqueue → play sequence → loop → stop.
  • Worklet: addModule with allow-list passes; rejected URL throws typed error.
  • Quarantine: a plugin that throws in initialize does not bring down the engine.
  • Offline render: renderOffline() returns non-empty AudioBuffer.

11. Benchmarks (src/__benchmarks__/)

  • graph.bench.ts: connect/disconnect 100 nodes, traverse 50-node graph.
  • queue.bench.ts: enqueue 1000 cues, dequeue all.
  • worklet.bench.ts: postMessage round-trip latency.

12. Docs

  • Write .md for every exported class/type (see layout in proposal.md).
  • Write browser/audio/audio-engine/README.md with purpose, install, quick-start, subpath table, benchmarks table, dependencies table.

13. Verify and publish

  • bunx turbo lint --filter=@suaveplan/audio-engine — zero errors.
  • bunx turbo typecheck --filter=@suaveplan/audio-engine — zero errors.
  • bunx turbo test --filter=@suaveplan/audio-engine — all tests pass.
  • bunx turbo test:coverage --filter=@suaveplan/audio-engine — 100% on all touched modules.
  • bun run docs:check --filter=@suaveplan/audio-engine — zero errors.
  • Confirm no TODO, FIXME, any, ts-ignore, .skip, vi.mock remain in src/.
  • "sideEffects": false set in package.json.
  • bun scripts/publish.ts --package @suaveplan/audio-engine.
  • Update CLAUDE.md package listing.
  • Archive: move to openspec/archive/2026-04-24-enterprise-browser-audio-engine/ and fold spec delta into openspec/specs/audio/spec.md.