# Rebuild the synthetic citation evidence

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

Use isolated checkouts at the two pinned revisions. Run `vp install`, then `T3CODE_DEV_SEED=0 vp run dev` in each. Never seed from live T3 userdata. The capture used before web port 8113/server 16153 and after web port 8396/server 16436. If those differ on another machine, adjust the driver origins and the `init.js` development import path. All imports resolve the real checkout source; no production file was changed.

Run `seed.mjs` once per fresh server, supplying its private pairing URL in `PAIR_URL`. The file is a standalone Playwright seed driver. It creates the scratch git project, creates a parent through the scoped project/startTurn commands, forks a used side chat with the real forkSideChat command, runs only the free Replay (dev) Showcase scenario, and selects a sentence from the rendered source to build valid UTF-16 citation selectors. Copy the returned synthetic `citations.json` to `before-citations.json` or `after-citations.json` beside the scripts. Do not copy the private session file into evidence.

The interactive `driver.mjs` opens Chromium and accepts JSON lines containing an async JavaScript body in `code`. Put fresh, private pair-command output into `before-pair-private.log` and `after-pair-private.log` for `api.login`. Those logs are private and are deliberately absent from uploaded evidence. Authenticate with `await api.login('before'); await api.login('after');`. Load `runtime-extensions.js` in the same `code` body, then call the row module functions with `api.forSide("before")` or `api.forSide("after")`, except R01/R02 which take the side explicitly. It fixes the export caption margin and closes prior contexts between fixtures. End with `{"exit":true}`. The driver creates a timestamped output directory; raw recordings remain there for inspecting rejected exports.

Row calls:

- R01: `await (await import(api.ROOT+'/R01.mjs')).default(api,'before')`, then `after`.
- R02: same signature in R02.mjs; perform it before adding extra fixture turns.
- R03: default export in R03.mjs; real selection/Cite/Save, unsent link click and Enter.
- R04 and R18: named functions in panels.mjs; final R20 uses panels-r2.mjs. R04 creates S2 only if absent. R18 writes the uploaded synthetic source-quote.md content into the scratch project through the filesystem and opens the real Files preview.
- R05/R06: responsive.mjs default with `api,'R05'` or `api,'R06'`.
- R07: default in R07.mjs; uses the current valid S1 quote created on each side by `prepare-native.mjs`, then records separate real Control, middle, Shift, and Alt clicks. Parent click and popup video are concatenated because Playwright records each page separately. `repair-popups.mjs` cuts from the native click to the final six settled seconds of the actual destination tab; startup loading is omitted and the cut is labelled. The captions identify the cut and destination URL.
- R08: default in R08.mjs, after R07 creates its current-source quote. It reuses the actual href recorded in R07-native-manifest.json rather than relying on the holder quote remaining in its initial virtualized page. A newly opened authenticated page has no existing source panel, then reload, navigation, Back/Forward run through the real browser history.
- R09: default in R09.mjs. **HARNESS** holds only the real quiet source-shell atom's read function at null, then restores its original implementation. The actual mounted ChatView hook/router/store/pane handle navigation. The state JSON records the null source, fallback route, replacement route, unchanged hash/activation/history length, and resulting parent panel. No source files are edited.
- R10/R14: `await (await import(api.ROOT+'/history.mjs')).seed(api)` before either capture. It adds one completed Replay turn at a time and checks a freshly loaded real history cursor and source absence. This run reached 11 total S1 turns. Then `capture(api,'R10')` or `capture(api,'R14') in history-r2.mjs for the repaired warning still`. R14 is a **HARNESS** which returns HTTP503 only for the first target S1 history request; it leaves the environment online, restores the next request, and explicitly activates the quote again. History state includes the real request URLs and rendered source bounds. `sourcePresent` refers only to the bounded projection's message array; paged timeline content is separately proven by `renderedSourceRects`.
- R11: default in R11-final.mjs after pagination seeding. It expands a real work group, selects an intermediate assistant response, saves a citation, collapses the group through its disclosure, then activates the saved quote. This demonstrates a source actually hidden by a fold rather than a final reply that never folds.
- R12/R13/R15/R16/R17: named exports in controls.mjs. Missing-message and changed-text inputs are serialized valid synthetic citations. R13 chooses the current S1-owned message ID so the stale-text warning is isolated from history paging. The ordinary fork is made through the real Fork from this response UI and owns its quoted Replay reply.
- R19: default in R19.mjs. This was a **real two-environment pass**, not a state harness. Each revision uses its own server as E1 and the other isolated server as E2; both contain synthetic data only and speak the same unchanged protocol. Mint a fresh private pair token for E2 into `secondary-pair-private.log`, update the environment ID to that server, and run. It creates distinct e2-parent/e2-side IDs, selects an actual E2 reply, saves its citation in E1, and compares E1's real panel state before and after navigation. No external machine or real account was used.

`render-video.mjs` adds a caption margin above the unchanged whole app frame. The actual current route is overlaid there; only the long base64 hash payload is abbreviated. Millisecond timing and full synthetic URLs are retained in each steps JSON. On-screen elapsed time is measured from capture start. Some R01/R02 action labels also contain nominal script times; the numeric elapsed timestamp is authoritative.

Stills use reduced motion, network idle, loaded fonts, and two pixel-identical PNGs taken 500ms apart. Recordings retain normal motion. `diffs.mjs` produces max-RGB-channel differences: exact >0 with 32x amplification and a visible minimum, plus >16/255. `contact-sheets.mjs` samples eight frames from each full video. `comparison-sheets.py` adds revision labels above whole Before/After frames without cropping. The contact sheets are indexes, not substitutes for videos.

The optional characterization groups C01–C06, Windows Electron, and native mobile were not run. R06 is desktop Chromium at a 390px viewport, using click-equivalent input, with no device or touch emulation.

Round 2 control recapture: after controls.mjs creates the ordinary source/fork fixtures, use controls-recapture.mjs for R15/R16/R17. Completed work is expanded and the real final reply centered; end-frame Diff0 is zero for these controls. R20 omits the optional PR page and captures settled Settings/Usage returns. R19 returns to E1 and collapses the sidebar using its real UI before recording. Mask coordinates come from DOM ranges over only server-measured duration digits; the app remains unmodified.

Final export repair: `repair-before-captions.mjs` changes only external caption labels inherited from the after driver, so before recordings accurately describe S1 route takeover. Run it after capture, then rebuild contact sheets. It does not modify app footage, CSS or DOM text. `restore-render.mjs` uses saved explicit render inputs; `render-video.mjs` CLI inference is for initial exports only.
