# Manual live-transcription verification (M7, D-016) The segment loop (`src/lib/live.ts`) and the protocol changes are covered by unit tests; microphone capture, the AudioWorklet path, and end-to-end live quality can only be exercised in a real browser. This is that procedure. Re-run it after any change to `src/lib/live.ts`, `src/lib/mic.ts`, `src/components/LiveControls.tsx`, or the live wiring in `src/App.tsx`. ## Prerequisites - A machine with a working microphone. - Chrome/Edge (WebGPU) and ideally also Firefox and Safari — the three differ exactly where mic capture is fragile (context sample rates, AudioWorklet Blob-URL modules; Safari exercises the ScriptProcessorNode fallback if the worklet path fails there). - `getUserMedia` requires a secure context; `http://localhost` qualifies: ```sh bun dev # or: bun run build && bun run start ``` ## 1. Permission flow 1. Open the app, pick `whisper-tiny.en`, click **Start live transcription**. 2. The browser prompts for the microphone. **Deny** it: the button must return to idle and the error "Microphone access was denied…" must appear; the app stays usable (file flow unaffected). 3. Click again and **allow**: button becomes **Stop** with a pulsing red dot; the browser's mic indicator turns on. If the model wasn't downloaded yet, the download progress panel appears and live text simply starts once it is ready (segment passes queue in the worker). ## 2. Live transcription behavior 1. Speak a few sentences with natural pauses. Expect: - While speaking: dimmed italic *tentative* text appears within a couple of seconds (tiny.en; slower models lag proportionally) and refreshes. - After a ~1 s pause: the sentence commits — the text turns from italic to regular ("committed") and no longer changes. - Silence alone (say nothing for 30 s) must produce **no** text — the energy gate drops silent segments, so no hallucinated "thank you."-style output. 2. DevTools → Network: **zero** requests while speaking (weights may download at the start; the audio itself never leaves the device). 3. During a live session, ModelPicker / options / dropzone are disabled. 4. Model choice sanity: repeat briefly with a multilingual model + a fixed language and confirm the language/task options are honored. ## 3. Stop & result 1. Click **Stop** mid-sentence. The button shows "Finishing…" while the last segment gets its final pass, then the normal **Transcript** panel appears: full text, Copy button, and a Timestamps section whose segment times are **absolute** (a sentence spoken ~10 s in must not be timestamped 0:00). 2. The browser's mic indicator must turn off immediately on Stop. 3. Start a new live session afterwards, then also transcribe a file — both must still work (session cleanup, request correlation). ## 4. Quality/latency knobs (only if needed) If commits are too eager/lazy in real rooms, tune `LiveSegmenterOptions` (`speechRms` gate 0.015, `commitSilenceSeconds` 0.75, `maxSegmentSeconds` 25, `minSpeechSeconds` 0.25) and the `LiveTranscriber` throttle (`tentativeIntervalMs` 1500) — all injected from `src/App.tsx` defaults, all unit-tested in `tests/live.test.ts`. Record any tuned values in D-016. ## 5. Offline live transcription With the PWA installed and a model cached (see `tests/offline.md`), go offline (airplane mode) and run a live session — it must work identically: capture, worklet (Blob URL, no network), inference, stop/transcript. ## Recording the result When this passes in a real browser, flip the `[~]` manual-verification item in `WorkBreakdown.md` M7 to `[x]` and note browser + version here. - [ ] Verified on: _browser/version, date_