# Tasks: enterprise-audio-sprite-packer **Change ID**: enterprise-audio-sprite-packer **Package**: `@suaveplan/audio-sprite-packer` **Target path**: `universal/compression/audio-sprite-packer` **Prerequisite packages on Verdaccio**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/mime`, `@suaveplan/crypto-utils` --- ## 1. Scaffold - [ ] Create directory `universal/compression/audio-sprite-packer/` 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/error workspace:^`, `@suaveplan/types workspace:^`, `@suaveplan/mime workspace:^`, `@suaveplan/crypto-utils workspace:^`, `zod catalog:forms`, `@opentelemetry/api catalog:observability`. - [ ] 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/types/common.ts` — `AudioFormat`, `AudioClipInput`, `AudioSpriteEntry`, `AudioSpriteManifest`, `AudioSprite`, `PackOptions`, `AudioAdapter`, `AudioSpritePackerOptions`. - [ ] Write `src/types/common.md`. - [ ] Write `src/error-codes.ts` — `AudioSpriteErrorCode`, `AUDIO_SPRITE_ERROR_METADATA`, `registerAudioSpriteErrorCodes()`. - [ ] Write Zod schemas: `AudioSpriteEntrySchema`, `AudioSpriteManifestSchema`, `PackOptionsSchema`, `AudioSpritePackerOptionsSchema`. --- ## 3. NullAudioAdapter - [ ] Implement `NullAudioAdapter` — `probe` returns configurable fixture metadata (WAV, 44100 Hz, 2ch, 1.0 s), `decode` returns 44100 × 2 float32 zeros, `encode` returns input bytes, `stripSilence` returns input unchanged, `normalise` returns input unchanged. - [ ] Write `null-adapter.test.ts` and `null-adapter.md`. --- ## 4. Manifest utilities - [ ] Implement `buildManifest(entries, packedBuffer): AudioSpriteManifest` — assembles manifest including SHA-256 content hash via `@suaveplan/crypto-utils`. - [ ] Implement `validateManifest(manifest): void` — checks version, entries array non-empty, offsets non-overlapping. - [ ] Write `manifest.test.ts` and `manifest.md`. --- ## 5. AudioSpritePacker - [ ] Implement `AudioSpritePacker.pack(clips, options, signal)`: 1. Validate clips non-empty. 2. For each clip: detect format (`@suaveplan/mime`), probe, decode PCM. 3. If `stripSilence`, call `adapter.stripSilence`. 4. If `normalise`, call `adapter.normalise`. 5. Append silence padding (zero-fill float32 × sampleRate × silencePaddingMs / 1000). 6. Encode all clips concatenated as single output buffer. 7. Build manifest with byte offsets per clip. 8. Return `{ data, manifest }`. - [ ] Implement `AudioSpritePacker.unpack(sprite, clipName)` — slice-and-return using manifest offsets. - [ ] Wire `AbortSignal` propagation; throw on abort. - [ ] Wire OTel: span `audio-sprite.pack`, counter, histogram, compression ratio. - [ ] Write `audio-sprite-packer.test.ts` (≤500 lines): pack 3 clips, unpack each, abort, empty clips throws. - [ ] Write `audio-sprite-packer.md`. --- ## 6. Benchmarks - [ ] Write `src/__benchmarks__/audio-sprite-packer.bench.ts` — pack 10 clips, pack 50 clips (null adapter). --- ## 7. Tests - [ ] Write `tests/integration.test.ts` — full pack/unpack round-trip. - [ ] Write `tests/property.test.ts` (fast-check) — manifest entry count = clip count, unpack returns correct slice, silence padding duration. --- ## 8. 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-sprite-packer` — green. - [ ] `bunx turbo test:coverage --filter=@suaveplan/audio-sprite-packer` — 100%. - [ ] `bun scripts/publish.ts --package @suaveplan/audio-sprite-packer`. - [ ] Archive to `openspec/archive/2026-04-24-enterprise-audio-sprite-packer/`.