# Round 2 replay

Target [#25761](https://git.cafe/pingdotgg/t3code/pull/25761), before [71646e031a](https://github.com/pingdotgg/t3code/commit/71646e031a6dc9db1309b3b9dff597f872cf2fd3), after [bbb5f62a6f](https://github.com/pingdotgg/t3code/commit/bbb5f62a6ff0346b82fd9779187098bec572088a). Real app, no source edits, component substitutes, or copied production database.

## Checkouts and server

Create separate detached worktrees at these SHAs; run `vp install` in each. Start with `T3CODE_DEV_SEED=0 vp run dev`; read actual ports. `start-round2.sh` records the exact wrapper used. Every app database was created by its own build. Browser pairing is generated normally and is deliberately absent from uploads. Create projects through `POST /api/projects/mutate`, protocol header 2, project.create; see seed-projects-round2.js. Do not copy the running VM's T3 state.

## Host seeds and resets

Keep [fixture b](https://github.com/juliusmarminge/t3-evidence-25761-r2b) and [fixture a](https://github.com/juliusmarminge/t3-evidence-25761-r2a) alive for replay. They are private synthetic owned repositories. Create EMPTY private repos before running seed-round2.sh b/a. Existing seeds must not be rerun over the existing repos. Branches action, sibling-one, sibling-two, merge-proof correspond to PRs 1–4. seed-pages.py creates additional page branches/PRs on b; 99 succeeded, the final attempted creation returned 422. Total b=103 PRs. Host CLI is only seed/reset/independent verification; recorded actions use the real app.

Both builds normally use b, captured sequentially with host reset between them. Reopen via `gh pr reopen N --repo juliusmarminge/t3-evidence-25761-r2b`, close via gh pr close; wait for host state and reload app before starting each probe. For ready reset use gh pr ready; for draft use gh pr ready --undo. Never reset during a recording. The final fixtures retain all action results.

For irreversible A05, both repositories began with identically named branches, PR number 4, title, body and 1-file diff. Temporarily rename b to t3-evidence-25761-merge, clone its main into fixture-merge-before, create a new Merge evidence project, record before merge. Rename it back to b. Rename a to the SAME common name, clone main into fixture-merge-after, create the matching project on after, record merge; rename a back. Both originals were restored and left unarchived. This avoids identity differences in the visible surface. If replaying now, create a fresh identical repository pair because PR4 is merged on each.

For A04 reset PR1 closed. State=all, q=#1, involvement=all, selected PR1, top scroll, dark. Record More actions → Reopen, move cursor to blank space, hold settled endpoint 12 s. The head's detail request starts before the action reply and is kept until its response. It is not restarted.

For B14, PR1 description contains `[Synthetic sibling link](https://github.com/juliusmarminge/t3-evidence-25761-r2b/pull/3)`. Reset PR3 open. In PR1 detail hover the markdown link, open its internal detail, close PR3, close its tab, hover the original link again, hold 12 s. This is real description markdown, not a chat message; the complete B14 chat/modified-click/other-host row remains unverified.

For B15 create the synthetic PR snapshot evidence thread, focus its draft composer, type #6 and choose the exact PR suggestion to produce a PR context chip. Reset PR6 open. Hover chip, click to open detail, close PR6, close detail tab, hover chip again and hold. This is wide dark with a normal author; narrow/light/long/null-author variants remain unverified.

For B12/B19 create a fresh stopped thread `evidence-25761-snapshot7`, title Snapshot action evidence, branch main, and explicitly link only PR7 with normal thread.pull-request.link. Wait for the modern snapshot. Reset PR7 open before each side. Open its Pull Requests panel, retain PR7 tab, hold Shift and quick Close. Move to blank space; dismiss action notification; retain final linked row, tab and sidebar badge. It updates through the modern snapshot path, later than the action reply; no held-snapshot gate was installed.

For C02/C03 reset the acted PR open before BOTH sides and reload both fresh list pages. B has 103 rows: first page limit99 plus a four-row continuation. Click Load more and retain the log proving its cursor response. C02 acts on head PR102. C03 acts on PR5, whose number must be absent from the first99 response and present in the cursor response. Scroll back to the same top after closing. C03 has a settled placement difference: the head places acted PR5 at top; baseline's settled normal refresh omits it there. Both retain Closed detail. Neither issues another exact-cursor RPC, but BOTH issue a normal `all,limit198` expanded reread, so these are NOT proof of zero cursor DATA reads or host calls. C02 missing-row/rejecting-list harness branches and C03 open-filter/late-override branches remain unverified.

Extra chaptered recording resets PR2 closed, then Shift Reopen, More→Convert to draft, Shift Ready for review. Full all-state list q=#2, no filter-exclusion proof. extra-flow.js has the actual selectors and timing waits.

## Browser driver and measurement

Use T3 preview tools, Chromium156 Linux, no device emulation, viewport1440x1000 CSS, DPR2, root16px, Inter Variable. Set both app themes through normal Appearance or existing persisted theme before capture; A05 light, other web rows dark. browser-probe.js freezes Date at 2026-11-02T22:00:00Z and logs WebSocket PR requests/responses, click events and body MutationObserver text. Reapply it after a hard navigation; call __evidence.start(chapter) before recording. Tool screenshots downsample to1280x889, raw video is2880x2000. No reduced-motion emulation is exposed; reported false. There are no continuously animating fixtures.

round2-capture.js contains A04, page-steps.js robust inline close confirmation, extra-flow.js the additional chapter. orchestration-round2.js records the remaining interaction recipes and runnable tool adapter. round2-finish.js holds 12 seconds, waits fonts, captures two frames750ms apart, checks pixel identity, and exports RPC events in12KB chunks (tool result cap64KB). Each accepted still pair passed zero-difference stability within each side. No gate was placed on normal refreshes: live timings do not isolate causal reply patches. Browser counts are RPC counts, NOT server/host network counts. DOM text timing is MutationObserver timing, not compositor paint timing. Slight UI-before-reply values are possible because both happen in the same dispatch and normal refreshes can arrive first. See rpc-timelines.json for every action/read, original inputs and cursor.

## Native

Actual Android16/API36 Pixel9 leased from device pool, physical1080x2424, portrait, dark, font scale1.0 (settings text-size category large/platformValue1). Native DPR and logical viewport were not measured. No RN-web substitution. Prepare/install with `vp run mobile:install android --prepare` then `--session evidence-25761-r2 --metro http://fs-06.tail131df4.ts.net:8081` (8082 after). Same native fingerprint971743703b097b8870b39ff842d130f50b115eeb; JS bundle from the corresponding checkout Metro on all interfaces. Clear app data and fresh pairing each side using that checkout's pair-client.sh and isolated server. Logs with pairing credentials are excluded.

Open Pulls, search Synthetic action fixture, Open filter, open PR1. Wait until action.txt file is loaded (same cached state on both builds). Record status→Close→native confirmation→Closed detail; take stable detail frames; Navigate up→No results; hold and take stable list frames. Native screenshots are full physical surface. Gesture telemetry gives command times, but native action reply/UI observer were not instrumented. CDP connections repeatedly closed1006, so no frozen native clock or RPC timings. Native recordings are DIAGNOSTIC, not strict clock-controlled comparison. Initial relative Updated ages also differ (about7m versus5m), and the initial bottom CTA is Work on PR before versus Continue thread after; both settle to Continue thread after close. Final detail adds clock/status-icon and a one-level Changed files separator difference. Final list differs only in the OS clock. These unrelated temporal/thread-CTA differences prevent a clean controlled native recording comparison. No list long-press action was executed, so D01's context-menu branch remains unverified. mobile-round2.sh records the command recipe. Device lease was released and both Metros stopped.

## Processing and rejection

analyze-assets-round2.py creates zero-threshold amplified and >16/255 maximum-RGB threshold diffs. Unchanged pixels dim to16%; changed pixels magenta. prepare-videos-round2.py adds provenance banners without cutting video; web downscales to1440x1000 full surface, native remains full1080 wide. Native recorder omits long unchanged tails: delivery videos explicitly add4s last-frame clones; raw recordings remain in raw-captures.tar.gz. This padding is not another measured live interval.

All accepted full frames, both diffs and sheets were opened and inspected; sampled action/reply/endpoint video frames were inspected. Raw captures and failed attempts are preserved in raw-captures.tar.gz, never substituted for accepted pairs. Early B14-after has failed close confirmation; C02-C03 combined runs changed paging state during reset; B12/B19 initial/retake have hover/extra-link mismatches; initial extra-before did not execute draft/ready; first native-before is abandoned navigation. pairs.json names the accepted replacements. No startup, auth, mobile-pair, browser-cookie or production-data logs are included.
