# Dictation navigation evidence

Before commit: 871b00907d0bcf2705224de6c6e90de925c7cbb9. After commit: 13123cfa15709b8db2a09998bb173707d10db8e1.

Observed on both routes: before, Thread A remains empty; after, Thread A contains `A blue bicycle belongs in the garden.` Thread B remains `Keep this draft unchanged.` A newly opened draft remains empty. Recording status is active immediately before navigation and inactive afterward on both commits.

Final stills were each preceded by two identical screenshots taken 500 ms apart (ImageMagick pixel difference: zero).

Both sides run the web development app from independent detached worktrees, each with its own fresh database and T3CODE_DEV_SEED=0. Browser: Chromium 157 on Linux x86_64; viewport: 1280 x 800 CSS pixels; device pixel ratio: 2; dark appearance. Videos are captured at 2560 x 1600. Synthetic Thread A starts empty; Thread B contains `Keep this draft unchanged.` No agent turn is sent.

The browser microphone is supplied with real PCM audio generated by:

```sh
espeak-ng -s 145 -w sentence.wav 'The blue bicycle belongs in the garden.'
ffmpeg -i sentence.wav -ar 16000 -ac 1 input.wav
```

Transcription is performed by the real server using the same local English speech-to-text model on CPU. No transcript or transcription response is mocked. The synthetic audio is about 2.8 seconds long and begins 0.6 seconds after microphone acquisition. The recording remains active after the sentence ends, until navigation.

Driver execution through the Browser panel:

1. Pair each browser tab with its own server using its startup pairing link (never publish that link).
2. Evaluate seed.js in each tab. Download and select the same English speech model from the catalog through POST `/api/voice/models/download` and `/api/voice/models/select`, passing its catalog ID in the JSON `modelId` field.
3. Evaluate prepare.js. Set `window.proofAudio64` to the base64 contents of input.wav, then evaluate microphone.js. The latter replaces only microphone acquisition with a real Web Audio MediaStream.
4. Open Thread A using the sidebar. Collapse thread details for A, B, and the new draft before capturing to keep environment details out of recordings.
5. Set `window.proofDestination` to `thread-b` or `new-draft`, start browser recording, then evaluate interaction.js. Wait for its promise to resolve and inspect `window.proofResult`; stop recording.
6. Before the second scenario, evaluate prepare.js again to restore the same initial composer text.

interaction.js uses fixed presentation pauses and waits for the actual Recording status. It starts dictation, lets the sentence finish while still recording, navigates without pressing Send or Finish, checks the destination draft, and returns to A. The new-draft scenario passes through the new draft and B before returning to A.

AI-assisted; verified with the tests and tools listed above.
