# Two-machine triage proof

Run `python3 boot.py <side> <checkout> <first-port>` in a separate terminal for each commit. It creates fresh timestamped homes, separate bwrap mount namespaces, separate server processes, a synthetic hostname per environment, and a web dev server. Each server sees only its own synthetic `/tmp/triage-machine-a` or `-b` home. Stop the fixture with Ctrl-C; it terminates only captured process groups.

After servers are ready, run `python3 seed.py <side>`. It uses the real CLI/RPC to create one Demo project and one stopped Earlier work thread with Replay (dev), Multi turn. No live database is copied.

Web: use a 1280×800 light browser; pair A then add B through Connections. Open Earlier work on A, open the command palette, choose Triage an issue, append `The sidebar freezes when I open a thread. Preserve this description.`, choose B in Run on, send, then click the sent playbook. Capture the actual file viewer and the sent description together. On head, also open context.md. In the thread's terminal run `cat /tmp/triage-machine-b/userdata/server-runtime.json` to compare the server PID with the context PID.

Mobile: install each checkout's client using `vp run mobile:install ios --prepare`, then `--session <leased-session>`. Both exact commits resolved to fingerprint `97f38ecae5db3547bcf15a610944b1da0457fa11`. Start Metro from apps/mobile with `T3CODE_DEV_SEED=0 vp run dev:client --port <metro-port>`. `mobile-link.py` delivers dev-client and pairing deep links; provide the device-reachable host through PROOF_DEVICE_HOST, never publish pairing logs. Use a wiped iPhone 18 Pro on iOS 27.2, light theme, 402×874.

Open Earlier work on A. Because the pool driver exposes no Cmd-K input, `mobile-cdp.mjs open-palette.js` invokes the existing T3KeyboardCommands onCommand callback through the development debugger; it does not replace any app code or server response. Set METRO_PORT for the running Metro. Type `triage` in the real palette and tap Triage an issue. Tap the draft composer and append the same description. Tap the environment picker, tap Machine-B, send, and tap the actual sent playbook link. Enable word wrap in File actions on both sides.

Head supplemental error: temporarily chmod the destination's synthetic userdata/triage directory to 0500, switch the unsent triage draft to B, capture the real error, restore 0700, dismiss the error and return to the draft. Confirm A and the description remain.

Head supplemental cancellation: SIGSTOP only the captured B process group, start the switch through the real environment picker, return to the draft and invoke the existing cycleHost command callback to select A again. SIGCONT the same process group. Wait for B to finish preparing its real session; the stale completion must not move the draft. Send and open the link to confirm it still targets A.

Replay gives a fixed reply; no claim is made that the replay model reads files. Readability is demonstrated by opening the real playbook through each client's file viewer, backed by the destination server.
