Owner's first live mic test (2026-09-17) drove four changes:
- ONE primary transcription input at all times: while a quiz/ask
question waits, finals land in its field (text mode → 'Your answer',
select modes → 'Your thinking') via a module-level claim registry
(useDictationTarget in dictation.tsx); the composer is the fallback.
Esc in a question field also stops dictation (threaded through
DockOverlay → QuestionDock).
- No interim results: live words were distracting and shifted the meter.
Params now match the pi dictate extension exactly (no interim_results,
endpointing=300, no utterance_end_ms); the meter's width stays fixed.
- Optimistic meter: the click enters the meter view immediately (Stop
pill + meter within one frame, verified at 150ms in the dev shell);
token mint and mic acquisition run concurrently behind it.
- Wide idle button: the stats-bar middle is one full-width affordance —
a quiet bordered 'Dictate' button when idle (failure text replaces the
label), Stop pill + fixed meter while live.
Live-verified in the Electron dev shell: wide button renders on home
(167px) and chat (358px), meter + Stop appear at 150ms after click,
flat 2px bars in silence, clean return to 'Dictate' on stop.
Two live-verified Deepgram facts from the first real mic-test round:
- /v1/auth/grant returns { access_token }, not { token } — the route now
parses the right field.
- Minted JWTs authenticate over the WebSocket via the "bearer"
subprotocol; ["token", jwt] is rejected at the handshake (token is
for raw API keys only, as in the pi dictate extension).
Also documents the env-precedence gotcha in docs/research/stt.md: a
DEEPGRAM_API_KEY exported in the shell (e.g. .zshrc) silently beats
.env.local in next dev and the desktop authEnv() seam.