docs: record the jitter buffer's unreachable shrink path as a known bug
CI / check (push) Canceled after 0s

`target_delay` grows +1 per disruption to MAX_DELAY_FRAMES (240 ms) but only
shrinks after 250 consecutive clean frames — 5 s of unbroken audio. Two of the
five `clean_run` resets fire on every natural pause in speech (jitter.rs:201
benign underrun, jitter.rs:181 re-prime), and the sender stops transmitting
outright while the gate is closed (core/mod.rs:2041). The AIMD decrease half is
therefore unreachable under conversational voice: one early jitter burst pins
the extra latency for the rest of the session.

Found by code review; not yet reproduced live. Pairs with field-test debt #5.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-31 22:38:26 -04:00
co-authored by Claude Opus 5
parent 52d842160d
commit 63c246d976
+29
View File
@@ -137,6 +137,35 @@ covers internals). When you ship a feature, add it here.
---
## Known bugs
Defects found by code review, not yet fixed.
1. **Adaptive playout delay never shrinks back in real conversation**
(`src/core/jitter.rs`) — `target_delay` grows +1 per disruption up to
`MAX_DELAY_FRAMES` (12 frames = 240 ms) but only shrinks after
`CLEAN_RUN_TO_SHRINK` = 250 consecutive cleanly-played frames, i.e. **5 s of
unbroken audio**. `clean_run` is reset in five places; two of them fire on
every natural pause in speech: the benign-underrun branch (`jitter.rs:201`,
talker went quiet) and the subsequent re-prime (`jitter.rs:181`). Because the
sender skips transmitting entirely while the noise gate is closed
(`src/core/mod.rs:2041`), a pause between sentences *always* underruns the
receiver and zeroes the clean run — twice.
Net effect: the controller is a one-way ratchet. A single burst of jitter
early in a call pins up to 240 ms of extra playout latency for the rest of
the session, because no conversational speaker talks for 5 continuous
seconds without the gate closing. The AIMD "decrease" half is effectively
unreachable under the workload the app is built for.
Likely fix: let `clean_run` survive a benign idle→re-prime transition rather
than resetting it. Silence is not evidence the link is bad, so it should not
count against the clean run. Distinguish "talker stopped" (benign) from
"playout broke" (real) at `jitter.rs:195-202`.
Found 2026-07-31 by code review. Not yet reproduced in a live call — pairs
with field-test debt item 5 below.
## Known field-test debt (the 🧪 rows above, collected)
Re-run on a real desktop ↔ dopedart call before calling these done: