# Rebuilding this evidence

Before: `15fe2832727893cbdd2214383f9f971474849695`; after: `9e4299152ede4514520d37791b603e2613095d51`.

Use two independent worktrees with installed dependencies and **fresh** `.t3` homes. Never seed from the VM's live home. Paths and selected ports for this run are in `rpc-driver.mjs`; read the real ports from each `[dev-runner]` line and update that mapping if occupied.

1. Create the synthetic workspace `/tmp/lead-28195-r1/evidence-capture/workspace`, `git init` it, and make one empty initial commit with a synthetic identity. It contains no source files or real user data.
2. Before: `T3CODE_DEV_SEED=0 vp run dev` in the base checkout. After: `T3CODE_DEV_SEED=0 vp run dev --share --host 0.0.0.0` in the head checkout. Retain each terminal/PID. `--share` failed here because the VM user lacks Tailscale Serve permission; the wildcard backend was reachable directly over the tailnet for native pairing.
3. Run `node <evidence>/seed-and-send.mjs before seed` and the same command with `after`. The driver creates the same project/thread and dispatches two identical prompts through authenticated RPC. The final driver subscribes **after** creating the thread. In the original run the first subscription was opened too early; turn 1 nevertheless completed, and `finishSeed` reattached and sent turn 2. No turn was repeated.
4. Save the C0 transcript. Stop both app servers before direct SQL. Run `repoint-native.py before` and `after`; this backs up each synthetic database, then changes only the exact thread/provider-thread projection's `nativeThreadRef.nativeId` to `019a0000-0000-7000-8000-000000028195`. Neither Codex native history nor the event log is changed.
5. Restart both servers against the same respective homes. Confirm the injected ref remains before dispatch. Run `record-recovery.mjs before` and `after`; each records the real app, invokes the shared RPC driver's `third` stage, awaits the persisted terminal event, then reloads and counts dividers. It records a complete load/dispatch/recovery/completion/reload sequence.
6. Run `capture-stills.mjs` for each side. Browser: headless Chromium 148.0.7778.96 on Linux x86_64; no device emulation; DPR 1; font scale 1; 1440×900 and 390×844; light/dark; reduced motion; fixed app clock 2026-11-03 02:00 UTC. Both use the real thread, same prompts and message contents. The narrow view retains the same bottom anchoring so the inserted divider moves earlier content upward. Viewport chrome and composer remain unchanged. Metadata JSON contains routes and frame hashes. Each accepted frame has an identical screenshot at least 500 ms earlier.
7. `make-diffs.py` makes each contact sheet, Diff0 and DiffT16. Diff0 paints **every nonzero per-channel RGB difference** full magenta (including one-level changes). DiffT16 paints differences whose maximum channel delta exceeds 16 full amber. Black means unchanged. No tolerance is used for the Diff0 comparison.
8. Run `transcript.py <side> S1`. It queries positions, items, messages, handoffs, transfers, native refs, and the event log read-only. For C0, point its optional third argument at the pre-fault backup. The transcript omits summary/history prose from event payloads. Those fields contain only the same synthetic conversation, but are unnecessary for linkage proof.
9. S5/V6: run `vp test run apps/server/src/orchestration-v2/TurnItemPositionStore.test.ts apps/server/src/orchestration-v2/testkit/ProviderSwitch.integration.test.ts` at head. At base, copy **only** the head integration test file into the disposable base checkout and run `vp test run apps/server/src/orchestration-v2/testkit/ProviderSwitch.integration.test.ts -t 'shows the recovery handoff in the timeline'`. That test must fail because the handoff timeline item is missing. `allocator-transcript.mjs` uses the actual head position store and an isolated in-memory migrated DB to print concrete allocation results.
10. Native: run `vp run mobile:install android --prepare` before leasing Pixel 9 with the device-pool skill. Connect/open session `evidence-28195`, run Metro from the head checkout on all interfaces with `REACT_NATIVE_PACKAGER_HOSTNAME=fs-15.tail131df4.ts.net`, then `vp run mobile:install android --session evidence-28195 --metro http://fs-15.tail131df4.ts.net:8081`. Use the repository's `pair-client.sh` with backend `http://fs-15.tail131df4.ts.net:15866`. Pair after the first app boot completes (an earlier deep link was lost during bundle loading). Open Remembered word, set OS dark appearance and animations off. `mobile-runtime.mjs` records React Native Dimensions and fixes only the app's JS Date to the same time used on web. Android's status bar clock remains the device clock. `mobile-still.mjs` accepts only two binary-identical screenshot frames at least 500 ms apart. Native output: 1080×2424 physical pixels, 411.43×923.43 logical points, scale 2.625, fontScale 1.0, Android 16/API 36, React Native 0.88/Hermes, x86_64 dev client fingerprint `541b3da3e5f7b2ad504aaa6303bdcea8d7194d22`. No static fixture or component harness was used for visual proof.
11. Close the AgentDevice lease and browser tabs, stop only retained terminal processes, and remove the disposable base worktree. The head worktree and evidence remain for the lead. No PR edits, commits, or pushes.

The `inspect-scroll.mjs` diagnostic demonstrated that forcing scrollTop=0 on the narrow after frame adds the app's Scroll to end control. That diagnostic is not submitted as evidence. Submitted narrow frames keep consistent bottom anchoring instead.

# Recording timestamps

Original recordings, nearest second (both 1440×900, light, DPR 1). Exact driver milestones relative to the ready frame are retained separately in each `recording-timestamps.json`.

| Original video time | Before | After |
|---|---|---|
| 00:00–00:12 | Initial app load, then turns 1–2 | Same |
| ~00:12 | Ready; no divider | Ready; no divider |
| ~00:14 | Start shared turn-3 RPC driver | Same |
| ~00:18 | Turn-3 user message appears | Same |
| ~00:19 | Resume fallback; no divider | Resume fallback inserts one divider above turn 3 |
| ~00:24 | PELICAN reply completes | Same; one divider |
| ~00:26 | Reload | Reload |
| ~00:32 | PELICAN persists; no divider | PELICAN and exactly one divider persist |

Both recordings include expected loading/streaming states. The empty right surface panel is the same on both sides; no branch-specific panel or data differs. Reload restores the main sidebar on both sides.
