# Evidence reproduction

Use pinned merge-base ac8dce0cc3abd8a337f2d806b5082a6834b9b81a and head f16d8770bda7acff940ed18a3557c050aea6651e. Install each with global vp. No source edits are needed. All scripts are scratch fixtures, not app patches.

`environment.ts`, `seed.ts`, `fake-fx.ts`, `fake-pi.mjs`, `pi-fixture`, and `freeze-clock.mjs` create synthetic isolated environments. Set CAPTURE_REPO to a checkout, CAPTURE_OUT to a **new timestamped directory**, CAPTURE_SHA to the revision, and T3CODE_DEV_SEED=0; run `node seed.ts` from the owning checkout with dependencies available (the original run symlinked scratch/node_modules to the head checkout's node_modules). Each server uses its own migration-created database, scratch HOME, and scratch workspace. No live database was read or copied. Data timestamps are frozen at 2026-11-02T20:00:00Z on the server; the OS clock remains live in recordings.

Start each checkout's mobile Metro on all interfaces (before 8081, after 8082) with EXPO_PUBLIC_T3_BEHAVIOR_PROBE=1, EXPO_NO_METRO_LAZY=1, REACT_NATIVE_PACKAGER_HOSTNAME set to the VM's reachable tailnet IP, and T3CODE_DEV_SEED=0. These captures used 100.68.167.16. Never publish pairing URLs. `pair.mjs` issues a fresh one-time pairing and hands it to the simulator without logging its value. `navigate.mjs` invokes only the real app's development navigation probe through Metro's inspector; it does not write drafts or input text.

Prepare and install development clients with `vp run mobile:install android --prepare`, then `vp run mobile:install android --session <lease> --metro <Metro URL>` (analogous iOS). Both revisions share their native fingerprint. Connect pool leases with agent-device; always name Pixel 9 or iPhone 17 Pro and pass --session. Software Gboard/Apple keyboards remain enabled; no test IME, clipboard replacement, or bulk text injection is used in proof flows.

`driver.py` provides native key-coordinate batches for Gboard. `android-rows.py` drives A2/A3/A5/A6; `a4-complete.py`/`a4-finish.py` drive the attachment lifecycle. `ios-driver.py`, `i1-complete.py`, and `i2-complete.py` use real Apple keyboard taps. Key positions come from recorded native accessibility trees. `send.ts` uses authorized server RPC to launch fixture threads and request subsequent questions; it never patches a database or client draft. The fixture HTTP server supplies the synthetic PNG for Chrome's ordinary Download flow, then the app's ordinary Choose Files picker.

Scripts have task-specific scratch paths, session names, IP and dataset names; update them together for a new run. The driver event log records actual dispatch duration. Native tap cadence depends on pool load; do not mistake holdMs:1 for a 1ms key interval. The Android A1 requested cadence was about 130ms, but measured batches were slower under load; outcomes and measured timings are reported in evidence.md.

`compare.py` creates a 255x amplified zero-threshold RGB difference and a threshold-16 luminance difference overlay (magenta). `frame-sheet.py` extracts twelve evenly spaced whole-surface video samples labelled with elapsed seconds. These sampled sheets aid review and do not replace the recordings.

Failed setup/driver attempts are retained separately in the supplementary archive and excluded from accepted row pairings. They include a bad inspector module lookup (Metro overlay), an initial Pi fixture lacking agent_settled, and keyboard/menu automation retries. Corrected fixtures add agent_settled and use native delete taps on iOS; no app source was altered.
