# Mobile thread-row accessibility evidence

Real dev clients, fresh server databases, synthetic projects only. Android: Pixel 9, API 36, portrait 1080×2424, light appearance. Each side runs its own server and Metro from its own checkout. The native client is obtained with `vp run mobile:install` for that checkout.

Place `mobile-proof-driver.ts` in `scripts/scenarios/` (it imports the repository's existing CLI, MCP and scenario helpers). Run `prepare-replays.py <checkout>` before starting the server. It supplies two synthetic ACP recordings through the normal Replay provider: an active command and an active thread-wait tool, each held for ten minutes. No projection or database rows are inserted. The same fixtures are used on both commits.

Start the fresh stack with `T3CODE_DEV_SEED=0 node scripts/scenarios/start-app.ts mobile <fresh-home> <server-port> <metro-port> <device-reachable-host>`. Export `PROOF_HOME`, `PROOF_PORT`, `PROOF_STATE` (a new output JSON file), and `T3_SCENARIO_APP_DIR` (the checkout), then run `node scripts/scenarios/mobile-proof-driver.ts seed`.

The driver creates Finished (Replay showcase, completed), Time-only (idle, no message), Approval (Replay approval in approval-required mode), Working (synthetic command-output recording), and Waiting (synthetic todo-list recording with an active t3_thread_wait tool). Pair the client to that server using the repository's `pair-client.sh` helper.

On both builds:

1. Open Chats; expand Working. Record the screen, capture the five rows, and dump the accessibility tree.
2. Long-press Finished thread → Snooze → In 1 hour. Expand Snoozed; capture the slim row and its node label.
3. Run the driver with `snooze 'Finished thread' 10` to use the real snooze command with a ten-second wake time. Leave Chats open until it wakes; capture Woke and its node label.
4. Run the driver with `settle 'Time-only thread'`, expand Settled, and capture its ordinary-time slim row.
5. `capture-state.sh <label> <output-directory> <session>` captures two screenshots separated by a 500 ms pause, compares them, and saves only app accessibility-node fields in a public JSON file. Live duration changes are also visible in the recordings.

Evidence is the captured real app and native accessibility tree, not a unit-test result. The Working row's visible elapsed time changes while its fixed-build label stays “Working thread, Working”. The Waiting row shows an icon without a visible duration and its fixed-build label says “Waiting thread, Waiting”.

iOS speech-output verification: Settings → Accessibility → VoiceOver → Caption Panel on, then enable VoiceOver using the switch thumb. A single tap focuses a row; double-tap activates controls such as shelf expanders. Capture each focused card, snoozed row, naturally woken row, and settled row. The black focus outline and bottom Caption Panel are generated by VoiceOver itself, not by the evidence annotation script. The recordings show those focus interactions. Audio itself could not be captured: the pool host denied Screen Recording permission to its audio probe.

Android TalkBack was enabled and its Developer settings → Display speech output was turned on. No speech captions or focus outline appeared through the available automation, and the app displayed an Android not-responding dialog during this attempt. Restarting restored the app. Therefore Android evidence is its real native accessibility nodes and UI recordings; TalkBack speech is unverified.
