Skip to content

Core hardening from the package audit: pull-block feasibility, real validation, resync clamp, C-ABI (PR A)#25

Merged
tap merged 1 commit into
mainfrom
claude/core-hardening
Jun 12, 2026
Merged

Core hardening from the package audit: pull-block feasibility, real validation, resync clamp, C-ABI (PR A)#25
tap merged 1 commit into
mainfrom
claude/core-hardening

Conversation

@tap

@tap tap commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Audit fix series, part A — the product-correctness findings. (Part B, CI/infra hardening, lands separately; part C, the docs truth sweep, follows both.)

F1 (High): the pull-block feasibility bug — fixed with an adaptive setpoint

A pull must synthesize from frames already buffered, so any pull block larger than the occupancy setpoint made the configuration infeasible: with defaults, 64-frame callbacks dropped out every ~0.24 s forever (never Locked, ppm pegged at a false +1500); 240-frame callbacks emitted 80% silence. Now:

  • pull() raises the effective setpoint to the largest observed block + ~half-block sawtooth margin, bounded by FIFO capacity; the servo slews there glitch-free (integrator kept, occupancy only grows).
  • Auto-sized FIFOs get a 1024-frame floor (21 ms @ 48 kHz), so callbacks up to ~340 frames work with zero configuration; larger ones need explicit fifoFrames (documented).
  • Status::effectiveTargetLatencyFrames reports the setpoint in force; designedLatencySeconds() follows it. README latency section states the constraint plainly.
  • Configs that were already feasible are untouched: 32-frame transfer against the 48-frame default keeps its exact setpoint, and all 21 icount scenarios across M33/M55/Hexagon measure within ±0.07% (ring-construction noise; hot loops byte-identical).
  • Regression suite: Feasibility.Pull{64,128,240}LocksCleanly — the audit's exact failing scenarios, now asserting Locked / zero underruns / correct mean ppm / reported raise — plus a control that small pulls keep the configured setpoint.

F2: validated() actually validates

Rejects NaN/Inf anywhere in Config (a NaN sample rate previously constructed an all-NaN-emitting converter), band-edge sums above the rate (anti-image cutoff past input Nyquist passed images wholesale), maxDeviationPpm beyond the Q0.64 int64 conversion range (UB before), and size products that wrap 32-bit size_t. Boundary-tested: Config::forSampleRate(16k/44.1k) sit exactly on the band-edge-sum equality and must keep constructing.

F3: resync over-discard

The hard-resync discard now clamps to ring contents; with a setpoint below the 16-frame staged scratch it used to drain the ring entirely and cascade straight back into Filling.

C ABI

Null-handle guards on every entry point (the "check create for NULL" convention previously crashed exactly the caller who forgot), a shipped srt_capi.h carrying the thread contract, and srt_version().

Sweeps + tests

Comment-arithmetic corrections (Q15 blend margin is 0.005%, not ~5%; Config's "~1 ms" was 1.5 ms), estimateTaps UB clamp, SpscRing lock-free static_assert, stale planar/whitepaper doc lines, resampler preconditions and the unfaded-cut honesty note. 13 new tests including channels 5/7 (the only counts reaching the channel-parallel K=2/K=1 remainder tiles — previously zero coverage) and QuickQuality: an emulation-sized Q15 SNR + near-full-scale saturation gate that runs on the M33/M55/Hexagon CI legs, which previously had no on-target SNR check at all.

Verified: host 64/64 under -Werror; M33 (171 s) and M55 (20 s) QEMU suites green; C-ABI builds; long new float sims excluded from emulated targets by filter/regex (checked against both mechanisms).

https://claude.ai/code/session_01HuAFfoeD5a5Xe5aGNA16M9


Generated by Claude Code

F1 (High): pull blocks larger than the occupancy setpoint used to
drain into a permanent underrun limit cycle (64-frame callbacks
dropped out every ~0.24 s with defaults, never locking). pull() now
raises the effective setpoint to the observed block plus sawtooth
margin, bounded by FIFO capacity (auto-sized FIFOs get a 1024-frame
floor so callbacks to ~340 frames work unconfigured); the servo slews
to the new setpoint glitch-free and Status reports
effectiveTargetLatencyFrames. Configs that already satisfied the
constraint are byte-identical (icount within 0.07%, all targets).

F2: validated() now rejects NaN/Inf config doubles (a NaN rate built
an all-NaN coefficient table), band-edge sums above the rate (image
passthrough), maxDeviationPpm beyond the Q0.64 int64 range (UB), and
size products that wrap 32-bit size_t.

F3: hard resync clamps the discard to ring contents (a setpoint below
the staged scratch drained the ring and cascaded into Filling).

C ABI: null-handle guards on every entry point, shipped srt_capi.h
with the thread contract, srt_version() export.

Sweeps: Q15 blend margin comment corrected (0.005%, not ~5%);
estimateTaps clamps UB-range inputs; SpscRing asserts lock-free
indices; stale planar/whitepaper/1 ms doc lines fixed; resampler
preconditions and unfaded-cut honesty documented.

Tests (+13): Feasibility 64/128/240 regression suite, validation
throws, small-setpoint resync, consumer reset relock, zero-len and
oversized calls, Q15 fade ramp, channels 5/7 (the K=2/K=1
channel-parallel tiles, previously uncovered), and QuickQuality - an
emulation-sized Q15 SNR + near-full-scale gate that runs on the M33,
M55 and Hexagon CI legs, which previously had no on-target SNR check.
Host 64/64; M33 and M55 QEMU suites green.

https://claude.ai/code/session_01HuAFfoeD5a5Xe5aGNA16M9
@tap tap merged commit 2f1ccc8 into main Jun 12, 2026
22 of 24 checks passed
tap pushed a commit that referenced this pull request Jun 12, 2026
The static-musl Hexagon toolchain cannot propagate C++ exceptions:
the hardened validated() throws correctly but EXPECT_THROW never
catches and libc++abi terminates - surfaced by the first throw-test
ever to reach that CI leg (from PR #25, so main is currently red
there; this commit heals it). Validation is target-independent and
covered on every other platform. Limitation recorded in the
Known-debt ledger with the deployment implication (invalid Config is
fatal on this toolchain; validate before constructing) and the
candidate fix (-unwindlib=libunwind).

https://claude.ai/code/session_01HuAFfoeD5a5Xe5aGNA16M9
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants