# Rebuild capture3

HARNESS synthetic RPC data around the real app routes; synthetic project created by RPC. No live database copy, forge edits or tracked source edits. Before [32ecd71726](https://git.cafe/pingdotgg/t3code/commit/32ecd71726fee16f335484c1f95cbce126d461f6), after [57eaadd11e](https://git.cafe/pingdotgg/t3code/commit/57eaadd11e361b203d165aa9b64f3951df6cbdb4).

The archive includes every written driver, fixtures, identical source media, accepted videos, full stills and settling partners, crops, diffs, native layout measurements and every-second inspection frames. It excludes auth, environment/database contents and server logs. Prior accepted rows are retained through the merged index. The files in assets are proof, not inputs. Runtime output directories have timestamped names; run-20261030T1412 is a legacy static-output label from the reused driver, not the actual capture time.

1. Extract the archive into a new empty scratch directory. The scripts use absolute paths: put its capture3 tree at /tmp/lead-25988-r2/capture3, and its capture/media tree at /tmp/lead-25988-r2/capture/media, or replace those roots consistently in copies. Never extract over another capturer's state. Check out the two exact SHAs at /home/ubuntu/wt/pr-25988-base and /home/ubuntu/wt/pr-25988; run `vp install` in each. Never copy ~/.t3. Use the matching Node/vp versions from the checkout.
2. Run `python3 start-capture3.py`. This is the non-overwriting launcher; do NOT rerun historical setup.py, which copies older driver versions. It sets T3CODE_DEV_SEED=0 and starts both real dev servers, Metro instances and synthetic-data HTTP/WS proxies. Check each actual dev-runner output and adapt proxy/seed ports if occupied: before server16579/web8539/proxy16735/Metro8082; after server16347/web8307/proxy18307/Metro8081. Host fs-27.tail131df4.ts.net must be replaced consistently on another machine. Dev logs can contain pairing credentials and must not be uploaded.
3. Run `node seed.mjs before`, `node seed.mjs after`, and `node configure.mjs before`, `node configure.mjs after`. This creates proof-project by authenticated RPC and sets reviewGuidesEnabled=false on BOTH isolated servers. The reused after sandbox initially had this setting true; matching it is required to avoid a Guide tab and differing tab defaults. Existing synthetic project reports already-exists safely. Read each checkout's .t3/userdata/environment-id (or .t3/dev/environment-id if that is the dev-runner state path), then substitute only those public IDs for before/after in native-control.py. Captured IDs: before6f4cf28b-290a-428d-8917-34d4517ec7a3; after508813d0-f70a-4ae6-8b99-a71113930083. No auth token is hardcoded in the scripts.
4. Prepare cached clients with `vp run mobile:install ios --prepare` and `vp run mobile:install android --prepare`. From the after checkout, connect sessions capture3-ios/capture3-android to the configured agent-device proxy; explicitly open iPhone 17 Pro and Pixel 9, then install using `vp run mobile:install <platform> --session <session>`. Android Metro argument is http://fs-27.tail131df4.ts.net:8081. Native fingerprints: iOS953468b560e21a2a7cfb6d86a69eda1e061efb8a; Android8006860c656de3319b4b47d3bab69506af6a0809. Tools target Google (Android), simlock (iOS) in Metro /json/list. Explicit Expo deep links in switch-side.py work on both platforms; an Android metro hint alone can open a white screen. Accept an iOS system Open confirmation if presented. The helper waits for rootNavigationRef.isReady before pairing/navigating.
5. `python3 switch-side.py android before`; `python3 native-f08.py 8082 Google android before` reproduces F08. The accepted after movie is retained from capture2, made with the same native-f08.py sequence; its source media and fixture match. F08 synthetic route number2598908.
6. For each side: `python3 switch-side.py android <side>` then `python3 fresh-capture.py <metro> Google android <side> 1`, repeat with2; do the same on iOS with target simlock and platform ios. fresh-capture performs a fresh app launch for every sample. `python3 native-f10.py <metro> <target> <platform> <side>` records the collapsed→expand→image→close→collapse sequence. Use Android dark, iOS light. Route2598910. Both same-SHA pairs are necessary to distinguish layout noise from table reflow. layout.js reads Fabric bounding boxes without changing layout.
7. `python3 switch-side.py ios <side>`, then `python3 inline-playback.py <metro> simlock <side> light` and repeat dark. It mounts both production players, pauses/seeks each to0, then plays and pauses each. Route2598888. DO NOT retry iOS fullscreen or web-wide fullscreen: both have an accepted known black-recording tool limit. This pass tests inline playback only.
8. `python3 compare-stills.py` builds raw cropped Diff0 absoluteRGB×16 and threshold12 comparisons; the iOS matching-layout comparison selects two captures at equal native positions without shifting pixels. `python3 validate-package.py` verifies whole-surface settling. `inspect-video.py` extracts fps1 frames and contact sheets; open every sheet, every comparison, and every endpoint before accepting a recording. `stage-package.py` names accepted run folders explicitly; update that whitelist to new timestamped runs, rather than accidentally packaging historical rejected captures. It derives the pixel-map attribution and creates manifests. `publish-assets.py` uploads individual review files; raw fps1 frames also travel in the archive.
9. Close both agent-device sessions promptly, stop only owned process groups recorded at spawn (verify PID cwd and process group), confirm all8 ports stopped, and remove only the before worktree created for the test. This pass stopped all6 owned groups and removed before; both close attempts reported Lease is not active, twice more than60s apart, so no active lease remained. After checkout and /tmp/lead-25988-r2 are retained for the lead; after tracked status is clean. The isolated after setting reviewGuidesEnabled remains false.

Environment: iPhone17Pro402×874pt/DPR3/fontScale1 (tool still402×874px, video1206×2622), Pixel9 API36 411.4286×923.4286dp/DPR2.625/fontScale1 (1080×2424px). F01 iOS light and dark, F10 iOS light; F08/F10 Android dark. Every F10 static full frame and crop has an identical second capture500ms later. JS clock08:00Z; full OS clock retained. Status-bar crops iOS(0,62,402,873), Android(0,120,1080,2424). No retouching. Recording durations include variable RPC/tool time; not a performance measurement. Hosted videos include native app chrome and a development warning bar within their identical source bytes.

F10 attribution: baseline same-SHA iOS fresh launches produce17,958 Diff0 pixels/8,713 atT12; the cross-SHA start absolute-difference map is identical byte-for-byte. Prose y differs315.999995→316.333331pt with height240pt unchanged. Cross-SHA end adds two endpoint rounding pixels belowT12. Matching-y baseline/head is zero at threshold0; Android final start/end are both zero. Android baseline same-SHA noise max3/255; head same-SHA noise zero. Full measurements, sources and raw diffs are in the F10 sheet. No deterministic unexplained difference remains.

Historical unsuccessful runs (Overview selected before matching server setting, Android white launch, one truncated iOS screenshot response) are excluded from accepted proof. Their orchestration wrappers remain available for audit but are not canonical entrypoints. No further fullscreen attempts occurred.

Drivers and fixtures: [scripts.md](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/a30c91267db025c3/scripts.md)

Manifests: [capture3-manifest.json](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/8733cf27e0a6d9b6/capture3-manifest.json) · [recording3-manifest.json](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/6d7d069652b7bbc5/recording3-manifest.json) · [full-frame-settling.json](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/c32728dcd7a898e8/full-frame-settling.json)
