Files
2026-05-27 23:29:53 +01:00

54 lines
3.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Add `@suaveplan/audio-ir-core`
**Package**: `@suaveplan/audio-ir-core`
**Status**: PROPOSED
**Type**: new-package
## Why
The IR ecosystem (`audio-ir-loader`, `audio-ir-{mic,speaker,room}-plugin-<name>` packages) needs a single foundation that owns the IR contract, manifest schema, and in-memory registry. Without it, every IR content package would reinvent the entry shape, the registry collision rule, and the ID-derivation convention — guaranteed drift. This package is the foundation every sibling depends on.
## What changes
- ADDED: `ImpulseResponse` type — `{ id: string; channelData: readonly Float32Array[]; channels: number; sampleRate: number; lengthFrames: number; durationSec: number; gainDb: number; family: "mic" | "speaker" | "room"; manifest: IrManifestEntry }`. Frozen, validated.
- ADDED: `IrManifestEntry` Zod schema — `{ id, family, uri, channels, sampleRate, gainDb, license, source }`. `id` matches `/^[a-z][a-z0-9-]*$/` (no consecutive `-`, starts with a letter, length 1–128). `uri` is any non-empty string (deferred validation to `storage-uri` at load time).
- ADDED: `IrManifest` Zod schema — `{ packageSlug: <slug grammar>, family: "mic" | "speaker" | "room", entries: readonly IrManifestEntry[] }`. Every `entry.id` SHALL begin with `<packageSlug>-` (enforced by schema refinement). `entry.family` SHALL equal manifest-level `family`.
- ADDED: `IrRegistry` — in-memory `Map`-backed registry with `register(entry)`, `has(id)`, `get(id)`, `list({ family? })`, `clear()`. `register` throws `AUDIO_IR.DUPLICATE_ID` when an ID is registered twice.
- ADDED: `createIrRegistry()` factory.
- ADDED: `AUDIO_IR.*` codes via `defineCodes`: `DUPLICATE_ID`, `NOT_REGISTERED`, `INVALID_MANIFEST`, `ID_PREFIX_MISMATCH`, `FAMILY_MISMATCH`.
- ADDED: OTel — `audio_ir.registry_size{family}` observable gauge; `audio_ir.registrations_total{family, outcome}` counter; `audio_ir.lookups_total{family, outcome}` counter; `audio_ir.errors_total{code}` counter.
## Out of scope
Nothing functional within the foundation's scope. The following are explicitly NOT here, because they belong to siblings:
- Loading + decoding — `audio-ir-loader` owns the resolver-driven walk.
- Concrete IR data — `audio-ir-{mic,speaker,room}-plugin-<name>` packages own the files and the per-package `register(registry, resolver)` call.
## Source mapping
Genesis-original. No upstream `enterprise/audio-ir-core.md` exists.
### Requirements with no source line
| Requirement | Justification |
|---|---|
| every spec requirement | Genesis-original foundation; no upstream baseline |
## Verification approach
- `src/types/manifest-entry.test.ts` — Zod parsing + refinement (id grammar, id-prefix rule, family rule).
- `src/types/manifest.test.ts` — manifest-level Zod validation.
- `src/registry/registry.test.ts` — register / has / get / list / clear semantics; `DUPLICATE_ID` throw.
- `src/registry/registry.spec-conformance.test.ts` — strict-mode behaviors, lookup invariants under concurrency.
- `src/otel/otel.test.ts` — counter + gauge assertions with real in-memory `MeterProvider`.
- `src/error-codes/error-codes.test.ts` — exhaustion.
## Impact
### Affected dependents
No dependents yet (the package is brand new). Verified by `bunx turbo ls --filter=...@suaveplan/audio-ir-core` returning only the package itself.
The first downstream consumers will be `@suaveplan/audio-ir-loader` and every `@suaveplan/audio-ir-{family}-plugin-<name>` package, each landing in its own change.