Initial Commit
This commit is contained in:
153
openspec/changes/enterprise-audio-codecs/tasks.md
Normal file
153
openspec/changes/enterprise-audio-codecs/tasks.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# Tasks: enterprise-audio-codecs
|
||||
|
||||
**Change ID**: enterprise-audio-codecs
|
||||
**Package**: `@suaveplan/audio-codecs`
|
||||
**Target path**: `packages/media/audio/audio-codecs/`
|
||||
**Prerequisite packages on Verdaccio**: `@suaveplan/audio-core`, `@suaveplan/audio-metadata`, `@suaveplan/streams`, `@suaveplan/error`, `@suaveplan/types`
|
||||
|
||||
---
|
||||
|
||||
## 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. Scaffold
|
||||
|
||||
- [ ] Create directory `packages/media/audio/audio-codecs/` with `src/`, `tests/`, `src/__benchmarks__/`, and all feature subdirectories per the layout in `proposal.md`.
|
||||
- [ ] Write `package.json` at version `0.1.0` with `"type": "module"`, `"sideEffects": false`, full `exports` map, deps: `@suaveplan/audio-core workspace:^`, `@suaveplan/audio-metadata workspace:^`, `@suaveplan/streams workspace:^`, `@suaveplan/error workspace:^`, `@suaveplan/types workspace:^`, `zod catalog:forms`, `@opentelemetry/api catalog:observability`.
|
||||
- [ ] Declare optional peer deps / `optionalDependencies` for WASM codec packages (`@audio/decode-mp3`, `@audio/decode-flac`, etc.).
|
||||
- [ ] Write `tsconfig.json` extending `@suaveplan/typescript-config/library.json`.
|
||||
- [ ] Write `vitest.config.ts` using `createTestConfig()` from `@suaveplan/testing/config`.
|
||||
- [ ] Add `lint`, `typecheck`, `test`, `test:coverage`, `build`, `docs:check` scripts.
|
||||
|
||||
---
|
||||
|
||||
## 2. Types + errors
|
||||
|
||||
- [ ] Write `src/registry/registry.types.ts` — `AudioCodec`, `DecodeResult`, `StreamingDecoder`, `StreamingEncoder`, `CodecRegistryOptions`.
|
||||
- [ ] Write `src/registry/registry.md`.
|
||||
- [ ] Write `src/decode/decode-source.types.ts` — `Source`, `DecodeSourceOpts`, `DecodeOpts`.
|
||||
- [ ] Write `src/decode/decode-source.md`.
|
||||
- [ ] Write `src/encode/encode-to.types.ts` — `Destination`, `EncodeOpts`.
|
||||
- [ ] Write `src/encode/encode-to.md`.
|
||||
- [ ] Write `src/stream/stream-decoder.types.ts` — streaming decoder config types.
|
||||
- [ ] Write `src/stream/stream-decoder.md`.
|
||||
- [ ] Write `src/stream/stream-encoder.types.ts` — streaming encoder config types.
|
||||
- [ ] Write `src/stream/stream-encoder.md`.
|
||||
- [ ] Write `src/error-codes.ts` — `AudioCodecErrorCode`, `AUDIO_CODEC_ERROR_METADATA`, `registerAudioCodecErrorCodes()`.
|
||||
- [ ] Write Zod schemas for every public options object (`DecodeOptsSchema`, `EncodeOptsSchema`, `DecodeSourceOptsSchema`, `AudioCodecSchema`, `StreamingDecoderSchema`, `StreamingEncoderSchema`).
|
||||
|
||||
---
|
||||
|
||||
## 3. Format detection
|
||||
|
||||
- [ ] Implement `detectSource(source)` — read first `HEADER_SIZE` (256KB) bytes, resolve string sources to `fetch()` or `fs/promises.readFile()` based on runtime, return format + bytes/reader.
|
||||
- [ ] Integrate `@suaveplan/audio-metadata` magic-byte detection.
|
||||
- [ ] Write `src/detect/detect-format.test.ts`.
|
||||
- [ ] Write `src/detect/detect-format.md`.
|
||||
|
||||
---
|
||||
|
||||
## 4. CodecRegistry
|
||||
|
||||
- [ ] Implement `CodecRegistry.register()` / `unregister()` / `detect()`.
|
||||
- [ ] Implement `CodecRegistry.decode(source, opts)` — dispatch to codec, return `AudioDocument`.
|
||||
- [ ] Implement `CodecRegistry.encode(doc, format, opts)` — dispatch to codec, return `Uint8Array`.
|
||||
- [ ] Implement `CodecRegistry.decodeStream()` — `ReadableStream<Uint8Array>` → `ReadableStream<AudioPage>` via `StreamingDecoder`.
|
||||
- [ ] Implement `CodecRegistry.encodeStream()` — `AudioDocument` → `ReadableStream<Uint8Array>` via `StreamingEncoder`.
|
||||
- [ ] Wire OTel span on `codec.decode` / `codec.encode` + counters + histograms.
|
||||
- [ ] Write `src/registry/registry.test.ts`.
|
||||
- [ ] Write `src/registry/registry.md`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Built-in codecs (native)
|
||||
|
||||
- [ ] Implement `WavCodec` — native WAV decode/encode with streaming support, no external deps.
|
||||
- [ ] Write `src/codecs/wav.test.ts` — round-trip, header validation, streaming chunks.
|
||||
- [ ] Write `src/codecs/wav.md`.
|
||||
- [ ] Implement `AiffCodec` — native AIFF decode (no encode), no external deps.
|
||||
- [ ] Implement `CafCodec` — native CAF decode (no encode), no external deps.
|
||||
|
||||
---
|
||||
|
||||
## 6. Built-in codecs (WASM wrappers)
|
||||
|
||||
- [ ] Implement `Mp3Codec` — dynamic `import('@audio/decode-mp3')` wrapper, decode + encode + streaming.
|
||||
- [ ] Write `src/codecs/mp3.test.ts` using deterministic fixtures (no network mocks).
|
||||
- [ ] Write `src/codecs/mp3.md`.
|
||||
- [ ] Implement `FlacCodec` — dynamic `import('@audio/decode-flac')` wrapper, decode + encode + streaming.
|
||||
- [ ] Write `src/codecs/flac.test.ts`.
|
||||
- [ ] Write `src/codecs/flac.md`.
|
||||
- [ ] Implement `OggVorbisCodec`, `OpusCodec`, `AacCodec`, `WebMCodec`, `QoaCodec` — decode wrappers with dynamic imports, optional streaming where supported.
|
||||
|
||||
---
|
||||
|
||||
## 7. Universal decode entry point
|
||||
|
||||
- [ ] Implement `decodeSource(source, opts)` — resolve source, detect format, dispatch to `CodecRegistry.decode`, support `notify` / `ondata` callbacks, page pre-allocation, memory budget.
|
||||
- [ ] Implement source resolution rules: `http/https/data/blob` → `fetch()`; `file:` → `fs/promises.readFile()`; other string → runtime-determined.
|
||||
- [ ] Write `src/decode/decode-source.test.ts`.
|
||||
- [ ] Write `src/decode/decode-source.md`.
|
||||
|
||||
---
|
||||
|
||||
## 8. Universal encode entry point
|
||||
|
||||
- [ ] Implement `encodeTo(doc, destination, format, opts)` — encode then write to file path, `WritableStream`, or callback.
|
||||
- [ ] Write `src/encode/encode-to.test.ts`.
|
||||
- [ ] Write `src/encode/encode-to.md`.
|
||||
|
||||
---
|
||||
|
||||
## 9. Progressive streaming decode
|
||||
|
||||
- [ ] Implement `progressiveDecode()` — fill `AudioDocument.pages` as chunks arrive via `StreamingDecoder` or fallback full-decode.
|
||||
- [ ] Implement `pageAccumulator()` — push decoded PCM into pages, call `notify` on first page, call `ondata` per block.
|
||||
- [ ] Return usable `AudioDocument` immediately (before decode completes) with edits extending as pages arrive.
|
||||
- [ ] Write `src/stream/stream-decoder.test.ts`.
|
||||
- [ ] Write `src/stream/stream-decoder.md`.
|
||||
|
||||
---
|
||||
|
||||
## 10. Stream encoder
|
||||
|
||||
- [ ] Implement `createEncodeTransform()` — `TransformStream<Float32Array[], Uint8Array>` using `StreamingEncoder`.
|
||||
- [ ] Write `src/stream/stream-encoder.test.ts`.
|
||||
- [ ] Write `src/stream/stream-encoder.md`.
|
||||
|
||||
---
|
||||
|
||||
## 11. Memory budget
|
||||
|
||||
- [ ] Implement memory budget enforcement in `decodeSource` and `progressiveDecode` — project bytes from `sampleRate × channels × duration × 4` and throw `AudioCodecError(AUDIO_CODECS.BUDGET_EXCEEDED)` if over `budget`.
|
||||
- [ ] Write budget tests in `decode-source.test.ts`.
|
||||
|
||||
---
|
||||
|
||||
## 12. Benchmarks
|
||||
|
||||
- [ ] Write `src/__benchmarks__/decode.bench.ts` — decode 5-minute stereo WAV (native) and MP3 (WASM).
|
||||
- [ ] Write `src/__benchmarks__/encode.bench.ts` — encode 5-minute stereo WAV and FLAC.
|
||||
- [ ] Write `src/__benchmarks__/stream-decode.bench.ts` — progressive stream decode 5-minute MP3.
|
||||
|
||||
---
|
||||
|
||||
## 13. Integration + property tests
|
||||
|
||||
- [ ] Write `tests/integration.test.ts` — full round-trip: `decodeSource` → run edits → `encodeTo` → file written.
|
||||
- [ ] Write `tests/property.test.ts` (fast-check) — decode-then-encode round-trip for WAV/FLAC yields identical PCM; `detect` returns correct format for known magic bytes; streaming decode total samples equals non-streaming decode total samples.
|
||||
|
||||
---
|
||||
|
||||
## 14. Docs + verify + publish
|
||||
|
||||
- [ ] All co-located `.md` files (≥200 words each).
|
||||
- [ ] Write `README.md` at package root.
|
||||
- [ ] `bunx turbo lint typecheck test --filter=@suaveplan/audio-codecs` — green.
|
||||
- [ ] `bunx turbo test:coverage --filter=@suaveplan/audio-codecs` — 100%.
|
||||
- [ ] `bun scripts/publish.ts --package @suaveplan/audio-codecs`.
|
||||
- [ ] Fold `specs/audio-codecs/spec.md` into `openspec/specs/audio-codecs/spec.md`.
|
||||
- [ ] Archive change folder to `openspec/archive/2026-05-14-enterprise-audio-codecs/`.
|
||||
Reference in New Issue
Block a user