fix(ptt): disable missed-key-up watchdog on P0 (DEC-031, supersedes DEC-028)
The watchdog spawned by ChanoraSession::start_audio cleared ptt_held after 30 s of continuous PTT key-down. That was correct for the 'OS lost the key-up event' failure mode the original SAD-079 / DEC-028 was designed to catch, but it was the wrong shape for real human speech: anyone holding the bound key for a long answer got cut off mid-sentence. For P0: - Comment out the spawn site in ChanoraSession::start_audio with the rationale + the P1 redesign options under consideration (raised ceiling / OS key-state polling / RMS-silence fallback). - Leave the MissedKeyUpWatchdog Rust type, its spawn / spawn_on_signal entry points, and all unit tests in chanora_audio::ptt unchanged so P1 can re-enable with the chosen detection strategy without re-implementing anything. Spec: new DEC-031 in product-decision-register.md supersedes DEC-028 for the v1 ship. DEC-028 stays in the register as historical context. The §7 open-decisions log + §8 change history get matching 0.9.12 rows. Note: Mumble and TeamSpeak ship without a comparable watchdog — the 30 s ceiling was stricter than industry baseline. The underlying protection (OS-level key-up loss) is still worth solving, just not with a fixed timeout. cargo test --workspace --lib: 80 passed / 0 failed / 1 ignored (unchanged; the watchdog unit tests still run because the type itself is unchanged). docs validator: clean (pre-existing 35-filename warning only).
This commit is contained in:
@@ -562,26 +562,31 @@ impl ChanoraSession {
|
||||
let controller = ptt::PttController::new(self.release_tail.clone());
|
||||
state.ptt_controller = Some(controller.clone());
|
||||
|
||||
// Spawn the missed-key-up watchdog on first start_audio.
|
||||
// It subscribes to the selector's `ptt_held` watch — NOT
|
||||
// the real gate — so it only fires when the user has
|
||||
// actually been holding the PTT key for >30 s. In
|
||||
// Continuous mode `ptt_held` is never set true, so the
|
||||
// watchdog never fires (the fix for the bug where
|
||||
// Continuous transmission would disable itself after the
|
||||
// 30 s default timeout).
|
||||
{
|
||||
let mut wd = self.ptt_watchdog.lock().await;
|
||||
if wd.is_none() {
|
||||
let signal = self.voice_selector.subscribe_ptt_held();
|
||||
let selector = self.voice_selector.clone();
|
||||
*wd = Some(chanora_audio::MissedKeyUpWatchdog::spawn_on_signal(
|
||||
signal,
|
||||
move || selector.set_ptt_held(false),
|
||||
chanora_audio::MissedKeyUpWatchdog::DEFAULT_TIMEOUT,
|
||||
));
|
||||
}
|
||||
}
|
||||
// SAD-079 / DEC-028 missed-key-up watchdog: DISABLED for
|
||||
// P0 per owner decision (2026-05-16). The original 30 s
|
||||
// ceiling caused real users to be cut off mid-sentence in
|
||||
// PTT mode whenever they spoke for longer than the
|
||||
// timeout. The watchdog's purpose (catching OS-level
|
||||
// key-up loss when the app loses focus / is minimised /
|
||||
// hits App Nap) is real, but the fixed-timeout
|
||||
// implementation is the wrong shape.
|
||||
//
|
||||
// P1 redesign options under consideration:
|
||||
// * Raise ceiling to ~5 min (owner-tunable, per DEC-028)
|
||||
// * Add Windows GetAsyncKeyState / macOS
|
||||
// CGEventSourceKeyState / X11 XQueryKeymap polling so
|
||||
// we detect the actual OS desync directly instead of
|
||||
// timing out on legitimate long speech
|
||||
// * Combine with an RMS-silence check once the audio
|
||||
// level meter (P1) lands, so the watchdog only fires
|
||||
// when the user has been "transmitting" silence for
|
||||
// the entire window
|
||||
//
|
||||
// Until P1 picks one of those, we ship without the
|
||||
// watchdog. The existing MissedKeyUpWatchdog code path
|
||||
// and tests remain in place so the P1 work can re-enable
|
||||
// it with the chosen detection strategy.
|
||||
let _ = &self.ptt_watchdog;
|
||||
|
||||
// Apply any binding the user saved before audio was running
|
||||
// (SDD-094 follow-up). Persistence + caching happen in
|
||||
|
||||
Reference in New Issue
Block a user