feat(transcribe): tolerate music without spurious errors or wasted Rev.ai calls
Two fixes for the transcribe pipeline when audio is background music or
other VAD-fooling non-speech content:
1. Trust empty STT results. `process_audio` no longer raises when the
backend successfully returns 0 statements — empty results now follow
the same filter/preserve path as VAD-insufficient audio. Backend
exceptions (5xx, timeout, failed jobs) still propagate as before.
2. Music-aware Rev.ai upgrade gate. `run_vad()` now computes a
speech-to-loud-window ratio (`loud_speech_ratio`) alongside `noisy_rms`.
The noise upgrade gate admits only when ratio is >= the new
`transcribe.noise_upgrade_min_speech_ratio` config key (default 0.3).
Music audio produces a very low ratio (loud windows dominated by
non-speech); noisy meetings stay well above the threshold. If the
ratio is unavailable (audio too short), the gate falls back to today's
`is_noisy()`-only behavior.
The new VAD signal is surfaced on `VadResult`, in `observe.transcribed`
events, and in JSONL metadata alongside `noisy_rms`/`noisy_s`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>