From 63c246d976fcdb45c158937a34afab077c69cd2a Mon Sep 17 00:00:00 2001 From: Mollusk Date: Fri, 31 Jul 2026 22:38:26 -0400 Subject: [PATCH] docs: record the jitter buffer's unreachable shrink path as a known bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `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 --- docs/FEATURES.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 556734d..f309ac6 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -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: