# Round 2 reproduction and limits

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

Before is [4c36119](https://git.cafe/pingdotgg/t3code/commit/4c361199f47f6ea32a2c14835df392640d0f7c63), after is [28ee80f](https://git.cafe/pingdotgg/t3code/commit/28ee80fa3a26b4663950345034f971887d0ad2f8). Each served its real Vite web application and Node server from its own checkout. No source edits, commit, push, or PR edit was made. Round 1 accepted rows were left alone.

## Environment

Linux x86_64 host fs-52; Chromium 157.0.0.0, browser zoom 1, DPR 2, locale en-US, timezone UTC. Whole client viewport, not cropped. WD = 1440×900 CSS pixels / 2880×1800 PNG, default dark theme; WN = 390×844 CSS pixels / 780×1688 PNG, default light theme. Set themes using `setTheme('dark')` / `setTheme('light')` from `/src/hooks/useTheme.ts`. Root font size 16px, composer 14px, code 13px. Sans stack resolves to `-apple-system,BlinkMacSystemFont,"Inter Variable","Segoe UI",system-ui,sans-serif`. No browser extensions or device emulation. WN is responsive web, not a native capture.

All ordinary endpoints freeze the browser clock at 2026-11-10 09:00:00 UTC, with a cached minuteTick snapshot. A09 instead uses the explicitly narrated 10:10 → 10:11 jump. Server event timestamps use server time; none are displayed in accepted frames. A13 disables CSS animations and transitions in its explicitly labelled presentation harness to make the Thinking endpoint stable. Other rows retain app styles.

## Fresh synthetic server state

Use only fresh isolated homes. Never use an installed T3 database. `seed.py` creates the synthetic workspace and two JSONL transcripts under this run's before/after temporary provider config directories. It does not read a real HOME. Both transcripts have identical synthetic two-message history, at 06:00 and 06:00:10 UTC, on both sides. The workspace is an empty git repository on branch `master` with an untracked README; that deliberately reproduces the visible +1 changes capsule.

Create the before checkout with `git -C /home/user/t3code worktree add /home/user/wt/pr-33042-before 4c361199f47f6ea32a2c14835df392640d0f7c63`, then `vp install` there. Run the following separately in each checkout, substituting the literal side in the paths:

```sh
T3CODE_DEV_SEED=0 CLAUDE_CONFIG_DIR=/tmp/lead-33042-r1/evidence-capture-2/run-20261110T0905Z/before/home/.claude CODEX_HOME=/tmp/lead-33042-r1/evidence-capture-2/run-20261110T0905Z/before/home/.codex vp run dev --home-dir /tmp/lead-33042-r1/evidence-capture-2/run-20261110T0905Z/before/t3
```

After uses `after` in all three paths. Actual ports were before web 7403/backend 15443, after web 5911/backend 13951, read from dev-runner output. Do not set VITE_HTTP_URL/VITE_WS_URL. Authenticate the browser against each isolated server using its own startup pairing URL; startup URLs and auth tokens are not part of this public package.

Wait until the authenticated app has loaded and connected before evaluating bootstrap.js (we allowed four seconds after a full reload). Applying presentation health before initial provider loading finishes can be overwritten. On a fresh empty server, evaluate `bootstrap.js`, then `setup-fixture.js` through the browser's JavaScript evaluation tool. The latter consolidates the normal project-create, import, metadata, model-selection and un-settle commands used for the captures; it must run only on a fresh synthetic environment. It deletes the other synthetic threads. The assembled fresh-server setup script was syntax checked; the independent repetition below reloads existing synthetic server state rather than recreating the database.

Open its returned route. Primary thread is the imported second transcript, renamed `Imported fixture — waiting status`, project `Synthetic import evidence`. It has two messages, no runs and no provider sessions. Imported provider binding is present in the app thread. The normal import initializes it settled, then a normal `thread.unsettle` command un-settles it. There is no watch for A12/A09. No shell injection is used for ordinary import, watch, unwatch, snooze, or acknowledgement.

An exploratory watch of the actual PR woke a different synthetic imported thread before capture and caused an unauthenticated provider start attempt. That watch was removed, the thread stopped and deleted. No accepted image or recording uses that exploratory thread or its history. The captured thread was checked to have zero runs and provider sessions. We do not claim there were no provider start attempts anywhere during exploration.

## A12: exact composer and health prerequisites

`bootstrap.js` embeds the complete `client-settings.json`, rather than relying on an operator's defaults. Critical settings: working shelf enabled, boring sidebar off, comfortable chat width, no in-app notifications, interface/prompt/code sizes 16/14/13, effort display label, no model preference overrides, rich composer on, panel animation 0, proactive panels off. All other fields are supplied too.

The isolated synthetic environment has no provider authentication. To make this a reproducible **presentation fixture**, bootstrap installs a ready/authenticated Claude provider presentation into the client atom only; it does not authenticate a CLI or send a turn. The entire descriptor is in bootstrap: enabled/installed/ready, auth authenticated, public Sonnet 4.6 model, interaction-mode toggle and context reporting enabled, reasoning options Low/Medium/High(default)/Max/Ultrathink, context 200k(default)/1M, no skills/slash commands/workspace snapshots. Call `evidence.healthFixture()` after any provider presentation refresh and just before capture. This removes the authentication banner by fixture design, not by hiding DOM or inventing credentials. The resulting composer is identical on both builds: Claude, Sonnet 4.6, 200k, Default, High, attachment/microphone/send controls.

A12 route must remain the second imported thread. Evaluate `watch-scenario.js`, call `watchEvidence.unlink()`, un-settle through the command helper, evaluate `refresh-shell.js`, then `evidence.freeze(); evidence.healthFixture()`. Open the thread details capsule above the composer; keep the separate right surface panel closed. Expand the synthetic project in the sidebar on wide web. On narrow web, keep sidebar closed, with history and composer visible. Empty composer, no selection/focus/caret, history scroll at the bottom (entire two-message history fits), no tooltip/dialog/menu. Pointer is moved off the sidebar row before every screenshot.

Set WD or WN viewport and default dark/light theme. Await fonts and app settlement, then run capture-driver.js's capture helper. Original and reload/rebuilt A12 screenshots were pixel-identical in all four checks (two builds × two profiles); `rebuild-check.json` records this. These are reload reproductions against each side's own existing synthetic server database, not a claim of a second independent fresh-database run.

## Watch: full server projection, synthetic unresolved target

Evaluate `watch-scenario.js`. `watchEvidence.set(true)` dispatches the normal `thread.pull-request.watch` server command with an unresolved synthetic host/repository/number. It persists the watch and link in the real server projection. `watchEvidence.read()` reads the fully loaded thread projection and invokes the checkout's real deriveThreadStructureRuntime; `watch-transcript.json` records zero runs/two messages/zero provider sessions, and runtime idle on both sides while watched. After unwatch, before remains idle and after becomes null. This is stronger than a shell injection, but it does not verify external forge check synchronization: the target intentionally cannot resolve. Watching the green real PR auto-woke the exploratory thread, so an ongoing real remote PR watch was not held for a stable pair.

`watchTake(side)` records normal server unwatch at about 2s, explicit refresh of the shell subscription at about 4s, then the visible transition by about 6s. The pointer is off the row. The fully loaded projection updates on command; the shell subscription required explicit refresh in this fixture. Automatic sidebar push latency is therefore unverified. The stale row tooltip from round 1 is absent. Unwatch retains the synthetic linked-PR badge in A17; unlink is a separate command used before A12.

## A13: bound provider-native child projection harness

`native-child-harness.js` uses the actual makeSubagentChildThread helper, creationSource provider, createdBy agent, parent lineage, non-null activeProviderThreadId, a Codex provider-thread binding including synthetic parent provider-session id, and a root activity with runId null/countsForRun false. Runs, attempts, messages, visible items and provider sessions are empty. This matches the empty started-activity shape in the adapter; it is not a real provider execution. The child is opened read-only, Thinking while its activity runs, then Completed in 15s. Close the thread details capsule on both sides before installing this harness. Both endpoints and their before/after zero diffs are provided. The helper reports runtime idle on before versus null on after, while native-child status remains running/completed correctly on both. Reload before leaving the harness; its visible-item overrides are not a complete application reset.

## A09: literal recording narrative

The synthetic deadline is 10:10:05 UTC; `clock-snooze.js` freezes at 10:10. Start the video with no row in the active list, then at about 2s jump the browser clock to 10:11 and explicitly refresh the shell subscription. By about 3s, before shows Working/Waiting, after shows Woke. At about 7s click the visible Dismiss button in the Woke-from-snooze footer. At about 9s, after another explicit shell refresh, after shows age 4h; before still shows Waiting. The footer is gone. End about 12s. This records the actual acknowledgement and age endpoint, not an opening gesture described as acknowledgement. It is a controlled clock/refresh fixture, not a natural wall-clock scheduling latency measurement.

## Script/tool execution

seed.py and diffs.py use Python 3; Pillow was available via `PYTHONPATH=/tmp/lead-33042-r1/evidence-capture/pylib`. Browser JavaScript files are evaluated in the authenticated real application tab; they import the checkout's Vite modules. bootstrap/watch/child code uses the observed web ports to choose its checkout path; update that two-way mapping if ports shift. capture-driver.js and scenario-driver.js are orchestration helpers for functions.exec, not standalone Node programs: set stores `root`, `tabs`, `bootstrap`, `watchScenario`, `childHarness`, `jumpClock`, `refresh` to the run path, owned tab ids and corresponding uploaded file contents; evaluate the helper declarations then call the requested scenario. Both helper files pass Node syntax checks. The archived browser-driver.js is the initial command helper; bootstrap.js supersedes it. forward.cjs was the now-stopped isolated backend proxy used only for the failed native pairing attempt.

All settled frames have a second whole-viewport screenshot taken 500ms apart; verify.py checks exact decoded pixels. Each accepted still, diff and recording was opened and inspected. Recording review contact sheets use one frame per second; full videos are also supplied. Diff0 saturates each nonzero RGB channel to 255; DiffT16 saturates each RGB channel whose absolute difference exceeds 16. Black means zero changed channels at that threshold. No cropping or alignment adjustment.

## What else changed

Within paired endpoints, C04 watch, narrow A12 and both A13 harness endpoints have zero changed pixels. Wide A12, A17 and A09 differences are confined to sidebar working-shelf membership, row placement/background and Waiting versus age/Woke text; history, composer and thread detail capsule remain identical. Between scenarios, A17 deliberately retains a synthetic linked PR badge, A12/A09 remove it, A13 replaces the ordinary imported transcript with an empty read-only synthetic child and adds a settled synthetic parent, and A09 advances the clock by 71 minutes from the ordinary 09:00 profile. These are declared scenario changes, not unexplained transcript shifts between before/after.
