test(cmux-next): --record-launch records every launch window from its first composited frame

Merged
TE
10d ago
+127-8

A DEBUG-only recorder for launch frames. It's the instrument for Leo's never-blank first launch frame item: the first frame paints the snapshot, then goes live, with no blank, white or black frame between.

debug.window_record can't see a launch, because it needs the control socket and that comes up only after launch settles (AppDelegate, launchSettle.settled(within: 4s)). With --record-launch DIR [--record-launch-seconds S]:

  • When it starts: DebugTimings.install starts an app-clock frame client before the first window exists.
  • What it records: once a display frame, any main window (ShellWindow) it hasn't seen gets its own recorder. That recorder takes a frame at once, then one per display frame of that window, from the window's first composited frame. That covers the launch window and each restored window, even those that wait off screen for their content.
  • What it writes: DIR/window-N/ holds JPEG frames and frames.json. The JSON has times, luminance and peak per frame, as debug.window_record writes them, plus processMs, the frame's time since the process started. That's the launch marks' clock.
  • Limits: each window records for S seconds (6 by default, 12 at most). The app looks for new windows for 30 s.
  • Code: the hook lives in DebugWindowRecord and DebugTimings. It doesn't touch WindowController, WindowManager or AppDelegate, which are all over the god-file limit.

DebugLaunchRecordTests covers the arguments. Next, a DEV build of this head records a cold launch and a launch with restored windows on a capture mini. Every blank or unpainted frame found gets its own failing test and fix PR, and if the launch is clean, a guard follows.

No capture: DEBUG-only instrumentation, nothing visible changes.

Capture

A real recording with this probe: a DEV build of this head on capture slot cua-5, 60 fps. Times are ms since process start. Top row: a cold launch. Bottom row: a relaunch that restores two windows.

launch recording, cold and restore

What it found (fixes follow in their own PRs):

  • Restore: frame 0, at 1831 ms, is solid white.
  • Restore: the sidebar is gone from 2193 to 2339 ms.
  • Restore: "Conversations need a newer cmux daemon." shows from 2012 to 2339 ms.
  • Cold: the layout settles in pieces from 3256 to about 5000 ms.

Agent session: huge-blue

šŸ¤– Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Adds --record-launch DIR [--record-launch-seconds S], a DEBUG-only recorder that captures every launch window from its first composited frame. debug.window_record can't see a launch because it needs the control socket, which comes up only after launch settles.

  • Starts from DebugTimings.install, before the first window exists, and records each ShellWindow from its first captured frame into DIR/window-N/.
  • Each frame's frames.json includes processMs, its time since process start, on the launch marks' clock.
  • Time zero is the first frame actually captured, so a window that shows before it can be captured doesn't start the clock early.
  • Windows record for S seconds (6 by default, at most 12); a recording ends when its window closes, and the app keeps looking for new windows for 30 s.
  • DEBUG-only: nothing changes without the flag; a plain debug.window_record keeps its own clock behavior.