This project now includes structured server-side telemetry for the audio/DSP pipeline.
GET /api/debug/telemetry/live
GET /api/debug/telemetry/history
since, until: unix seconds/ms or RFC3339limitname, prefixsignal_id, session_id, stage, trace_id, componenttag_<key>=<value> for arbitrary tag filtersinclude_persisted=true|falseGET /api/debug/telemetry/events
level.GET /api/debug/telemetry/config
POST /api/debug/telemetry/config
debug.telemetry in config:
enabledheavy_enabledheavy_sample_everymetric_sample_everymetric_history_maxevent_history_maxretention_secondspersist_enabledpersist_dirrotate_mbkeep_filesPersisted JSONL files rotate in persist_dir (default: debug/telemetry).
enabled=true, heavy_enabled=false, persist_enabled=true.GET /api/debug/telemetry/liveGET /api/debug/telemetry/events?since=<start>&level=warnGET /api/debug/telemetry/history?since=<start>&prefix=stage.GET /api/debug/telemetry/history?since=<start>&prefix=streamer.heavy_enabled=true (keep sampling coarse with heavy_sample_every > 1), rerun, then inspect iq.* metrics and audio.* anomalies by signal_id/session_id.Status: SOLVED
The March 2026 live-audio click investigation ultimately converged on a combination of three real root causes plus two secondary fixes:
Shared allIQ corruption by IQBalance aliasing
cmd/sdrd/pipeline_runtime.gosurvIQ aliased the tail of allIQdsp.IQBalance(survIQ) modified allIQ in-placesurvIQ before IQBalancePer-frame extractor reset due to StreamingConfigHash jitter
internal/demod/gpudemod/streaming_types.goStreaming path batch rejection for non-WFM exact-decimation mismatch
cmd/sdrd/streaming_refactor.gointernal/recorder/streamer.gointernal/recorder/streamer.goIQBalance aliasing fix in pipeline_runtime.goWhen the same captured allIQ buffer feeds both:
then surveillance-side DSP helpers must not mutate a shared sub-slice in-place unless that mutation is intentionally part of the extraction contract.