11 KiB
11 KiB
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/withpackage.json,tsconfig.json,vitest.config.ts(usecreateTestConfig()from@suaveplan/testing/config;pool: 'forks'). package.jsondeclares"engines": { "node": ">=20" }, no"browser"field,"sideEffects": false,"type": "module", andversion: "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-ffmpegare not yet in the rootpackage.jsoncatalog block, add them undercatalog.audio/catalog.typesand re-runbun install. - Declare subpath
exportsfor every feature module listed inproposal.md"Module layout" plus the root barrel — every entry resolves to a typedimportcondition underdist/. - Add per-package
tsconfig.jsonextending the shared preset.
2. Types + error codes
src/error-codes.ts—defineCodeswith the eightAUDIO_CODEC_FFMPEG_NATIVE.*codes; exportAudioCodecFfmpegNativeError 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,ResolvedBinaryshapes.src/binary/binary.test.ts— coversbinaryProviderprecedence, explicitbinaryPath, dynamic-import fallback, andBINARY_MISSINGthrow path.src/binary/binary.md.src/binary/index.ts— explicit named exports.
4. Semaphore
src/semaphore/semaphore.ts— ~30-line FIFO semaphore withacquire/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)andrunEncode(opts). Owns spawn, stdin pipe, stdout drain (chunk-by-chunk, no full-outputBuffer.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_FAILEDwith stderr context, spawn failure →_SPAWN_FAILED, timeout →_TIMEOUTwith SIGTERM/SIGKILL escalation observed.src/runner/runner.md,index.ts.
6. Decode pipeline
src/decode/decode.ts—decodeOneShot(bytes, opts)orchestratingrunDecode+ per-channelFloat32Arrayaccumulators + interleave splitter.src/decode/decode.types.ts.src/decode/decode.test.ts— well-formedDecodeResult, chunk-by-chunk assertion (instrument runner to countBuffer.concat),_DECODE_FAILEDwith stderr in context,canDecodedelegation.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_PCMfor ragged channels,_UNSUPPORTED_CODECfor unknown format and for WMA encode.src/encode/encode.md,index.ts.
8. Streaming adapters
src/stream/stream-decoder.ts—createDecoder(opts)returningStreamingDecoder;createDecodeTransform(opts)returning a@suaveplan/streamsTransformStream<Uint8Array, AudioPage>.src/stream/stream-encoder.ts—createEncoder(opts)returningStreamingEncoder;createEncodeTransform(opts)returning aTransformStream<Float32Array[], Uint8Array>.- Sibling
.types.ts,.test.ts,.mdfor 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): sendsSIGTERM, starts 1 s timer, escalates toSIGKILL, 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-memoryMeterProvider+TracerProvider),otel.md,index.ts.
11. Codec class + register helper
src/codec/codec.ts—FfmpegNativeCodecimplementingAudioCodec. Owns the per-instance semaphore, the cached binary path, the OTel handles, and delegates todecode/,encode/,stream/modules.src/codec/codec.schemas.ts—FfmpegNativeCodecOptionsSchema,EncodeOptsSchema(Zod).src/codec/codec.types.ts,codec.test.ts(constructor Zod validation,canDecoderejection without spawn, WMA encode short-circuit, fullDecodeResultshape),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. Noexport *(rule 10 / §6a).
13. Tests — purity, integration, exports
tests/purity.test.ts— built dist has no browser globals;child_processimported only fromsrc/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/ffmpegbinary.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 atconcurrencyLimit= 4. Use--cpu-prof-md/--heap-prof-mdfor LLM-assisted analysis.- Publish baseline numbers in
README.md.
15. Documentation
- Every
.ts(excluding.test.ts,.types.ts,.schemas.ts, barrelindex.ts) has a sibling.mdmeeting §4: ≥200 words, Purpose / Features / Basic / Advanced / API Reference / Implementation Notes. README.mdat package root: name, one-paragraph description, install, quick-start, Modules section linking everysrc/<feature>/<feature>.md, format support matrix fromdesign.md, baseline benchmark numbers.
16. Pre-publish gates (§13)
- Step 0 — Spec reconciliation: walk every requirement and
Verified byfrom the spec delta; confirm every symbol, span, counter, error code, and test name exists verbatim insrc/. 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-nativereports 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, bareany,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-
.mdscan returns zero output. README.mdpresent.- 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→ refreshMANIFEST.md.bun scripts/generate-missing.ts→ refreshMISSING.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.mdintoopenspec/specs/audio-codec-ffmpeg-native/spec.mdper §14.
19. Archive
- Move
openspec/changes/enterprise-audio-codec-ffmpeg-native/toopenspec/archive/2026-05-15-enterprise-audio-codec-ffmpeg-native/.