Issue 24280 runtime evidence (server-only; visual matrix empty) Worktree: /home/ubuntu/wt/issue-24280 Patched head: 72f0858bfd2a7c213fd0e48949981335fe4510d3 Main baseline: 27e0c684c585 (lead-provided before transcript) Existing primary dev server: vp run dev; web 7466; server 15506. Reused it; never started or stopped a dev server. No repository edits/commits/pushes/PR writes. No live ~/.t3/userdata access. Only isolated dev-session changes. BEFORE (verbatim lead-provided transcript) Issue 24280 main reproduction, fs-08 Linux, Chromium through T3 preview. Main commit: 27e0c684c585 (2026-10-24). Reporter script run with node in apps/server after vp install: unwrapped socket: httpEffect exit = Success | observed = {} wrapped reader: httpEffect exit = Success | observed = {"code":4001,"reason":"client heartbeat timeout"} Real app: vp run dev, isolated worktree .t3. Browser paired on localhost:7466. Browser evaluated new WebSocket(ws://${location.host}/ws?orchestrationProtocol=2), onopen -> close(4001, 'client heartbeat timeout'), awaited onclose. Browser result: {"code":4001,"reason":"client heartbeat timeout","wasClean":true} Server output for that socket: [09:58:20.240] INFO (#8153) http.span=19ms: Sent HTTP response http.method: GET http.url: /ws http.status: 101 No WebSocket closed or code/reason line appeared. Red commit: 132f0b60c0. vp test run src/ws.test.ts (apps/server): 1 failed, 6 passed. 'logs the close code and reason when a client closes /ws' AssertionError: expected '[]' to include '4001' src/ws.test.ts:599:12 PATCHED: pairing T3 preview_status({}) -> available:false. T3 preview_open({reuseExistingTab:false}) -> available:true, agent-owned tab. Read pairingUrl from private /tmp/issue-24280/patched-server.log, then preview_navigate({tabId:,url:}) -> success. The URL/token is deliberately excluded. App /api/auth/session -> authenticated:true. PATCHED SCENARIO 1: authenticated RPC, close frame Exact JavaScript: browser-fixtures.mjs export closeFrame, run via preview_evaluate with awaitPromise:true in paired browser on localhost:7466. Output: {"validRpcResponse":true,"code":4001,"reason":"client heartbeat timeout","wasClean":true} Server output (exact selected record; exactly one record with marker appVersion): [10:08:58.049] INFO (#8234) http.span=79ms: WebSocket closed { endedBy: 'close_frame', closeCode: 4001, closeReason: 'client heartbeat timeout', durationMs: 76, lastInboundAgeMs: 60, sessionId: '87f0f02f-6ac5-4ffa-9a62-8148e49b1123', surface: 'web', appVersion: 'issue24280-evidence-close', remoteAddress: '127.0.0.1' } PATCHED SCENARIO 2: authenticated RPC, abrupt TCP loss Final fixture command: node /tmp/issue-24280/tcp-relay.mjs Output: owned relay pid=1752175 localhost:17466 -> Vite:7466 Exact JavaScript: browser-fixtures.mjs export abruptTransport via preview_evaluate. Output: {"validRpcResponse":true,"transport":"owned TCP relay -> Vite -> primary server"} Command: kill -USR1 1752175 Relay output: severing 1 TCP pair(s), no WebSocket close frame Exact JavaScript: browser-fixtures.mjs export readAbruptClose via preview_evaluate. Output: {"code":1006,"reason":"","wasClean":false} Server output (exact selected record; exactly one record with marker appVersion): [10:09:43.304] INFO (#8747) http.span=224ms: WebSocket closed { endedBy: 'connection_lost', closeCode: 1006, durationMs: 211, lastInboundAgeMs: 184, sessionId: '87f0f02f-6ac5-4ffa-9a62-8148e49b1123', surface: 'web', appVersion: 'issue24280-evidence-loss', remoteAddress: '127.0.0.1' } PATCHED SCENARIO 3: session invalidated In original paired administrator tab: POST /api/auth/pairing-token with JSON {"label":"issue24280-disposable-invalidation"} Output: status 200; credential held privately, excluded from transcript. preview_open({reuseExistingTab:false,profileId:"incognito"}) -> available:true. preview_navigate to localhost:7466/pair with that private credential -> success. GET /api/auth/session in incognito -> {"authenticated":true} Exact JavaScript: browser-fixtures.mjs export invalidationSocket via preview_evaluate. Output: {"validRpcResponse":true} GET /api/auth/clients in administrator tab, filter label for disposable session: Output: [{"sessionId":"abf8fff7-5fea-4939-8b1c-1fc74ece7434","current":false}] Exact JavaScript: browser-fixtures.mjs export revokeDisposableSession via preview_evaluate. Output: {"status":200,"result":{"revoked":true}} Exact JavaScript: browser-fixtures.mjs export readInvalidatedClose via preview_evaluate. Output: {"code":1000,"reason":"","wasClean":true} Server output (exact selected record; exactly one record with marker appVersion): [10:10:22.352] INFO (#9248) http.span=3505ms: WebSocket closed { endedBy: 'session_invalidated', durationMs: 3502, lastInboundAgeMs: 3492, sessionId: 'abf8fff7-5fea-4939-8b1c-1fc74ece7434', surface: 'web', appVersion: 'issue24280-evidence-invalidated', remoteAddress: '127.0.0.1' } COUNT VERIFICATION Python re.findall(r'^\[[^\n]*WebSocket closed\n \{.*?\n \}', server_log, re.M|re.S), filtered by each appVersion marker: close=1, loss=1, invalidated=1. A valid response means a Chunk carrying the matching requestId from subscribeServerConfig. Response payloads were intentionally not retained because they contain private configuration. The sessionId UUIDs above identify sessions, not credentials. CLEANUP Command: kill -TERM 1752175 Owned relay stopped. Earlier captured fixture PIDs 1751206 and 1752061 also stopped. Primary dev server remains running; original paired tab retained. Disposable session revoked; incognito tab closed after capture. MISSING ROWS Server shutdown captured below by primary owner using its retained terminal session. Visual matrix: empty; proof auditor confirmed no render changes; no screenshots required. FRICTION Initial shell-background relay exited with its shell before readiness; no successful exchange. Tracked terminal relay first targeted IPv4 but Vite listens only on [::1]:7466. Failed browser attempts returned 'Preview automation evaluate failed: Error: WebSocket error'. Diagnostic command: ss -H -ltnp 'sport = :7466' Relevant output: LISTEN ... [::1]:7466 ... Diagnostic command: curl -sS --max-time 3 http://127.0.0.1:7466/ -o /dev/null Output: curl: (7) Failed to connect to 127.0.0.1 port 7466 ... Couldn't connect to server Corrected owned relay to target ::1; final successful run shown above. No ws package resolves from apps/server (MODULE_NOT_FOUND); used paired incognito browser instead. No other browser automation system, CDP, private payload capture, or raw server-log upload used. Additional exact HTTP evaluator expressions are in browser-fixtures.mjs: mintDisposableCredential, checkAuthenticated, findDisposableSession. Attempted cleanup POST /api/auth/pairing-links/revoke for the consumed disposable pairing id returned status 200, {"revoked":false}; the single-use credential had already been consumed. No credential is included in the safe artifacts. Final git status showed modifications in WsConnectionLog.test.ts and ws.test.ts owned by other ongoing work; this evidence capture did not edit either file. PRIMARY SHUTDOWN (Ctrl-C retained exec session32172, vp run dev, at10:10:54) Two normal app connections were open; each emitted one record with its own request fiber: [10:10:54.176] INFO (#7624) http.span=3181ms: WebSocket closed { endedBy: 'server_interrupted', durationMs: 3177, lastInboundAgeMs: 1265, sessionId: '87f0f02f-6ac5-4ffa-9a62-8148e49b1123', surface: 'web', appVersion: '0.1.2', remoteAddress: '127.0.0.1' } [10:10:54.178] INFO (#7018) http.span=8525ms: WebSocket closed { endedBy: 'server_interrupted', durationMs: 8512, lastInboundAgeMs: 3529, sessionId: 'f67431ba-ccfe-4f9c-b39e-d1acce873ad9', surface: 'web', appVersion: '0.1.2', remoteAddress: '127.0.0.1' }