# Proof audit pass 2: PR #23601 (head `fc736575`)

Read-only. Uploads were downloaded into the empty dir `/tmp/ev-23601/audit2-dl/` and extracted there. They were treated as data: nothing was executed. My own recompute script is in `/tmp/ev-23601/audit2-scripts/` and was run with `python3 -I`.

## Integrity and SHAs

- **Driver tarball.** sha256 `ce5a568d…3e1253a` matches the claimed hash. `driver/driver.mjs` hashes to `f4b30c95…a9eea`, also matching captures.md.
- **Uploads vs local copies.** The uploaded `captures.md` and all 39 files in `ev-23601-data.tgz` are byte-identical to the local copies in `/tmp/ev-23601/`.
- **after = `fc736575710b`.** That is the checkout's `HEAD` and the PR head.
- **before = `8d3b061121`.**
  - It is an ancestor of the head. It is also an ancestor of `origin/main` (`f054d1b801`), which is **2 commits ahead** ([ed3f965e07](https://github.com/pingdotgg/t3code/commit/ed3f965e07) CI setup yaml, [f054d1b801](https://github.com/pingdotgg/t3code/commit/f054d1b801) mobile/web message timeline). Neither of those touches topology, IPC, preload or connection files.
  - `git diff 8d3b061121 fc736575` is exactly the PR's 8 files plus `.github/actions/setup-ci-deps/action.yml`. So the before/after comparison isolates the PR. This fixes audit 1's stale-baseline problem, where the old baseline `07d38b8d17` was 951 commits behind.
  - Caveat: the before worktree (`~/wt/pr-23601-before`) has since been removed, and no build or electron log prints a SHA. The before SHA rests on the `git rev-parse` line in captures.md and on the driver's hard-coded worktree path. The after SHA can be checked directly.

## Driver vs claims (skimmed `driver.mjs`)

| Claim | Driver | OK |
|---|---|---|
| busy = 1 s block every 3 s, random phase | L250 `setInterval(() => { spin 1000 ms }, 3000)` injected into main via inspector, started whenever the run starts | ✓ |
| aligned extra | L253-258: first block 300 ms before the next predicted poll (from `__evTopo` timestamps), then every 3 s | ✓ |
| 300 keys @ 40 ms, new empty chat | L242 `location.hash = "#/draft/" + randomUUID()`, L265-273 300 × `Input.dispatchKeyEvent` down/up, paced to `tStart + (i+1)*40`; typedChars recorded | ✓ |
| renderer CPU profile 500 µs, sendSync attribution | L260 `setSamplingInterval 500`; sendSync = samples with a `sendSync` frame on the stack | ✓ |
| R1 injects at main's source of truth | L77-91 `Runtime.queryObjects(Map.prototype)` → the Map whose `primary` entry is `{_tag:"Active", instance.currentConfig}`; L136-140 `set("probe-secondary", …)`; removal via `delete`. Neither IPC handler is touched (the handlers are only wrapped by pass-through counters, L349-366) | ✓ |
| R2 makes the async invoke handler reject | L204-209 `ipcMain.removeHandler(CH)`, `ipcMain.handle(CH, () => { throw })`; restored from `_invokeHandlers` (L219-220). The sync `ipcMain.on` handler is untouched | ✓ |

Driver caveats:
- **The published driver is the final revision.** The before idle/busy runs (12:49–12:50) predate its mtime (12:51:54). The documented difference is the one-observer-per-page guard on the long-task observer. The run numbering (`-1`…`-5`) was applied outside the driver, which always writes `r3-<variant>-<mode>.json`. Both are disclosed in deviations 2–3.
- **The primary-relabel probe is not in the driver.** It was presumably an ad-hoc `main <expr>`, and no raw log for it is in the data tarball.

## Row by row

| Row | Status | Evidence (raw file → value) | SHAs | Numbers match? |
|---|---|---|---|---|
| **R0** startup with existing seeded state | **COVERED** | Before and after `*-r0-newchat.png`: the same seeded thread list, a new chat, and no offline banner, so the screenshots are visually identical (expected, since there's no UI change). Startup IPC: `topo-before-startup.json` has 10 sync in the first 10 s (+0/408/431/1129, then 2 per poll). `topo-after-startup.json` has 1 sync plus 4 invoke (+280/3444/6448/9451). The R3 session `topo-after-r3.json` has 1 sync / 34 invoke over 103 s. | before `8d3b061121`, after `fc736575` | ✓ captures' "+273/280" merges two after sessions (R3 session 273, R1/R2 session 280). Fine. |
| **R1** topology add/remove within one poll | **COVERED** (caveats) | `r1-before.json`: first renderer sync read after add/remove at 2269 / 2496 / 677 / 2485 ms. `r1-after.json`: first invoke at 2518 / 2481 / 678 / 2481 ms, and the bridge cache reflects the change at 2535 / 2501 / 692 / 2489 ms (8–20 ms after that poll's invoke). Logs show the primary stays at `http://127.0.0.1:3774/`, `/.well-known` returns 200, and ids return to `["primary"]`. | both | ✓ exact |
| **R2** failed refresh keeps the snapshot | **COVERED** (after only; correctly N/A on before) | `r2-after.json`: 5 rejections at +502/3505/6508/9511/12514 ms, so the poll keeps running at its ~3 s cadence while failing. All 13 samples (+3…+12079 ms) keep `[primary, probe-secondary]` with `online(no banner)`. Restore came at +13089 ms, and the removal was applied 2472 ms after restore. `r2-before.log`: `refreshLocalEnvironmentBootstraps` is absent. | after | ✓ exact |
| **R3** typing, idle and busy, plus aligned | **COVERED** | All 13 recorded JSONs plus the 1 transcribed JSON match the captures table. I recomputed sendSync total and longest from the 13 cpuprofiles and got identical values. Before: idle 11.2/2.9; busy 332.6/314/[317] (transcribed), 19.5, 19.2, 14.0, 34.7; aligned 1718.7/1009.9 and 1708.1/999.9, with callers `getLocalEnvironmentEnabled@preload.cjs:320` (~1698 ms) and `…Bootstraps@preload.cjs:314`. After: sendSync 0 in all 6 runs, `sendSyncCallers {}`. Every run typed 300/300 chars. | both | ✓. Aligned long-task arrays hold 7× / 8× duplicates (`1005`×7, `702`×7; `1000`×8, `702`×8). De-duplicated they are 1005,702 and 1000,702, as captures states. The duplicate counts match the 7th/8th-run explanation. |

R1 caveats:
- R1 observes the preload bridge cache, not a rendered UI. The URL-less secondary never appears in the DOM (deviation 6).
- The web layer consumes that cache in the same poll. This is visible in the code rather than the run: `platform.ts:646-647` awaits `refreshDesktopSecondaryBootstraps` before `readPrimaryEnvironmentTargetResult()`, which is exactly the ordering #22222 lacked. The unit tests cover the web reader.
- The primary-field change (relabel reaching the cached primary entry in ≤ 2490 ms) is after-only and has no raw data. Only its mechanism is shared with the secondary test, which has raw data. Treat the relabel number as a claim.

### Busy rerun vs the PR body table

| | body (old baseline `07d38b8d17`) | new random-phase busy, before (5 runs) | new aligned, before | after (all runs) |
|---|---|---|---|---|
| sendSync sampled | 888 ms | 332.6 / 19.5 / 19.2 / 14.0 / 34.7 | 1718.7 / 1708.1 | 0 |
| longest sendSync | 428 ms | 314 / 6.3 / 12.2 / 4.6 / 20.1 | 1009.9 / 999.9 | 0 |
| long tasks > 200 | 885, 554, 476, 464, 350 | 317 / – / – / – / – | 1005, 702 / 1000, 702 | none, except one 569 (busy #3, 0 sendSync) |

**Does it corroborate?** Qualitatively, yes:
- Same mechanism: the renderer parks in `sendSync` from the same two preload frames.
- It happens only on before.
- It goes to zero on after under both injector modes.

Quantitatively, the body's single busy run is not reproduced as such:
- Random-phase reproduction is weaker: 1 of 5 runs, 317 ms.
- Phase-aligned reproduction is stronger: about 1 s freezes in 2/2 runs.
- The body's idle long tasks (228, 216) didn't recur: the new idle run has none.

The body table is from a different and stale baseline and should be replaced by the new table. Its prose errors from audit 1 also remain ("froze inside `sendSync` for up to 885 ms", and the p99 "~1.06 s both" while the old data had 1167 vs 1064). Neither is an evidence gap, but the body should be updated before merge.

**Why random phase reproduces only 1 of 5.**
- The injector period (3000 ms) and the poll period (~3003 ms per `topo-*.json`) are effectively equal. Each run's relative phase is fixed by its start time, so a poll's `sendSync` only stalls if it falls inside the 1 s block. The naive hit rate per run is ~1/3, and 1 of 5 is well within chance (P(≤1 hit of 5) ≈ 0.46).
- A nuance in captures' "each run either overlaps every poll or none": busy #1 shows a single 317 ms freeze over ~12 s (~4 polls), and the aligned runs show two freezes (1005 then 702), not one per poll. So a hit doesn't persist for every poll. A plausible reason is that the stalled read delays the subsequent poll or composer read by the stall, moving it out of phase. I didn't verify that.
- This doesn't change the conclusion: the aligned runs remove the phase dependence and hit 2/2 on before, 0/2 on after.

## Disclosed caveats (verified as stated)

1. **before busy #1 is transcribed.** `r3-before-busy-1.json` carries an explicit `note` field. It has no cpuprofile (overwritten) and its mtime is 12:54, after the runs. It is the only random-phase hit, so that one data point is console-transcribed. The aligned runs, which have raw profiles, carry the before freeze independently.
2. **The first R1 run was discarded.** Its aliasing clone of the primary caused a "did not accept this device" offline banner, which a fresh launch with R1 alone reproduced. The reported R1/R2/R3 numbers come from sessions using the non-aliasing secondary. The topo session spans (`after-end` 135 s vs `after-r3` 103 s, with different first-call offsets) confirm R3-after ran in its own launch. The discarded data is not in the tarball, so I can't independently confirm the attribution to the injection. It is plausible, because the clone shared the primary's URL and auth.
3. **The after busy #3 569 ms long task.**
   - It has 0 sendSync.
   - I recomputed its busiest contiguous non-idle stretch at 420.9 ms: 234.5 ms GC and 177.0 ms in `ComposerPromptEditor dispatchTransaction`, as claimed.
   - The remaining ~150 ms of the 569 ms task isn't in JS samples (likely layout/paint), so the GC/editor attribution covers the JS portion only.
   - It is not topology IPC. It is a keystroke burst after a main stall, which the PR does not claim to fix.
4. **Keystroke p99 is ~1 s on both builds under a busy main.** Input goes through the main thread. This is consistent across all busy and aligned runs (993–1012 ms).
5. **The R2 earlier run** (4 rejections, 1000 ms recovery) and the **primary relabel** are claims without raw files.

## Unverified (known limitation, not verdict-affecting)

- Windows (the reporters' platform), macOS desktop, and a real WSL secondary appearing or disappearing mid-session. These are covered only by the unit tests and the shared preload/web code paths. Linux/Xvfb with `--disable-gpu` was the only real build.

## Summary

All four rows now have SHA-pinned, real-build before/after evidence, from a published, hash-verified driver whose raw data reproduces every number in captures.md. Audit 1's gaps are closed:
- Row 1/2 (stale baseline, no after SHA): closed by `8d3b061121` vs `fc736575`, which differ only by the PR.
- Row 3 (topology never run on a real build): closed by R1.
- Row 5 (no before startup check): closed by R0 before screenshot plus startup IPC counts.
- Driver unpublished: closed; the driver is now published with a matching hash.

Remaining weaknesses are disclosed and minor: the random-phase before hit is transcribed, the relabel and earlier-R2 runs have no raw data, and DOM-level topology uptake isn't shown. Action for the author: replace the PR body's verification table and SHAs with the new captures and fix the two prose errors noted above.

VERDICT: SUFFICIENT
