# 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`.