216 lines
11 KiB
Markdown
216 lines
11 KiB
Markdown
# Tasks: enterprise-audio-codec-ffmpeg-native
|
|
|
|
Implementation checklist for `@suaveplan/audio-codec-ffmpeg-native`. Tasks are ordered;
|
|
each section must be complete before the next begins. Every `### Requirement` and
|
|
`#### Scenario` from `specs/audio-codec-ffmpeg-native/spec.md` is enumerated in §0c
|
|
working notes and checked off as implementation lands.
|
|
|
|
---
|
|
|
|
## 1. Scaffold
|
|
|
|
- [ ] Create `packages/media/audio/audio-codec-ffmpeg-native/` with `package.json`,
|
|
`tsconfig.json`, `vitest.config.ts` (use `createTestConfig()` from
|
|
`@suaveplan/testing/config`; `pool: 'forks'`).
|
|
- [ ] `package.json` declares `"engines": { "node": ">=20" }`, no `"browser"` field,
|
|
`"sideEffects": false`, `"type": "module"`, and `version: "0.1.0"`.
|
|
- [ ] `dependencies`: `@suaveplan/audio-codecs workspace:^`,
|
|
`@suaveplan/audio-core workspace:^`, `@suaveplan/streams workspace:^`,
|
|
`@suaveplan/error workspace:^`, `@suaveplan/types workspace:^`,
|
|
`fluent-ffmpeg catalog:audio`, `zod catalog:forms`,
|
|
`@opentelemetry/api catalog:observability`, `tslib catalog:build`.
|
|
- [ ] `optionalDependencies`: `@ffmpeg-installer/ffmpeg catalog:audio`.
|
|
- [ ] `devDependencies`: `@suaveplan/testing workspace:^`, `vitest catalog:testing`,
|
|
`@vitest/coverage-istanbul catalog:testing`, `fast-check catalog:testing`,
|
|
`mitata catalog:testing`, `@types/fluent-ffmpeg catalog:types`.
|
|
- [ ] If `fluent-ffmpeg`, `@ffmpeg-installer/ffmpeg`, or `@types/fluent-ffmpeg` are
|
|
not yet in the root `package.json` catalog block, add them under
|
|
`catalog.audio` / `catalog.types` and re-run `bun install`.
|
|
- [ ] Declare subpath `exports` for every feature module listed in `proposal.md`
|
|
"Module layout" plus the root barrel — every entry resolves to a typed
|
|
`import` condition under `dist/`.
|
|
- [ ] Add per-package `tsconfig.json` extending the shared preset.
|
|
|
|
## 2. Types + error codes
|
|
|
|
- [ ] `src/error-codes.ts` — `defineCodes` with the eight
|
|
`AUDIO_CODEC_FFMPEG_NATIVE.*` codes; export
|
|
`AudioCodecFfmpegNativeError extends SuaveplanError`,
|
|
`AUDIO_CODEC_FFMPEG_NATIVE_ERROR_METADATA`,
|
|
`registerAudioCodecFfmpegNativeErrorCodes()`.
|
|
- [ ] `src/error-codes.test.ts` — assert each code is thrown by at least one call
|
|
site (this test cross-references the per-feature tests once they exist).
|
|
- [ ] `src/error-codes.md` — Purpose / Features / Basic / Advanced / API / Notes.
|
|
- [ ] `src/constants/index.ts` — supported format lists, MIME types, default
|
|
timeouts, default concurrency.
|
|
|
|
## 3. Binary resolver
|
|
|
|
- [ ] `src/binary/binary.ts` — `resolveBinary(opts): Promise<string>` implementing
|
|
the 4-step discovery order; cache result on success.
|
|
- [ ] `src/binary/binary.types.ts` — `BinaryResolverOptions`,
|
|
`ResolvedBinary` shapes.
|
|
- [ ] `src/binary/binary.test.ts` — covers `binaryProvider` precedence, explicit
|
|
`binaryPath`, dynamic-import fallback, and `BINARY_MISSING` throw path.
|
|
- [ ] `src/binary/binary.md`.
|
|
- [ ] `src/binary/index.ts` — explicit named exports.
|
|
|
|
## 4. Semaphore
|
|
|
|
- [ ] `src/semaphore/semaphore.ts` — ~30-line FIFO semaphore with `acquire` /
|
|
`release`; no external dep.
|
|
- [ ] `src/semaphore/semaphore.types.ts`.
|
|
- [ ] `src/semaphore/semaphore.test.ts` — concurrency cap, FIFO ordering,
|
|
slot-release on error.
|
|
- [ ] `src/semaphore/semaphore.md`, `index.ts`.
|
|
|
|
## 5. Subprocess runner (the only place `node:child_process` / `fluent-ffmpeg` is imported)
|
|
|
|
- [ ] `src/runner/runner.ts` — `runDecode(opts)` and `runEncode(opts)`. Owns spawn,
|
|
stdin pipe, stdout drain (chunk-by-chunk, no full-output `Buffer.concat`),
|
|
stderr ring buffer, exit handling, timeout enforcement, semaphore release.
|
|
- [ ] `src/runner/runner.types.ts` — `RunDecodeOptions`, `RunEncodeOptions`,
|
|
`RunnerCallbacks`, `RunnerHandles`.
|
|
- [ ] `src/runner/runner.test.ts` — happy path, non-zero exit → `_DECODE_FAILED`
|
|
with stderr context, spawn failure → `_SPAWN_FAILED`, timeout →
|
|
`_TIMEOUT` with SIGTERM/SIGKILL escalation observed.
|
|
- [ ] `src/runner/runner.md`, `index.ts`.
|
|
|
|
## 6. Decode pipeline
|
|
|
|
- [ ] `src/decode/decode.ts` — `decodeOneShot(bytes, opts)` orchestrating
|
|
`runDecode` + per-channel `Float32Array` accumulators + interleave splitter.
|
|
- [ ] `src/decode/decode.types.ts`.
|
|
- [ ] `src/decode/decode.test.ts` — well-formed `DecodeResult`,
|
|
chunk-by-chunk assertion (instrument runner to count `Buffer.concat`),
|
|
`_DECODE_FAILED` with stderr in context, `canDecode` delegation.
|
|
- [ ] `src/decode/decode.md`, `index.ts`.
|
|
|
|
## 7. Encode pipeline
|
|
|
|
- [ ] `src/encode/encode.ts` — `encodeOneShot(pcm, opts)` with PCM-shape validation,
|
|
interleaver writing into a 64 KiB working buffer, runner invocation.
|
|
- [ ] `src/encode/encode.types.ts`.
|
|
- [ ] `src/encode/encode.test.ts` — round-trip through decode, `_INVALID_PCM` for
|
|
ragged channels, `_UNSUPPORTED_CODEC` for unknown format and for WMA encode.
|
|
- [ ] `src/encode/encode.md`, `index.ts`.
|
|
|
|
## 8. Streaming adapters
|
|
|
|
- [ ] `src/stream/stream-decoder.ts` — `createDecoder(opts)` returning
|
|
`StreamingDecoder`; `createDecodeTransform(opts)` returning a
|
|
`@suaveplan/streams` `TransformStream<Uint8Array, AudioPage>`.
|
|
- [ ] `src/stream/stream-encoder.ts` — `createEncoder(opts)` returning
|
|
`StreamingEncoder`; `createEncodeTransform(opts)` returning a
|
|
`TransformStream<Float32Array[], Uint8Array>`.
|
|
- [ ] Sibling `.types.ts`, `.test.ts`, `.md` for each; tests cover chunked-write
|
|
equivalence, TransformStream composition, encoder yielding before flush.
|
|
- [ ] `src/stream/index.ts` — explicit named exports.
|
|
|
|
## 9. AbortSignal wiring
|
|
|
|
- [ ] `src/abort/abort.ts` — `attachAbort(child, signal, semaphoreRelease)`:
|
|
sends `SIGTERM`, starts 1 s timer, escalates to `SIGKILL`, releases slot,
|
|
rejects with `_ABORTED`. Short-circuit path for pre-aborted signals.
|
|
- [ ] `src/abort/abort.types.ts`.
|
|
- [ ] `src/abort/abort.test.ts` — pre-aborted short-circuit (no spawn observed),
|
|
mid-decode SIGTERM → SIGKILL escalation under a child that ignores SIGTERM.
|
|
- [ ] `src/abort/abort.md`, `index.ts`.
|
|
|
|
## 10. OpenTelemetry instrumentation
|
|
|
|
- [ ] `src/otel/otel.ts` — span / counter / histogram / inflight-gauge helpers;
|
|
inert without exporter; no import-time side effects.
|
|
- [ ] `src/otel/otel.types.ts`, `otel.test.ts` (in-memory `MeterProvider` +
|
|
`TracerProvider`), `otel.md`, `index.ts`.
|
|
|
|
## 11. Codec class + register helper
|
|
|
|
- [ ] `src/codec/codec.ts` — `FfmpegNativeCodec` implementing `AudioCodec`. Owns
|
|
the per-instance semaphore, the cached binary path, the OTel handles, and
|
|
delegates to `decode/`, `encode/`, `stream/` modules.
|
|
- [ ] `src/codec/codec.schemas.ts` — `FfmpegNativeCodecOptionsSchema`,
|
|
`EncodeOptsSchema` (Zod).
|
|
- [ ] `src/codec/codec.types.ts`, `codec.test.ts` (constructor Zod validation,
|
|
`canDecode` rejection without spawn, WMA encode short-circuit, full
|
|
`DecodeResult` shape), `codec.md`, `index.ts`.
|
|
- [ ] `src/register/register.ts` — `register(registry, options?)` idempotent
|
|
installer.
|
|
- [ ] `src/register/register.test.ts`, `register.types.ts`, `register.md`,
|
|
`index.ts`.
|
|
|
|
## 12. Root barrel
|
|
|
|
- [ ] `src/index.ts` — explicit named re-exports of every public symbol from each
|
|
feature module. No `export *` (rule 10 / §6a).
|
|
|
|
## 13. Tests — purity, integration, exports
|
|
|
|
- [ ] `tests/purity.test.ts` — built dist has no browser globals; `child_process`
|
|
imported only from `src/runner/runner.ts`; package import mutates no global
|
|
OTel state.
|
|
- [ ] `tests/integration.test.ts` — full round-trip across every declared
|
|
encodable format using the bundled `@ffmpeg-installer/ffmpeg` binary.
|
|
- [ ] `tests/exports.test.ts` — every feature module has a working subpath export
|
|
entry and is independently importable.
|
|
- [ ] Every test file imports runner primitives from
|
|
`@suaveplan/testing/runner` (rule 11 / §7).
|
|
|
|
## 14. Benchmarks
|
|
|
|
- [ ] `src/__benchmarks__/codec.bench.ts` — mitata suite: decode 10 s WAV,
|
|
decode 10 s MP3, encode 10 s WAV→MP3, concurrent-decode at `concurrencyLimit`
|
|
= 4. Use `--cpu-prof-md` / `--heap-prof-md` for LLM-assisted analysis.
|
|
- [ ] Publish baseline numbers in `README.md`.
|
|
|
|
## 15. Documentation
|
|
|
|
- [ ] Every `.ts` (excluding `.test.ts`, `.types.ts`, `.schemas.ts`, barrel
|
|
`index.ts`) has a sibling `.md` meeting §4: ≥200 words, Purpose / Features
|
|
/ Basic / Advanced / API Reference / Implementation Notes.
|
|
- [ ] `README.md` at package root: name, one-paragraph description, install,
|
|
quick-start, Modules section linking every `src/<feature>/<feature>.md`,
|
|
format support matrix from `design.md`, baseline benchmark numbers.
|
|
|
|
## 16. Pre-publish gates (§13)
|
|
|
|
- [ ] Step 0 — Spec reconciliation: walk every requirement and `Verified by` from
|
|
the spec delta; confirm every symbol, span, counter, error code, and test
|
|
name exists verbatim in `src/`. STOP if any item is unmatched.
|
|
- [ ] `bunx turbo lint typecheck test --filter=@suaveplan/audio-codec-ffmpeg-native`.
|
|
- [ ] `bun run check` (biome).
|
|
- [ ] `bunx turbo test:coverage --filter=@suaveplan/audio-codec-ffmpeg-native`
|
|
reports 100 / 100 / 100 / 100 (istanbul).
|
|
- [ ] `bunx turbo build --filter=@suaveplan/audio-codec-ffmpeg-native`.
|
|
- [ ] Banned-pattern scan: zero hits for `@deprecated`, `TODO`, `FIXME`,
|
|
`ts-ignore`, `ts-expect-error`, `.skip`, `.only`, bare `any`, `console.log`.
|
|
- [ ] Barrel scan (§13 step 4a): zero `export *` in feature barrels.
|
|
- [ ] Test-runner import scan (§13 step 4b): zero direct
|
|
`from "vitest"` / `from "bun:test"` imports.
|
|
- [ ] Missing-`.md` scan returns zero output.
|
|
- [ ] `README.md` present.
|
|
- [ ] Bare-version scan returns zero output.
|
|
- [ ] Subpath-export count matches feature-module count.
|
|
- [ ] Security scan for hardcoded secrets returns zero output.
|
|
- [ ] (Not a foundation package — dependent sweep optional; run it anyway since
|
|
this is a fresh public surface.)
|
|
|
|
## 17. Root-doc refresh + markdownlint (§13b)
|
|
|
|
- [ ] `bun scripts/folder-reorg/generate-manifest.ts` → refresh `MANIFEST.md`.
|
|
- [ ] `bun scripts/generate-missing.ts` → refresh `MISSING.yml`.
|
|
- [ ] Move the package row from Pending → Completed in `STATUS.md`.
|
|
- [ ] Add the per-package paragraph in `SUMMARY.md`.
|
|
- [ ] `bunx markdownlint-cli2 --fix`; resolve any remaining violations by hand.
|
|
|
|
## 18. Fold spec into canonical location
|
|
|
|
- [ ] Fold
|
|
`openspec/changes/enterprise-audio-codec-ffmpeg-native/specs/audio-codec-ffmpeg-native/spec.md`
|
|
into `openspec/specs/audio-codec-ffmpeg-native/spec.md` per §14.
|
|
|
|
## 19. Archive
|
|
|
|
- [ ] Move `openspec/changes/enterprise-audio-codec-ffmpeg-native/` to
|
|
`openspec/archive/2026-05-15-enterprise-audio-codec-ffmpeg-native/`.
|