# Recording rate evidence for issue 19442

Issue: [#19442](https://git.cafe/pingdotgg/t3code/issues/19442). No PR, push or forge writes performed.

## Provenance and result

Baseline [11adcb0e25](https://git.cafe/pingdotgg/t3code/commit/11adcb0e25); recorded desktop/server build [07d7b3c836](https://git.cafe/pingdotgg/t3code/commit/07d7b3c836). Frontend HMR subsequently loaded [70acaad5a8](https://git.cafe/pingdotgg/t3code/commit/70acaad5a8), whose tests/comments/compatibility exports do not change the encoder. Fixture [b66487e17c](https://git.cafe/pingdotgg/t3code/commit/b66487e17c) and linear diagnostic [3bb66f26c9](https://git.cafe/pingdotgg/t3code/commit/3bb66f26c9) were committed after capture. Parent merged main afterward; these are not recaptures of the merged build. Pass2 must independently rebuild/capture final head.

Environment: Linux x86_64 fs-39, KVM, 4 vCPU AMD family25/model1, Electron44.9.3, Xvfb1920×1080, --no-sandbox --disable-gpu, isolated .t3-desktop/.desktop-config. App shell1100×780 at410,150; one existing light theme. Actual recording content1280×800; explicitly requested throughput variant800×450. Existing parent dev runner14760/Vite localhost6720; desktop internal server14761; fixture HTTP19443. No live userdata writes. No origin overrides. Browser recordings came from agent preview_recording_start/stop through the actual isolated desktop; parent live-app preview tools were not used.

At1280×800, the setting60 after clip averages29.619fps versus20.794 before and contains37 decoded frames in a sliding second versus28 before. At800×450, setting60 averages45.542fps versus29.144 at30, with51 versus32 frames in a sliding second. These are actual decoded server artifacts, not captureStream arguments. The60 setting raises delivered cadence on this host; it is a maximum, not a constant60 guarantee. Short intervals/bursts also occur at30, so they alone do not prove a strict instantaneous cap. VM encode/CDP/JPEG roundtrip load limits throughput. Runs are sequential, not a controlled hardware benchmark; the long transition clip also overlaps desktop screen recording and Settings interaction.

## Measurements

Average is ffprobe avg_frame_rate, not nominal r_frame_rate (which reports30000/1 and is unsuitable here). Packet/frame timestamps are VFR. A half-open sliding window counts timestamps in[start,start+1). All full decode checks use passthrough with microsecond encoder timebase to avoid null-muxer rounding warnings.

| Artifact | Content | Frames | Duration seconds | Average fps | Median interval ms | Intervals below33.333ms | Peak frames/1s |
|---|---|---|---|---|---|---|---|
| after-idle.mp4 | 1280×800 | 4 | 0.310733 | 12.873 | 32.467 | 2/3 | 4 |
| after30-post-transition.mp4 | 1280×800 | 104 | 4.334933 | 24.266 | 36.833 | 41/103 | 30 |
| after30-small.mp4 | 800×450 | 121 | 4.151133 | 29.144 | 32.217 | 66/120 | 32 |
| after30.mp4 | 1280×800 | 114 | 4.419267 | 25.905 | 34.500 | 52/113 | 31 |
| after60-small.mp4 | 800×450 | 189 | 4.126333 | 45.542 | 19.767 | 171/188 | 51 |
| after60-transition.mp4 | 1280×800 | 686 | 32.678700 | 20.960 | 23.300 | 517/685 | 46 |
| after60.mp4 | 1280×800 | 130 | 4.387900 | 29.619 | 27.833 | 85/129 | 37 |
| before.mp4 | 1280×800 | 92 | 4.424333 | 20.794 | 38.333 | 33/91 | 28 |

Source RAF: initial60 capture61 intervals/1.0166s,16.666ms mean; both30 sizes60 intervals/1s; later60 sizes61 intervals/1.0166s. Source measurement is separate from encode cadence. Full timestamp arrays and histogram bins are in measurements.json; the committed probe emits all timestamps/intervals. It runs O(n) time/O(n) memory for parsed frames, assuming ffprobe's ordered timestamps. Linear peak matched the reference across all8 recordings. Malformed3000-token ffprobe JSON was rejected nonzero in0.1086s, with JSONDecodeError; no hang. No special malformed-input recovery is claimed.

Before interval bins(<16.667,16.667–25,25–33.333,33.333–50,50–100,≥100ms):1,14,18,40,14,4. After60 full size:15,41,29,29,14,1. Small30:8,12,46,47,6,1. Small60:66,59,46,16,0,1. Largest gaps before421.833ms, after60 full361.1ms. Do not infer smooth constant playback from means or these counts. Full decode succeeded without decoder errors; no separate human playback smoothness judgment was completed.

## Actual interactions and timestamps

- Reset60→30: reset60-to30.mp4 is an18s excerpt from an actual Xvfb screen recording, original source offset77s. At~10s it shows60; at~11s the reset control is clicked (23:08:14 UTC); by~16s it shows30. It is UI interaction evidence, not the encoder artifact.
- Select30→60: select30-to60.mp4 is a22s excerpt from actual Xvfb capture, source offset32s. At~10s the dropdown shows30/60; selection occurs~14.3s (23:17:36 UTC). No generated frames or synthetic pointer are substituted.
- Original60 and30 artifacts each used a four-second wait between agent start/stop. Small60 includes an actual agent click on #n; the source remains the same counter.
- Long recording started23:14:09.548 UTC. Duplicate start returned recording:true and the identical startedAt. Real setting reset at23:14:36 UTC; long artifact duration32.6787s. Subsequent new30 recording exported104frames/4.334933s. Startup-rate retention is additionally explained by the source below, not asserted from average cadence.
- Idle fixture at normal HTTP/idle.html: start23:18:21.048, stop export created23:18:21.238;4414bytes,4decodedframes,0.310733s. No artificial wait. Both tool responses isError:false. The earlier data: URL attempt was rejected and is not presented as successful evidence.

## Matrix disposition

Nine affected rows A–I; J unchanged control. Five rows have direct runtime or focused behavioral evidence(A,B,D,H,I), two have source-backed explanation only(F,G), two lack the requested live path(C,E). All nine are accounted for; this is not9/9 live verification.

- A: actual desktop setting60→agent server encoder recording, RAF, artifact dimensions/counts/timestamps and before comparison captured. Human playback smoothness judgment remains unverified.
- B: real reset60→30 and selection30→60 recorded; fresh30 and60 artifacts at matched full/small sizes captured.
- C: MISSING live browser/web reporter→server-owned page recording. Desktop and server-owned pages share the same [startRecording encoder/frame path](https://git.cafe/pingdotgg/t3code/blob/07d7b3c836/apps/server/src/preview/ServerBrowser.ts#L1474); that source fact does not replace the missing alternate-entry live check. No extra static/theme combination is needed.
- D: focused existing ServerBrowser tests passed for fresh default30, explicit30/60,60→omitted retains60,60→30 resets30. Real schema decode accepted omission/30/60 and rejected15/120/string60. Transcript attached.
- E: MISSING live disconnect/new-start and process-restart capture. [Service-local rate initializes30 and only explicit reports assign it](https://git.cafe/pingdotgg/t3code/blob/07d7b3c836/apps/server/src/preview/ServerBrowser.ts#L1319); omission retains it. This explains retention for service lifetime and reset on fresh service, with default/omission unit evidence, but socket-disconnect/restart was not exercised live.
- F: SOURCE-BACKED ONLY, no live permission/hydration transition. [Reporter](https://git.cafe/pingdotgg/t3code/blob/07d7b3c836/apps/web/src/browser/BrowserProfileReporter.tsx#L33) returns before reporting while unhydrated and skips unsupported/nonoperable environments. Those existing guards remain intact; rate is added to the same guarded report. No callback-wiring test is offered as live proof.
- G: SOURCE-BACKED ONLY, no linked-environment/reconnect/multiclient live trace. Same reporter loops destination-tagged serverConfigs; dependencies include hydration, permissions, profiles/default, recording rate and configs. Service assignment is last-explicit-report wins for future starts, environment-wide, not per tab/client. Omitted fields preserve prior explicit rate. Source explains semantics; actual multi-environment delivery is unverified.
- H: actual duplicate-start identical timestamp, change-during-recording transcript/long artifact, subsequent new30 export, and immediate idle4-frame export captured. [Source](https://git.cafe/pingdotgg/t3code/blob/07d7b3c836/apps/server/src/preview/ServerBrowser.ts#L1474) returns existing recorder before constructing another and evaluates rate once at startup; it seeds an idle frame before returning. No live internal encoder-option trace was captured during the setting change.
- I: actual generated script evaluated with fake canvas/MediaRecorder confirms1280×800/30→2.5Mbps,1280×800/60→3.072Mbps,640×400/60→floor,10000×10000/60→50Mbps ceiling. This is arithmetic evidence only; real H.264 encoding is demonstrated by A/B. No giant real capture was made.
- J: unchanged human recorder/native mobile/provider variants excluded as specified in the original matrix.

Threshold0/amplified and thresholded spatial diff images: OMITTED as not meaningful for this cadence-only change. The captures' counter epochs/phases are unsynchronized; corresponding elapsed-time frames contain different counter text. A spatial diff would measure phase/codec noise and cannot establish frame cadence. Actual recordings/timestamps are supplied instead; no screenshot substitutes for interaction evidence.

Focused validation: vp test run apps/server/src/preview/ServerBrowser.test.ts apps/server/src/preview/ServerBrowserPage.test.ts:43tests/2files passed. Fixture probe ran against real small60 artifact. Formatter and git diff --check passed at fixture commit. No repo-wide checks, no runtime pacing or encoder changes by this test agent. Only deterministic fixture/replay files committed; no media/generatedstate committed. The formatter expanded fixture whitespace; counter behavior is unchanged.

## Artifacts

Before: [before.mp4](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/73851235a4dbe4fa/before.mp4)

[after60.mp4](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/e854f5906b41d5ec/after60.mp4)
[after30.mp4](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/a314f53a8f71b51d/after30.mp4)
[after30-small.mp4](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/dac6c21d2d92a80b/after30-small.mp4)
[bitrate-proof.txt](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/843ec7cb02d61655/bitrate-proof.txt)
[schema-proof.txt](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/20e5d84b8b05fb85/schema-proof.txt)
[reporter-proof.txt](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/d6bc0009c5a4d21c/reporter-proof.txt)

[after60-small.mp4](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/1e1eb41f4647936c/after60-small.mp4)
[after60-transition.mp4](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/986777ccf5daf7c7/after60-transition.mp4)
[after30-post-transition.mp4](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/96311c5a7ae1a4bb/after30-post-transition.mp4)
[after-idle.mp4](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/7bea7525b7c10b5b/after-idle.mp4)
[reset60-to30.mp4](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/2dd04fff99e915d1/reset60-to30.mp4)
[select30-to60.mp4](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/be13ac472e4a3005/select30-to60.mp4)
[measurements.json](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/976a3a07e245fb9d/measurements.json)
[decode-check.json](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/a17183b827af6320/decode-check.json)

[runtime-transcript.txt](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/0940a87c531f0107/runtime-transcript.txt)
[decode-check-final.json](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/105b516b3cff48f0/decode-check-final.json)
[replay-probe.json](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/894d6b83eefc9f7a/replay-probe.json)


The uploaded reporter-proof.txt is an exploratory mocked-hook scratch result, not accepted live guard/environment proof; the matrix above relies on source and explicitly marks those live gaps.

## FRICTION

- infra: source HMR invalidated the old desktop webview; recordingStart timed out after15000ms and stop stalled. Closing stale tab/opening fresh recovered; no duplicate server was started. Vite binds localhost/IPv6; an IPv4-only connectivity probe initially misdiagnosed it.
- tool: data: navigation rejected by preview URL policy; ordinary HTTP idle fixture succeeded. Initial detached screen-recording attempts exited before capture and are not offered as evidence; successful Xvfb sessions supplied the reset/select clips.
- runbook: supplied audit reports missing t3code-ops/docs/EVIDENCE.md; used explicit brief/matrix and checked-in test workflow.
- brief: initial external-only fixture interpretation was corrected by explicit requirement; deterministic fixture/replay is now committed.
- policy: no forge writes/push/PR; no media or live/generated database commits. No parent servers stopped by this agent. Parent owns post-capture cleanup/rebuild.
- model: no additional runtime/code changes; requested claim is up-to60, not guaranteed constant60.

Pass2 handoff: rebuild final source SHA, use committed fixture/replay, independently recapture one matched pair, inspect delivered files and decide sufficiency of explicitly missing live rows. Parent is now handling merge/rebuild; this test agent is finished interacting with UI.
