# Reproduce the evidence

**Refreshed A1:** follow [reproduce-A1.md](reproduce-A1.md) for A1 only. It supplies the breadcrumb pin, race-free seeding, fresh-state repeatability, and complete-frame inspection workflow. Other accepted rows retain the original recipe below.

AI-assisted; verified with the tests and tools listed above.

These scripts operate only on synthetic, isolated state. No real user database was read or copied. Every dev server started with `T3CODE_DEV_SEED=0`. Before and after are separate builds, checkouts, Electron profiles, and server databases.

1. Check out the supplied before and after commits; install dependencies with `vp install`. Run `T3CODE_DEV_SEED=0 vp run dev` in each checkout. In this run, before web/server ports were 8057/16097 and after 8725/16765; substitute the actual dev-runner ports in the scripts if needed. Never set VITE_HTTP_URL or VITE_WS_URL.
2. Run `python3 seed-files.py`. It creates 24 synthetic files in the scratch project. No provider turn is started.
3. Build each desktop with `vp run --filter @t3tools/desktop build`. `launch-desktop.py` installs Electron if needed, then starts each real Electron app through headless-desktop, with isolated homes and remote debugging on 9331/9332. No GPU, no device emulation, DPR 1. The app uses each checkout's Vite frontend and its own built server at 17761/17762. Track the returned PIDs.
4. Complete onboarding without importing anything (`finish-onboarding.js` via desktop-eval.mjs); use `seed-desktop.mjs before` and `seed-desktop.mjs after` to add the synthetic project through the actual UI. The script records each app-created draft URL. Evaluate `seed-panels.js` in each renderer, then reload. This seeds the shipped version-14 right-panel localStorage envelope under the valid environment/draft key, opening the first 11 files. It does not add a window API or replace production panes.
5. Capture each side's DISPLAY and XAUTHORITY from that side's owned Electron process into before-xenv.json/after-xenv.json (only these two variables). The actual X window id was 2097155 on each display; substitute another app window id if needed. Close detached DevTools and raise the app before recording. `resize-desktop.py` sets the real window size; full-window x11grab regions are used. S1 is 390x844, S2 900x800, other desktop rows 1280x800.
6. `python3 capture-suite.py before` and `python3 capture-suite.py after` execute A1,A2,A3,A4,A5L,A5R,A6,A7,P1,S2,S1, one fresh reload/history per row. Each run writes a NEW timestamped directory; no previous evidence is deleted. `node capture-desktop.mjs <side> <row>` captures an individual row. Both sides share the same driver. The final A6 pair was repeated after normalizing every nested scroller to zero to remove unrelated breadcrumb reveal drift; that normalization is in the published driver.
7. P1 is explicitly a HARNESS: `seed-pr-panel.js` invokes the existing store's openPullRequest with 51 injected synthetic PR surfaces in the real /pull-requests caller. Forge loading is unavailable and visibly reports no working credential. This verifies caller/scroll behavior only, not real forge-data integration. It is not a recording of 51 readable real PRs.
8. For W1 mint a fresh pairing token against each isolated server using its `node apps/server/src/bin.ts pair` command with the matching home/port, keep the command output private, and supply PAIR_TOKEN to `node capture-web.mjs <side>`. `launch-web-captures.py` consumes those private mint logs without printing tokens. The web driver creates an isolated Playwright Chromium renderer, adds the synthetic project through the UI, seeds the same 11 persisted file tabs, waits for the rendered fixture01 token, fonts, network idle, and absence of loaders, then records native CDP horizontal and Playwright vertical mouse-wheel input. Only the trimmed recording is published; pairing/onboarding footage is private.
9. `process-evidence.py` selects the final runs from their result logs, verifies each pair of per-side screenshots 500 ms apart is pixel-identical, generates full-resolution settled frames, amplified zero-threshold and 8/255-threshold diffs, 2x2 comparison sheets and video timelines. Black diff pixels match; white means max absolute RGB delta > 0 (Diff0, gain 255) or > 8 (DiffT). Full surfaces are preserved. Overlay is visible in recordings and hidden identically for final-frame comparisons. Inspect all sheets/timelines before upload.

All CDP gestures are synthetic mouse-source Input.synthesizeScrollGesture, speed 800, preventFling true. They are not physical trackpad or macOS momentum evidence. A6/W1 vertical steps use actual Playwright mouse.wheel; A7 exact equality is verified from delivered wheel deltas, not DOM-dispatched events. Each desktop fixture establishes available back history through Settings -> draft/PR, and A4/A5R additionally establish forward history through draft -> Appearance -> Back.

All captures use dark theme, reduced motion, root font 16px/100%, DPR 1, no mobile device emulation, full viewport. JavaScript Date is frozen at 2026-11-10 00:00 UTC during capture; event timing uses performance.now. Composer buttons are hidden on both sides to avoid publishing private runtime attribution; no gesture target is hidden. Desktop capture uses Xvfb, ImageMagick import and ffmpeg x11grab at 30fps; web uses Playwright video and screenshots. Both use real app code. No isolated replacement component is used.

Audit the raw event files for route, scrollLeft, wheel deltas/defaultPrevented, begin/end, indicator, and navigation. Desktop videoSeconds markers are approximate capture-relative wall times; the on-screen event clock starts approximately 0.55 seconds earlier. Web timestamps in the index refer to the on-screen clock (the encoder's trimmed video start can differ). Independent fresh databases generate different opaque draft/environment ids; overlays normalize these to B /draft/synthetic. Displayed content is identical.

Additional observed caveat: after A1/A2, a final CDP wheel event can arrive after gestureScrollEnd and produce an indicator=true event without navigation. These runs do not establish indicator disappearance; retain this observation for review.

Stop owned processes by their captured PIDs, remove only the before checkout, then remove scratch after uploads. Never remove the after checkout or touch another worktree/live install.
