Skip to content

No noisy-environment listening option: the tuned 'conservative' VAD preset exists but no code path can ever select it #571

Description

@rosscado

Problem

SayPi ships a VAD preset tuned for noisy environments (conservative) that selectVADPreset can never return, so a user in a noisy room has no way to reach it — and the one listening control they do have ("Quiet mode") moves sensitivity in the opposite direction.

Scope

  • Affected: src/vad/VADConfigs.ts (selectVADPreset), and the "Quiet mode" control in entrypoints/settings/tabs/general/.
  • Applies to both contexts the selector serves: dedicated chat hosts and generic/universal-dictation pages.
  • Out of scope: retuning balanced, and the exact UX of any new control (see acceptance criteria — deliberately not prescribed).

Reproduction / verification

Current selector is total and has two outcomes (src/vad/VADConfigs.ts:104):

export function selectVADPreset(context: VADSelectionContext): VADPreset {
  if (context.quietMode) return "highSensitivity";
  return "balanced";
}

So the reachable set is {balanced, highSensitivity}. The presets and their opening thresholds:

preset positive negative redemption reachable?
highSensitivity 0.35 0.20 12 (384ms) yes — Quiet mode on
balanced 0.40 0.25 10 (320ms) yes — default
conservative 0.60 0.45 8 (256ms) no path

conservative is documented in the same file as "Noisy environments – lower sensitivity (reserved; not yet selected)", and its values are locked by test/vad/VADConfigs.spec.ts, so it is maintained but dead.

The only user-facing listening control is the "Quiet mode" checkbox (General settings), described to users as "Speak softly — picks up quieter speech…". Enabling it selects highSensitivity (positive 0.40 → 0.35), i.e. it makes the VAD more likely to open on background noise.

Expected: a user in a noisy room can bias listening toward requiring clearer speech.
Actual: they can only leave it at balanced or make it more sensitive; the preset built for their case is unreachable.

Acceptance criteria

  • conservative is reachable in normal operation, or is deleted along with its lock test — a tuned, tested, permanently-unreachable preset is not a valid end state.
  • A user (or an automatic signal) in a noisy environment ends up on a preset whose thresholds are at least as strict as balanced.
  • The existing Quiet-mode behaviour and the balanced default are unchanged for users who don't opt in.
  • Whatever selects it is unit-testable at the selectVADPreset seam, without a browser.

Notes / hypotheses (non-binding)

  • Leverage the VAD's own confidence signal (computed, then discarded) to cut silence hallucinations — and characterize the thresholds #420 item 4 anticipated exactly this: its remaining refinement was to wire conservative to a noise/SNR estimate, which would make the choice automatic rather than a setting. Either direction satisfies the criteria above; the automatic one avoids adding a control users must understand.
  • Founder-reported symptom that prompted this (2026-07-29): STT quality noticeably worse with a washing machine running nearby. Mechanism is not established — filed as the reachability gap, not as a diagnosis of that report. Two candidate mechanisms worth measuring before choosing a fix: (a) balanced's low negativeSpeechThreshold (0.25) may not be crossed cleanly when steady broadband noise raises the probability floor, affecting where segments end; (b) noise-only segments clearing 0.40 get uploaded and transcribed. The Leverage the VAD's own confidence signal (computed, then discarded) to cut silence hallucinations — and characterize the thresholds #420 admission gate is unlikely to be involved — its floor is positiveSpeechThreshold + 0.05 on the segment's peak, which real speech clears easily.
  • The getUserMedia constraints are not the gap: @ricky0123/vad-web hardcodes noiseSuppression/echoCancellation/autoGainControl to true after spreading caller constraints, so browser-level noise suppression is already active and cannot be accidentally disabled by SayPi.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions