# `runtime` — shared analyzer plumbing ## Purpose The runtime module is the shared spine for `SpectrumAnalyzer`, `Spectrogram`, and `MFCC`. It owns option parsing through the canonical Zod schema, abort-signal short-circuits, OTel span+counter+histogram instrumentation, and construction of the audio-core `AnalysisResult` envelope. Centralising this scaffolding means every analyzer stays focused on its DSP and the package as a whole emits identical telemetry shapes. ## Features - `parseOptions` — single boundary into `SpectrumAnalyzerOptionsSchema` that throws `AUDIO_ANALYSIS_SPECTRUM.INVALID_OPTIONS` with the Zod issues. - `ensureNotAborted` — throws `AUDIO_ANALYSIS_SPECTRUM.ABORTED` if a caller-supplied `AbortSignal` is already aborted. - `startRun` — opens a span, records sample-rate/duration attributes, and returns `end`/`fail` callbacks bound to the runs counter and duration histogram. - `recordBlock` — bumps the block-duration histogram for `analyzeBlock`. - `buildBase` — produces the `AnalysisResult` envelope (`analyserName`, `analyserVersion`, `sampleRate`, `durationSamples`, `computedAt`). ## Usage: Basic ```ts import { buildBase, ensureNotAborted, parseOptions, startRun, } from "@suaveplan/audio-analysis-spectrum/analyzer/runtime"; const opts = parseOptions(raw); ensureNotAborted(opts.signal); const handle = startRun("spectrum-analyzer", doc, "analyze"); try { // ... run the DSP ... handle.end(); } catch (err) { handle.fail(err); throw err; } ``` ## Usage: Advanced ```ts import { recordBlock } from "@suaveplan/audio-analysis-spectrum/analyzer/runtime"; const startedAt = performance.now(); const result = computeBlock(); recordBlock("spectrum-analyzer", performance.now() - startedAt); ``` ## API Reference - `parseOptions(raw): SpectrumAnalyzerOptions` — schema-validated options. - `ensureNotAborted(signal): void` — throws `ABORTED` on pre-aborted signals. - `startRun(op, doc, mode): { end, fail }` — OTel run handle. - `recordBlock(op, durationMs): void` — record a single block timing. - `buildBase(op, doc): { analyserName, analyserVersion, sampleRate, durationSamples, computedAt }`. ## Implementation Notes Instrumentation uses `@opentelemetry/api` which short-circuits to a no-op when no SDK is registered, so importing this module mutates no global state and runs free in suites that don't configure a `MeterProvider`. Tags on the counter and histograms are intentionally minimal — `op` and `mode` — so cardinality stays bounded even with high analyzer fan-out.