# Desktop capture proof

Two isolated builds; Linux/Xvfb 1920x1080x24; Electron 44.10.1; app 1440x1000; guest 1280x800; DPR 1; dark; --no-sandbox --disable-gpu. Fresh databases, synthetic project/thread and local HTML only. No live database was copied.

The unchanged app painting decision is observed through scratch instrumentation. A loopback control endpoint invokes the real preview service/CDP session and authenticated orchestration RPC. The replay agent runs through the real provider adapter. The driver uses actual run.interrupt, not a synthetic turn-ended notification. It sends the screenshot through the existing server CDP session during the replay turn; the replay agent itself does not call the preview tool.

Both sides: ordinary screenshot control; start replay turn; hide BrowserWindow; send Page.captureScreenshot; verify native pending and isBeingCaptured=true; interrupt the running turn; await actual focus-disable delivery; restore without opening Browser panel; observe. Only after the observation, a labelled CSS rescue on base demonstrates that a paintable guest lets its pending native capture finish.

Status text is explicitly labelled instrumentation, sampled from real webContents.isBeingCaptured and host painting state. It is not a product feature. Stills are unscaled crops of the top 1440x250 region; each crop is identical across the two captures 500 ms apart (0 differing pixels). Full recordings are 1440x1000 at 10 fps. The unrelated message-sync indicator visible in the head recording is not used for the verdict.

## Observed native sequence

### before

Milliseconds relative to restoring the real app window:

```
-5710.44 {"event": "native_send", "method": "Emulation.setFocusEmulationEnabled", "F": false, "pending": 0}
-5709.70 {"event": "native_resolve", "method": "Emulation.setFocusEmulationEnabled", "F": false, "pending": 0}
-5564.26 {"event": "host_received", "type": "turn", "active": true}
-5033.11 {"event": "window_hide", "visible": false}
-5030.94 {"event": "native_send", "method": "Emulation.setFocusEmulationEnabled", "F": true, "pending": 0}
-5030.81 {"event": "P+"}
-5030.38 {"event": "native_resolve", "method": "Emulation.setFocusEmulationEnabled", "F": true, "pending": 0}
-5030.33 {"event": "native_send", "method": "Page.captureScreenshot", "format": "png", "pending": 1}
-5014.16 {"event": "renderer_apply", "views": [{"wc": 2, "x": 0, "y": 0, "width": 1280, "height": 800, "visibility": "visible", "z": "-1", "left": "0px", "top": "0px", "display": "flex"}]}
-4828.61 {"event": "host_received", "type": "turn", "active": false}
-4828.47 {"event": "P-"}
-4816.13 {"event": "renderer_apply", "views": [{"wc": 2, "x": -100000, "y": -100000, "width": 1280, "height": 800, "visibility": "hidden", "z": "-1", "left": "-100000px", "top": "-100000px", "display": "flex"}]}
-30.76 {"event": "native_send", "method": "Emulation.setFocusEmulationEnabled", "F": false, "pending": 1}
-30.12 {"event": "native_resolve", "method": "Emulation.setFocusEmulationEnabled", "F": false, "pending": 1}
+0.00 {"event": "window_restore"}
+3002.75 {"event": "observation", "label": "3 seconds after restore", "visible": true, "capturing": true, "painting": [false]}
+6319.30 {"event": "css_rescue_begin"}
+6320.52 {"event": "renderer_apply", "views": [{"wc": 2, "x": 0, "y": 0, "width": 1280, "height": 800, "visibility": "visible", "z": "-1", "left": "0px", "top": "0px", "display": "flex"}]}
+6367.14 {"event": "native_resolve", "method": "Page.captureScreenshot", "bytes": 52952, "pending": 0}
+6404.14 {"event": "renderer_apply", "views": [{"wc": 2, "x": -100000, "y": -100000, "width": 1280, "height": 800, "visibility": "hidden", "z": "-1", "left": "-100000px", "top": "-100000px", "display": "flex"}]}
+6404.90 {"event": "css_rescue_end"}
+7107.14 {"event": "observation", "label": "Native capture finished; guest returned offscreen", "visible": true, "capturing": false, "painting": [false]}
```

### after

Milliseconds relative to restoring the real app window:

```
-5726.32 {"event": "native_send", "method": "Emulation.setFocusEmulationEnabled", "F": false, "pending": 0}
-5725.67 {"event": "native_resolve", "method": "Emulation.setFocusEmulationEnabled", "F": false, "pending": 0}
-5566.98 {"event": "host_received", "type": "turn", "active": true}
-5043.80 {"event": "window_hide", "visible": false}
-5041.70 {"event": "native_send", "method": "Emulation.setFocusEmulationEnabled", "F": true, "pending": 0}
-5041.11 {"event": "native_resolve", "method": "Emulation.setFocusEmulationEnabled", "F": true, "pending": 0}
-5041.05 {"event": "P+"}
-5040.83 {"event": "native_send", "method": "Page.captureScreenshot", "format": "png", "pending": 1}
-5018.22 {"event": "renderer_apply", "views": [{"wc": 2, "x": 0, "y": 0, "width": 1280, "height": 800, "visibility": "visible", "z": "-1", "left": "0px", "top": "0px", "display": "flex"}]}
-4859.02 {"event": "host_received", "type": "turn", "active": false}
-40.65 {"event": "native_send", "method": "Emulation.setFocusEmulationEnabled", "F": false, "pending": 1}
-40.11 {"event": "native_resolve", "method": "Emulation.setFocusEmulationEnabled", "F": false, "pending": 1}
+0.00 {"event": "window_restore"}
+64.03 {"event": "native_resolve", "method": "Page.captureScreenshot", "bytes": 52952, "pending": 0}
+64.16 {"event": "P-"}
+65.66 {"event": "renderer_apply", "views": [{"wc": 2, "x": -100000, "y": -100000, "width": 1280, "height": 800, "visibility": "hidden", "z": "-1", "left": "-100000px", "top": "-100000px", "display": "flex"}]}
+3002.56 {"event": "observation", "label": "3 seconds after restore", "visible": true, "capturing": false, "painting": [false]}
+7052.48 {"event": "observation", "label": "Native capture finished; guest returned offscreen", "visible": true, "capturing": false, "painting": [false]}
```

## Re-run

Install dependencies in each checkout and build with `vp run --filter @t3tools/desktop build:bundle`. Install Electron with `node node_modules/electron/install.js` from apps/desktop if needed. Apply instrument.py and server-hook.py identically before building. Start fixture-server.py. Run launch.sh under headless-desktop with side, checkout, app port, control port, and output directory arguments (before: 42310/41980; after: 42311/41981). Set PROOF_CHECKOUT to that side’s checkout and run `python3 prove.py before` or `python3 prove.py after` in this evidence directory. The driver creates timestamped output directories. Each run requires a fresh app data directory. Never point it at live data.

The uploaded driver differs from the executed one only by replacing checkout/fixture absolute paths with parameters. The instrumentation patches show all app source changes. No tests are used as proof.

Unverified: macOS pmset Capturing assertion and actual display sleep; this Linux run shows the native Chromium capturer and completion behavior only. Relay-release and viewer-detach variants were not run in this proof.

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