# Pass 1: code-derived proof matrix for PR 20924

Read-only audit in `/home/ubuntu/wt/pr-20924`. No browser, tests, server, checkout, push, review comment, or watch started. Only external handoff artifacts written under `/tmp/ev-20924`. This is a capture specification, not visual approval.

Original [#20924](https://git.cafe/pingdotgg/t3code/pulls/20924), also [#20924](https://github.com/pingdotgg/t3code/pull/20924), fork [watashiwaaniket/t3code](https://github.com/watashiwaaniket/t3code), branch `fix/preview-snapshot-backdrop-filter`, original [5afb4d04](https://github.com/watashiwaaniket/t3code/commit/5afb4d04daaf16553b94e2c33e7732ddbb88ce20).
Replacement `takeover/pr-20924` [097dc0d6](https://git.cafe/pingdotgg/t3code/commit/097dc0d6c0e8441d1b2aa085d011a0e509ef26d9). Verified HEAD equals supplied SHA. Read full `git diff origin/main...HEAD`: 4 files, 138 insertions, 48 deletions. `origin/main` and merge base both [c4fa4629](https://git.cafe/pingdotgg/t3code/commit/c4fa4629eb645b95aae2beef56c70f705b736049).

## Changed paths and code basis

- [ServerBrowserPage.ts](https://git.cafe/pingdotgg/t3code/blob/097dc0d6c0e8441d1b2aa085d011a0e509ef26d9/apps/server/src/preview/ServerBrowserPage.ts): removes clip/offset/scale from captureViewport; snapshots now capture full PNG then shrink via createImageBitmap/canvas in isolated world when scale < 1. Also removes offset from readPageMetrics/renderingOf. Width cap 1280; scale=min(1,1280/(viewport.width*renderScale)). Native display branch retains ratio/zoom metrics calculation.
- [ServerBrowser.ts](https://git.cafe/pingdotgg/t3code/blob/097dc0d6c0e8441d1b2aa085d011a0e509ef26d9/apps/server/src/preview/ServerBrowser.ts): recording first JPEG (1482) and viewer pushStill JPEG (2350) call signature changes; prior scale=1 already omitted clip, so CDP screenshot options remain equivalent. Snapshot caller (1975) retains screencast pause and uses fixed RENDER_SCALE for server pages, display for attached native pages. Recording encoder and live screencast algorithm unchanged.
- [ServerBrowserPage.test.ts](https://git.cafe/pingdotgg/t3code/blob/097dc0d6c0e8441d1b2aa085d011a0e509ef26d9/apps/server/src/preview/ServerBrowserPage.test.ts): adds real Chromium helper-level 1280x800 DPR2 tests, three coarse color probes for blur and plain. These do not establish real-app integration, actual blur quality, themes, scroll, zoom, recording, or viewer recovery.
- [ServerBrowser.test.ts](https://git.cafe/pingdotgg/t3code/blob/097dc0d6c0e8441d1b2aa085d011a0e509ef26d9/apps/server/src/preview/ServerBrowser.test.ts): mock response for Runtime.callFunctionOn. No visual proof.

Surface classification: **server only**, all changed paths are under apps/server. Web Browser panel is the client used to exercise that server path; do not claim a desktop surface change merely from server native-display support. No mobile, contracts, client-runtime, or desktop files changed.

## Minimal capture matrix

Every static row: BEFORE main, AFTER replacement, independent headed Chromium/Xvfb REFERENCE. Use same Chromium build, content, geometry, media, scroll, zoom. Default height 800; scroll 0, zoom 1, server DPR2 unless overridden. Width means configured server viewport, not outer browser window. Capture returned PNG dimensions and actual innerWidth/innerHeight/devicePixelRatio/scroll coordinates in manifest. Expected dimensions below assume DPR2 native PNG dimensions match configured viewport. Values are expectations to verify, not observations.

| ID | Fixture / width / theme | Classification and expected branch | Artifact | Required judgement |
|---|---|---|---|---|
| A1 | blur / 1440 / light | Affected must capture; shrink 4/9; expected 1280x711 | Static triplet | Actual soft blur through glass, blue left/red right, no mirrored or duplicated content; geometry matches reference |
| A2 | blur / 1440 / dark | Affected must capture; same branch, different compositing | Static triplet | Dark translucent compositing and blur preserved; no mirrored duplicate |
| A3 | blur / 390 / light | Unshrunk regression control, not a claimed fix; expected 780x1600 | Static triplet | Narrow composition and blur unchanged |
| A4 | blur / 390 / dark | Unshrunk regression control | Static triplet | Narrow dark composition unchanged |
| A5 | blur / 1280 / light | Affected must capture; scale .5; expected 1280x800 | Static triplet | Exact test/reproduction width. Retain even if A1 reproduces: establishes original 1280 case |
| A6 | blur / 640 then 641 / light | 640 unshrunk control (1280x1600); 641 affected shrink (~1280x1598) | Two static triplets, settled independently | Boundary is meaningful because RENDER_SCALE=2; no sudden mirrored duplicate above threshold |
| A7 | blur / 1440 / dark; scroll 0→600, then zoom 1→1.25→1 | Affected must capture; removed document clip offsets + existing server zoom emulation | Recording plus final static PNG triplets at scroll600/zoom1.25 | Fixed glass stays anchored; document labels move correctly; no stale/wrong document region, duplicate, or zoom displacement. Record actual layout dimensions, DPR and screenshot dimensions; do not assume zoom changes configured page.viewportSize |
| C1 | plain / 1440 / light | Regression control, changed shrink implementation; expected 1280x711 | Static triplet | No geometry/color/content regression; allow resampling differences, not blind byte equality |
| C2 | plain / 390 / dark | Regression control, unshrunk | Static triplet | Content placement and dimensions unchanged |
| C3 | blur / 1440 / dark; recording start then immediate stop on idle page | Unaffected CDP options; changed recording-seed caller | Recording (before/after playable outputs, plus reference state) | First frame exists and matches page, dimensions/aspect sane; immediate stop remains encodable |
| C4 | blur / 1440 / dark; viewer attached, snapshot during recording, scroll and settle/reconnect | Unaffected full-size JPEG caller; pause/resume and viewer still control | External recording of Browser panel before/after; retain internal recording too | No flash/mirror frame introduced to viewers, playback resumes, settled viewer frame is correct. Internal recording alone cannot prove viewer behavior |
| N1 | native attached page / measured display DPR and zoom | Conditional server path; display ratio/zoom and removed offset touched | NOT required in this server-only pass; record as unverified | Server-owned headless page cannot exercise renderScale='display'. A genuine native attachment is needed, not pretending numeric scale=display or inferring desktop coverage |

No Cartesian product of all themes, widths, zooms, scroll offsets and callers: A1-A6 cover visible branch/theme/width distinctions, A7 covers interactions, C1-C4 cover regressions. No separate color picker state: RGB bands, white/yellow high-frequency features, translucent light/dark background cover color and actual blur. Each width/theme settles before static capture; any demonstrated transition or timing claim requires a recording. A7/C4 can share one controlled interaction session but retain their distinct assertions and artifacts. An unchanged before image at a control row is expected, not a failed reproduction.

## Capturer route: actual app, fresh synthetic state

1. Use only authorized worktree and supplied revisions. Auditor has not switched it. Capturer must stop only its own retained PIDs before switching. Capture main c4fa4629 first, then 097dc0d6. No edits to source to force a launch mode or inject a component harness.
2. Start actual dev server with `T3CODE_DEV_SEED=0 vp run dev --home-dir /tmp/ev-20924 --no-seed`. Database must be fresh per revision. Store before userdata in a capturer-owned archive and create fresh after state; preserve evidence files. Do not read/copy/write `~/.t3/userdata`; do not run migrate-dev-db. Read actual ports from dev-runner. Do not set VITE_HTTP_URL/VITE_WS_URL. Never publish pairing links, cookies, tokens, profiles, or private app data.
3. Seed through actual app: pair a headed Chromium/Xvfb client using this dev server's startup URL, create a synthetic project pointing at `/tmp/ev-20924/pages`, then a stopped empty thread via app UI. This invokes production project/thread services with no provider turn required. This is the simplest viable route from a fresh DB; no DB transplant needed. RPC alternative uses real project service and `thread.create` command, followed by preview.open/preview.navigate and preview.resize/preview.adjust; payloads must follow this revision's contracts and authenticated RPC transport. Do not invent a WebSocket JSON protocol.
4. Run the public fixture generator into `/tmp/ev-20924/pages`, serve its directory via a separate capturer-owned loopback HTTP server, and navigate the thread's real Browser panel to `/blur.html` or `/plain.html`. This is an external website fixture, not an isolated component harness. The actual server ServerBrowser must own the tab. Use fixed viewport settings and explicit preview colorScheme. ServerBrowserContexts deliberately launches its capture Chromium headless with DPR2; leave this production behavior intact.
5. Obtain PNG through this new dev server's real preview automation snapshot service (the Browser screenshot shown by a separate automation browser is not sufficient). A valid thread-bound MCP invocation can call preview_status/open/navigate/resize/set_appearance/snapshot(save=true); credentials/session must belong to the fresh dev server, not this audit's live environment. Concrete supported MCP route: start a tightly scoped provider turn in that synthetic thread from the paired client, instruct it to capture only these local fixture pages, and let the real provider launch issue its thread-bound MCP registry credential. The child then calls the fresh server preview tools. This is later capturer work, not delegation performed by this audit. An empty stopped thread alone does not issue this credential; a generic OAuth MCP client also lacks the required thread scope (McpInvocationContext.requireThreadMcpCapability). Provider access is therefore a prerequisite for this supported route; if unavailable, mark capture blocked rather than inventing a credential or assuming preview.open RPC provides snapshot RPC. The transport and auth prerequisite must be resolved, not bypassed by directly importing ServerBrowserPage.snapshot. A stale MCP connection to another running server invalidates the evidence.
6. Reference: separate **headed** Chromium on Xvfb, same fixture, browser build, viewport/layout, media, effective DPR/zoom and scroll. Take an unscaled native capture (no CDP clip.scale<1), then if needed normalize offline to the returned snapshot dimensions. Preserve original reference PNG and normalization command. Compare the actual backdrop blur over stripe edges, not just the three coarse RGB samples. Server browser being headless and reference being headed is intentional. Record Xvfb size/depth and versions.
7. Save manifest containing revision SHA, fixture script URL+hash, page hash, server command/ports with credentials redacted, snapshot route, dimensions, media, scroll, zoom, DPR, and reference command. Upload PNGs and videos with ghdrop. Label BEFORE / AFTER / REFERENCE. No visual claim is approved until reviewed.

If step 5 cannot create valid fresh app automation scope, report integration capture blocked; helper-level tests or a standalone Playwright call to ServerBrowserPage are not substitutes. If headed Xvfb/Chromium is unavailable, record the reference gap. N1 is explicitly not captured by this setup. No screenshots or recordings produced in pass1.

## Test status and later independent audit

Tests/main red is confirmed input to this pass and remains outstanding, **not superseded** by the matrix, new tests, or an eventual visual pass. Auditor did not rerun tests and makes no claim about which checks or failures were observed. Preserve exact failure logs from the owner separately. This pass does not grant merge readiness.

Pass2 must be a new delegated audit. Rebuild one chosen row from the publicly uploaded external fixture script, independently verify script hash and resulting page, and follow the actual dev-server route. Scratch scripts stay under /tmp, never committed even if another brief requests a committed reproducer.

## FRICTION

| category | event | prevention |
|---|---|---|
| Scope | Four server files can be mistaken for a desktop UI change | Classify from changed paths; N1 remains a conditional server path, no inferred desktop claim |
| Coverage | 390 does not enter the new shrink path; 640 is exact threshold | Retain 390 as control and 640/641 boundary, explicitly mark affected rows |
| Proof | RGB probes detect gross mirroring but not actual blur | Compare detailed stripe edges to headed reference and preserve full images |
| Integration | Existing live MCP could silently capture a different server | Bind fresh project/thread and credentials to logged dev ports and revision |
| State | Default dev seeding could access real userdata | Explicit home, --no-seed and T3CODE_DEV_SEED=0; never migrate/copy live state |
| Timing | Static PNG cannot prove recording seed or viewer recovery | C3/C4 and interaction A7 require recordings |
| Reproducibility | Committed scratch script conflicts with user instruction | Publish synthetic generator from /tmp via ghdrop; record hash; pass2 rebuilds independently |
| Validation | Visual evidence might be treated as clearing red tests | Carry tests/main red forward as unresolved, with original logs retained separately |

Public synthetic generator: [fixture-20924.py](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/49cbb14fa7a8aab3/fixture-20924.py). SHA-256 `1abdeee1085e1e3bd5b5280b756bb2f67d9e370410bb374442c36cb86c4eb82d`. Generator does not launch anything. Auditor did not execute it.


## Supplemental pass 1 — N1 and RM only, replacement PR

Read-only code audit of [#24618](https://git.cafe/pingdotgg/t3code/pulls/24618) at [b7fddd87](https://git.cafe/pingdotgg/t3code/commit/b7fddd87a69bb9f868bfd54928aaf4ae881c9432). Existing matrix above is preserved verbatim, including its historical revision/test statements; this appendix supersedes only its N1 capture exemption and supplies RM. No captures, servers, browser launches, tests, source edits, PR edits or watches performed. Checkout clean. Disk available about 10 GiB; capturer must stop below 5 GB. No live userdata accessed. These are outstanding proof requirements, not PASS results.

| ID | Required fixture/state | Actual production path | Evidence still required |
|---|---|---|---|
| N1 | Genuine Electron guest, blur stripes/glass, native display scale measured; scroll 600; zoom 1 and 1.25; width large enough to enter shrink | Desktop guest attached event → bootstrap FD CDP relay → ServerBrowser tab.desktop → snapshot renderScale="display" | BEFORE/AFTER actual server snapshot PNGs plus independent matching headed reference; native attachment provenance and metrics; compare blur, offsets, dimensions and zoom. UNCAPTURED |
| RM | CSS animation over/behind glass with explicit prefers-reduced-motion rule; no-preference positive control and reduce state | CDP Emulation.setEmulatedMedia on the actual target; actual server snapshot service afterward | BEFORE/AFTER server PNGs under reduce, matching headed reference; media/computed-style/animation evidence showing animation runs normally and stops under reduce. UNCAPTURED |

### N1 definition and platform paths

Code basis at audited head: `apps/desktop/src/preview/Manager.ts:2380` restoreControlSession attaches the real guest's existing debugger through browserHost.attach when serverTab exists. `DesktopBrowserHost.ts:184` emits attached; backend bootstrap uses descriptors 6/7 (`backend/DesktopBackendConfiguration.ts:529`), `apps/server/src/preview/DesktopBrowserChannel.ts` creates the per-tab loopback WebSocket and forwards CDP through those descriptors. `ServerBrowser.ts:686-714` awaits that specific thread/tab attachment and connects via `ServerBrowserContexts.connectDesktopPage`; snapshot at line 1977 selects display only for tab.desktop. `ServerBrowserPage.ts:435-460,526-540` reads isolated-world DPR, inner dimensions and Page.getLayoutMetrics zoom; renderScale=ratio/zoom and viewport=round(inner size*zoom). Preserve those measured values, not assumptions about screen DPI.

This path is shared on macOS, Windows and Linux; no Darwin-only gate controls the attachment. OS display scale and native Electron page zoom are relevant on all three. Linux Xvfb supplies a virtual X display to a real headed Electron app and therefore can exercise this production attachment. It does not prove macOS/Windows behavior or a physical monitor. An arbitrary headed Chromium page, even connected over CDP, is not this native attachment: there is no public endpoint-registration API substituting it for DesktopBrowserChannel. Plain server pages remain headless with fixed DPR2 (`ServerBrowserContexts.launchOptions/createContext`), regardless of whether their viewer is headed. There is no repository `headless-desktop` launch mode; do not invent that flag or call Chromium --headless a native display.

### Concrete Linux driving route for later authorized capture

1. Use the same baseline already evidenced, [c4fa4629](https://git.cafe/pingdotgg/t3code/commit/c4fa4629eb645b95aae2beef56c70f705b736049), and audited after head. Separate fresh homes below /tmp/ev-24618; no migration or live state. Start a capturer-owned Xvfb (for example `Xvfb :97 -screen 0 1920x1200x24 -nolisten tcp`) and retain its PID. Use DISPLAY=:97 throughout. Record actual display geometry, Chromium/Electron versions and scale.
2. Production desktop route is `T3CODE_DEV_SEED=0 DISPLAY=:97 vp run dev:desktop --home-dir /tmp/ev-24618/n1-after-home --no-seed` (separate baseline home on before). This launches Electron and its own backend; do not launch an unrelated web server and claim its headless page is native. Create synthetic project/stopped thread and open Browser panel in the desktop renderer so its real webview is registered. A normal desktop server connection/provider turn supplies thread-bound MCP capability as in original route; use that backend's scope and explicit tabId. Do not consume the live environment's MCP scope.
3. For a programmable main-process driver, use the existing `@t3tools/desktop dev:bundle` task (build/watch only, no auto-launch), matching web dev origin from dev-runner, then external Playwright `_electron.launch({executablePath:<resolved Electron runtime>,args:[<absolute apps/desktop/dist-electron/main.cjs>],env:{...process.env,DISPLAY:':97',T3CODE_HOME:<fresh home>,T3CODE_DEV_SEED:'0',VITE_DEV_SERVER_URL:<actual loopback Vite origin>}})`. Prepare browser secret/annotation CSS with the existing bundle task; build the server dependency with existing build tasks. This replaces the auto-launched Electron, never launches a second against its home. No source patch or mock relay. Keep launcher handles/PIDs. Drive renderer UI with the Electron application's window, and inspect guest webContents from Electron main via application.evaluate. Log its URL/id, type webview, server thread/tab identity and attachment/CDP traffic without secrets. Prove snapshot travels through that guest's debugger (e.g. collect Page.captureScreenshot event/command trace in external driver), rather than merely logging a headed client.
4. Set native page zoom with the actual desktop zoom control (or guest.setZoomFactor in main for controlled setup), scroll fixture, settle and record DPR/inner dimensions/scroll plus CDP Page.getLayoutMetrics. Capture using fresh thread-bound preview_snapshot(save=true, tabId=<native tab>) through ServerBrowser. Native guest capturePage or external Playwright screenshot is reference/provenance only, not the required snapshot output. A server fallback after attachment timeout invalidates N1.
5. Preserve PNGs, raw/reference normalized images, diffs, fixture hash, commands, trace and dimensions. Reference must match effective layout/zoom/scale and Chromium build; use an unscaled headed capture before offline normalization. Report Linux virtual-display evidence explicitly. Stop only captured PIDs. If desktop cannot build/attach, report that precise prerequisite; plain Chromium under Xvfb remains reference-only.

### RM API absence and usable CDP route

Public contracts `packages/contracts/src/previewAutomation.ts` operation list and MCP `preview_set_appearance` expose colorScheme only. `ServerBrowser.ts:650-653,1965-1971` calls page.emulateMedia with colorScheme only. There is no reducedMotion input, generic CDP automation operation, or HTTP reduced-motion route. `preview_evaluate` evaluates JavaScript in the target page through Runtime.evaluate (`ServerBrowserPage.evaluate`); page JS cannot issue browser CDP Emulation commands. A matchMedia stub or injected override of its return value is invalid proof. The production headless browser launch has neither a remote-debugging port nor an exposed CDP WebSocket; do not presume an externally connectable port exists.

This does NOT make actual server snapshot RM proof impossible. Use the genuine Electron route above and its existing debugger. In external Electron main evaluation, select the unique synthetic fixture guest by URL/id, require wc.debugger.isAttached() (do not detach or attach a competing debugger), and call:

```js
await wc.debugger.sendCommand('Emulation.setEmulatedMedia', {
  features: [
    {name:'prefers-color-scheme', value:'light'},
    {name:'prefers-reduced-motion', value:'reduce'}
  ]
});
```

`DesktopBrowserHost.relayFor` → `CdpRelay.pageCommand` → `GuestInput.sendPageCommand` forwards Emulation.setEmulatedMedia to that same debugger; it is not filtered. Electron main access is an external fixture driver, not a shipped preview API. Set appearance first, then media; desktop applyColorScheme/restoreControlSession replaces the features array and may clear RM on appearance change or debugger reattach. Reapply after reattach and verify matchMedia immediately before every server snapshot. A second client must not connect to the private one-client relay endpoint. Save only redacted command/results. Use value 'no-preference' for positive control, then 'reduce'; do not merely change fixture CSS to force a reduced state.

External synthetic fixture should add, for example:

```css
@keyframes stripes-move { from { transform: translateX(0); } to { transform: translateX(80px); } }
.stripes { animation: stripes-move 1s linear infinite alternate; }
@media (prefers-reduced-motion: reduce) { .stripes { animation: none; transform: translateX(0); } }
```

Keep a fixed glass overlay above the moving high-frequency stripes. Preserve generator/page hashes. Under no-preference record matchMedia false, computed animationName and transform at two distinct animation frames (or animation currentTime progression); this establishes genuine activity. Under reduce require matchMedia true, computed animationName none, no running stripe animation and stable transform. Obtain actual server snapshot BEFORE and AFTER under reduce at identical width/theme/zoom/scroll/DPR, plus matching headed reference and repeat stable capture. Keep no-preference snapshots or short recording as positive control; uncontrolled animated frames cannot be compared pixel-for-pixel. This tests server snapshot behavior under real media emulation using a native attached page, and does not claim a new public server RM API or headless RM configuration feature.
