PR-3 of ADR-0181. Externalises the PR-2 in-code operator registry to a
versioned, checksum-locked pack and wires the sensorium adapter. Mounts
gate-closed until the PR-4 eval gates pass. No core mutation (ADR-0013).
Pack (packs/audio/audio_core_v1/):
- manifest.json canonical params, resampling config, gating defaults, ordering
- operators.jsonl the 8 elliptic operators (byte-equivalent to DEFAULT_OPERATOR_REGISTRY)
- basis_map.json alias→index over the six elliptic planes {6,7,8,10,11,13}
- resample_fir_v1.npy pinned odd-length symmetric windowed-sinc low-pass (unit DC)
- checksums.json sha256 of every artifact
Loader (packs/audio/loader.py) — trust boundary (ADR-0051 / CLAUDE.md §Security):
- _validate_pack_id rejects traversal/separators/dotfiles before any path join
- fail-closed checksum verification: every file re-hashed vs checksums.json
- resolved path must stay under the packs root (defense in depth)
- JSON format (matches every other CORE pack loader; spec §6.1 TOML was
illustrative; no tomllib dependency added)
Adapter (sensorium/adapters/audio.py):
- AudioProjectionHead wraps AudioCompiler; project(AudioSignal)->(32,) f32
- make_audio_pack loads+verifies the pack, builds a gate-closed ModalityPack
Tests (19): PR-2↔PR-3 registry byte-parity via manifest_sha256, elliptic-only
operators, FIR integrity, fail-closed checksum mismatch, path-traversal guard,
gate-closed refusal, mount-time unitarity (+ bad-unitarity blocks mount),
gate-engage requires checksum_verified, engaged pack projects (32,) f32.
All audio 32 + arch-invariants 40 + smoke 67 green.
101 lines
3.5 KiB
Python
101 lines
3.5 KiB
Python
"""
|
|
sensorium/adapters/audio.py — Audio modality adapter (ADR-0181 PR-3).
|
|
|
|
The thin, pack-governed ProjectionHead for audio. It wraps the deterministic
|
|
AudioCompiler (PR-2): a canonical AudioSignal is compiled to one
|
|
AudioCompilationUnit and the unit's (32,) float32 versor crosses the
|
|
Logos-recovery boundary.
|
|
|
|
The pack mounts **gate-closed** (``gate_engaged=False``) until the eval gates
|
|
(PR-4) pass — `ModalityRegistry.project` refuses a closed gate, so audio
|
|
contributes no field state until determinism/checksum/versor gates are green
|
|
(ADR-0181 §2.5). Adding audio touches no existing layer (ADR-0013).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
|
|
import numpy as np
|
|
|
|
from sensorium.audio.canonical import CANONICAL_SAMPLE_RATE, canonicalize
|
|
from sensorium.audio.compiler import AudioCompiler
|
|
from sensorium.audio.types import AudioSignal
|
|
from sensorium.protocol import (
|
|
CL41_DIM,
|
|
Modality,
|
|
ModalityPack,
|
|
ModalityVocabulary,
|
|
)
|
|
|
|
|
|
@dataclass(frozen=True, slots=True)
|
|
class AudioProjectionHead:
|
|
"""D1 projection head for audio.
|
|
|
|
Determinism class: D1 — deterministic given a pinned pack (operator
|
|
registry + basis). ``project`` accepts an already-canonical AudioSignal;
|
|
raw waveform is canonicalised upstream via ``canonicalize`` (a helper is
|
|
exposed as ``project_raw`` for convenience).
|
|
"""
|
|
|
|
compiler: AudioCompiler
|
|
modality: Modality = Modality.AUDIO
|
|
|
|
@property
|
|
def embedding_dim(self) -> int:
|
|
return CL41_DIM
|
|
|
|
def project(self, signal: AudioSignal) -> np.ndarray:
|
|
out = self.compiler.compile_signal(signal).versor
|
|
if out.shape != (CL41_DIM,):
|
|
raise ValueError(f"expected ({CL41_DIM},), got {out.shape}")
|
|
if out.dtype != np.float32:
|
|
raise TypeError(f"expected float32, got {out.dtype}")
|
|
return out
|
|
|
|
def project_batch(self, signals: list[AudioSignal]) -> np.ndarray:
|
|
return np.stack([self.project(s) for s in signals], axis=0)
|
|
|
|
def project_raw(
|
|
self, samples: np.ndarray, sample_rate: int, *, fir: np.ndarray | None = None
|
|
) -> np.ndarray:
|
|
"""Convenience: canonicalise raw samples then project."""
|
|
signal = canonicalize(samples, sample_rate, target_sr=CANONICAL_SAMPLE_RATE, fir=fir)
|
|
return self.project(signal)
|
|
|
|
def verify_unitarity(self, sample: AudioSignal) -> bool:
|
|
try:
|
|
return self.compiler.compile_signal(sample).versor_condition < 1e-6
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
def make_audio_pack(
|
|
pack_id: str = "audio_core_v1",
|
|
*,
|
|
gate_engaged: bool = False,
|
|
checksum_verified: bool = False,
|
|
packs_root=None,
|
|
) -> ModalityPack:
|
|
"""Construct a gate-closed audio ModalityPack from a verified pack.
|
|
|
|
Loads + checksum-verifies the pack (fail-closed), builds the compiler over
|
|
the pack's operator registry, and wraps it in an AudioProjectionHead. The
|
|
pack ships gate-closed; engaging the gate is the PR-4 eval-gate decision.
|
|
"""
|
|
from packs.audio.loader import load_audio_pack
|
|
|
|
loaded = load_audio_pack(pack_id, packs_root=packs_root)
|
|
compiler = AudioCompiler(loaded.registry, pack_id=loaded.pack_id)
|
|
head = AudioProjectionHead(compiler)
|
|
return ModalityPack(
|
|
pack_id=loaded.pack_id,
|
|
modality_type=Modality.AUDIO,
|
|
projection=head,
|
|
decoder=None,
|
|
vocabulary=ModalityVocabulary(),
|
|
grammar_scaffold=None,
|
|
checksum_verified=checksum_verified,
|
|
gate_engaged=gate_engaged,
|
|
)
|