feat(dev): frame log, recording, and window and state verbs for the screenshot harness#38

open3
main
feat/ui-tools-156
opened5h agobyKKainoa Newton
View on GitHubTwo-way sync enabledPR last imported 50m ago

Stacked PR. This branch is based on the sync branch sync/helium-0.20.1.1 (Chromium 156) and targets it. Retarget it to main once the sync merges. It also carries Ship's fix(devutils): keep string files' mtimes… commit (PR #35); that commit drops out of the diff once #35 merges.

Problem

Phase A of the UI overhaul showed that rac's dev screenshot harness couldn't measure motion or reach most surfaces:

  • burst was only accurate for its first frame. The PNG encode ran on the UI thread (~110 ms at 2400x1472), so it stalled the compositor it was measuring.
  • Nothing could drive the edge reveal. It reads the global cursor, and the harness can't move it.
  • The harness could only drive and capture the first window. App, incognito, second-profile, PiP and onboarding windows were out of reach.
  • Light mode and Increase Contrast couldn't be forced on a dark Mac.
  • Nothing kept the harness's switches out of release builds.

Change

Everything sits behind Core's BUILDFLAG(RAC_DEV_SWITCHES) (rac_dev_switches = !is_official_build). New files are listed only inside if (rac_dev_switches) in chrome/browser/ui/views/rac/BUILD.gn. The existing harness body in window_screenshot.mm compiles down to two empty hooks in official builds.

PatchAdds
rac/core/dev-switches-buildflag (Core)dev_switches.gni and //chrome/browser/rac/dev:buildflags
rac/dev/gate-dev-switchesWraps every existing switch (rac-window-screenshot, -delay, -command, -requests, -activate, rac-launch-in-background) and every existing verb in the flag
rac/dev/frame-log--rac-frame-log=PATH: one JSON line per presented frame (frame), the sidebar and page bounds each commit put on screen (layout), each harness request (req), and a clock pairing. Writes happen off the UI thread. Also adds rac::dev::LogAnimationStep() for rac's own motion code, which is a no-op in release.
rac/dev/window-screenshot-recordrecord DIR MS [SCALE]: copies every frame to fNNNN.png plus frames.jsonl, with a 512 MB in-flight cap. Every PNG encode, including burst and single shots, moves to the thread pool.
rac/dev/forced-appearance--rac-force-color-mode=light|dark, --rac-force-increased-contrast, and the verbs appearance light|dark|system and contrast on|off. These affect this process only.
rac/dev/window-screenshot-windowswindows OUT.txt, capture-window SEL OUT.png, target SEL (later input verbs act on that window), and profile-window NAME, which creates profiles only under --user-data-dir and refuses folders that aren't profiles. Selectors: #N, first, normal, app[:ID], incognito, profile:NAME, pip, onboarding, name:WIDGET.
rac/dev/window-screenshot-statespace-theme PRESET|- [auto|light|dark], space-new, open-urls URL… (through -[NSApp.delegate application:openURLs:], the Launch Services path), pointer X Y, pointer-path X0 Y0 X1 Y1 MS and pointer off. The pointer verbs hold +[NSEvent mouseLocation] and post a native mouse-moved event, so the real cursor never moves.

Other harness behavior in window-screenshot-state:

  • Captures of non-browser windows, such as the welcome tour, paint each WebView's surface in.
  • Any --rac-window-screenshot* switch keeps occluded windows painting.
  • A run that sends requests stays in the background unless it passes -activate.
  • Unknown requests are logged instead of silently captured.

Also added: devutils/rac/motion_trace.py, which reads a frame log, and devutils/rac/frames_to_video.swift, which turns burst/record PNGs into an .mp4.

Net upstream hunks (D17): 0. All 46 hunks are in rac-owned files: chrome/browser/rac/dev/*, chrome/browser/ui/views/rac/BUILD.gn, window_screenshot.mm and the new views/rac/dev/* files. A draft had moved the occlusion switch into ChromeBrowserMainParts::PreMainMessageLoopRun, which would have added 3 upstream hunks (two in chrome_browser_main.cc, one in chrome/browser/BUILD.gn). The final review moved it back into the harness's own pre-show hook, and the runtime check below shows that hook is early enough.

Fixes from the final review

  • Capture overpaint (regression in the last draft). Painting every WebView's surface over browser-window captures had three effects: it squared off the content card's rounded corners, it would have covered views drawn over the page (such as the revealed sidebar), and it mixed a later frame into burst shots. The composite now runs only for widgets that aren't browser windows, which covers the tour. Before and after: 05-card-corners-before-fix.png and 06-card-corners-after-fix.png.
  • Thread safety. The CopyFromSurface result now goes through base::BindPostTaskToCurrentDefault, because content doesn't promise it arrives on the calling sequence. The widget, WebContents and bitmap are only touched on the UI thread, through WeakPtrs. If the window closes mid-capture, the shot is written without the composite. If the WebContents goes away, it is skipped.
  • Recorder. The recorder drops its widget pointer when the window is destroyed, so no raw_ptr dangles until DeleteSoon.
  • Occlusion hook. Moved back into rac-owned code (see above).
  • Patch hygiene. Two patches had been refreshed with the wrong quilt prefix (src.orig/). They are re-refreshed with the repo's quilt args and clang-formatted.

How it was verified

Builds went through devutils/rac/build-queue.sh he build on the 156 clone. The final round settled at about 520 planned steps and ran 4. Runs went through the queue's run slot with worktree.sh run and --rac-launch-in-background, against the worktree's own profile. he validate series passes.

Final review runtime check, without --disable-backgrounding-occluded-windows:

  • document.visibilityState is visible and the page paints.
  • burst 10 16 request gaps are 16 Β± 6 ms under a load average of about 100.
  • record 500 0.5 across Cmd+S produced 29 frames with 0 skipped and an 18 ms median gap.
  • pointer 2 400 reveals the hidden sidebar over the page.
  • capture-window onboarding matches a CDP capture of the tour.

Scorecard (17 pass, 0 fail, 1 unknown of 18)

  1. Compiles: pass.
  2. Series valid: pass.
  3. Gate covers every switch: pass on the dev side. All five new switch names are in the dev libchrome_dll.dylib.
  4. Frame log: pass. Every line is valid JSON. A static page idle for 21.4 s logs 0 frames.
  5. record: pass. 40 to 43 frames per 700 ms, 0 skipped, 16.6 ms median gap. burst gaps went from 110 ms to 15.7 ms.
  6. Forced contrast: pass. The page sees prefers-contrast: more, and the UI draws the outlined omnibox.
  7. Forced light/dark: pass. Browser windows switch live, and so does an installed web-app window.
  8. windows, capture-window and target: pass. A targeted command 34014 landed in the incognito window.
    • 8b. Onboarding capture: pass.
  9. space-theme and space-new: pass.
  10. open-urls: pass. Tabs open in the existing window.
  11. pointer verbs: pass.
    • Sidebar reveal: reveals after the 100 ms dwell, hides after the grace period. A sub-dwell path never reveals.
    • Real cursor: never moved.
  12. Existing verbs: pass. As on 154, key escape doesn't close the omnibox popup (nskey escape does). wheel changed nothing visible.
  13. Switches compile out with is_official_build=true: unknown. This is by gn and code reading only, since no release binary was built. Ship's G6 strings check on the release framework is the real test.
  14. 156 motion baselines recorded: pass.
  15. PWA re-check: pass.
  16. 0 upstream hunks: pass.
  17. profile-window on a fresh profile opens a normal window: pass.

Proof (worktree .scratch/proof/, not committed)

Final review build:

  • /Users/knewton/.t3/worktrees/rac/tools-156/.scratch/proof/review/01-browser-window-no-occlusion-flag.png
  • /Users/knewton/.t3/worktrees/rac/tools-156/.scratch/proof/review/02-pointer-edge-reveal.png
  • /Users/knewton/.t3/worktrees/rac/tools-156/.scratch/proof/review/03-capture-window-onboarding.png
  • /Users/knewton/.t3/worktrees/rac/tools-156/.scratch/proof/review/04-record-cmds-hide.mp4 and 04-record-cmds-hide-4x.mp4
  • /Users/knewton/.t3/worktrees/rac/tools-156/.scratch/proof/review/05-card-corners-before-fix.png and 06-card-corners-after-fix.png

Earlier rounds:

  • /Users/knewton/.t3/worktrees/rac/tools-156/.scratch/proof/after/forced/01-forced-light-contrast-media.png
  • /Users/knewton/.t3/worktrees/rac/tools-156/.scratch/proof/after/verbs/19-incognito-after-targeted-newtab.png
  • /Users/knewton/.t3/worktrees/rac/tools-156/.scratch/proof/after/round2/07-profile-window.png
  • /Users/knewton/.t3/worktrees/rac/tools-156/.scratch/proof/pwa-156/side-by-side-app-and-normal.png
  • /Users/knewton/.t3/worktrees/rac/tools-156/.scratch/proof/after/idle/frames.jsonl
  • Baselines on 156: /Users/knewton/.t3/worktrees/rac/tools-156/.scratch/proof/baseline-156/baseline-156.md, with sidebar-reveal-in.mp4, sidebar-reveal-in-4x.mp4, reduced-reveal-in.mp4 and topbar-show.mp4 in the same folder.

Written by Claude Sonnet 5.5 and Devin SWE-2 (drafts), with final review and fixes by Claude Opus 5.5 in Claude Code.

Merge order

Stacked on the sync branch sync/helium-0.20.1.1 (Chromium 156). Nothing under patches/ merges before the sync (D62). After the sync merges, retarget this PR to main before deleting the sync branch. It carries Core's rac/core/dev-switches-buildflag.patch commit (same content as Core's dbaa394) and Ship's dev_names fix (PR #35) unchanged, so each lands once.

πŸ€– Generated with Claude Code

Onboarding window captured by the harness on 156

Edge reveal driven by the new pointer verb

Browser window paints with no occlusion flag

Card corners squared by the round-2c composite (fixed)

Card corners after the fix

https://github.com/user-attachments/assets/bb137717-d143-48af-bd03-32941711214d

Installed web app next to a normal window, dark and forced light (G8)


Devin Review


Note

Medium Risk Large dev-only surface area including Obj-C runtime overrides for pointer and contrast, but gated from official builds via RAC_DEV_SWITCHES; main product risk is accidental exposure if the build flag is misconfigured.

Overview Adds BUILDFLAG(RAC_DEV_SWITCHES) (rac_dev_switches = !is_official_build) so the screenshot harness and new --rac-* switches compile out of official builds; window_screenshot.mm becomes no-op hooks in release.

Behind that flag, the harness gains frame logging (--rac-frame-log), record DIR MS [SCALE] with frames.jsonl, stale-frame cleanup, skipped frames on write failure, and PNG encode on the thread pool (including burst). New request verbs cover window targeting (windows, target, profile-window, capture-window), appearance (CLI + appearance / contrast), and state (space-theme, pointer / pointer-path / pointer off, open-urls). Pointer tests hold +[NSEvent mouseLocation] without moving the real cursor; profile-window only auto-completes onboarding for profiles it creates.

Capture behavior changes: non-browser windows composite WebView surfaces (browser windows skip this to avoid corner/regression issues), occluded windows keep painting when any screenshot switch is set, request-driven runs stay background unless -activate, and unknown requests log errors instead of defaulting to PNG capture.

New devutils/rac/ tools: motion_trace.py, frames_to_video.swift, harness_selftest.py (+ unit tests). patches/series lists seven new rac dev patches.

Reviewed by Cursor Bugbot for commit 3d0cc55cca043c0d4bea3cc30c7edc3e260df27f. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Expands the dev screenshot harness so it can measure motion, reach any window type, and drive state the old harness couldn't touch. Everything sits behind BUILDFLAG(RAC_DEV_SWITCHES) (rac_dev_switches = !is_official_build), so release binaries carry none of it and the old harness body compiles to two empty hooks.

  • --rac-frame-log=PATH writes one JSON line per presented frame plus the sidebar and page bounds, off the UI thread.
  • record DIR MS [SCALE] copies every frame to PNGs with a frames.jsonl; PNG encoding moved off the UI thread, cutting burst frame gaps from ~110 ms to ~16 ms. It starts only once the folder exists, stops with an error if the folder can't be made, clears earlier recordings, and counts frames whose PNG write fails as skipped.
  • Window selectors (#N, first, normal, app[:ID], incognito, profile:NAME, pip, onboarding, name:WIDGET) plus windows, capture-window, target, and profile-window verbs. profile-window marks onboarding finished only for a profile it creates.
  • space-theme, space-new, open-urls, and pointer/pointer-path verbs; the pointer is held via +[NSEvent mouseLocation] so the real cursor never moves. pointer off and new pointer commands cancel a running pointer-path; space-theme validates all arguments before applying any.
  • --rac-force-color-mode=light|dark and --rac-force-increased-contrast affect this process only.
  • Non-browser-window captures (such as the welcome tour) paint each WebView's surface in; any screenshot run keeps occluded windows painting.
  • Adds devutils/rac/motion_trace.py (reads a frame log), devutils/rac/frames_to_video.swift (turns burst/record PNGs into an mp4), and devutils/rac/harness_selftest.py with its unit tests, which check the fixes above against a running build.

Bug Fixes

  • dev_names.py records file mtimes on unsub and restores them on files the passes rewrite byte-identical, so builds don't reprocess ~2,700 unchanged string files after every sync.

Written for commit 3d0cc55cca043c0d4bea3cc30c7edc3e260df27f. Summary will update on new commits.

View guided diff Turn on auto-fix

Checks

2 failing Β· 7 successful Β· 2 neutral Β· 1 skipped
Some checks failed

Failing2

  • pullfrogGitHub
    Failed
  • VercelGitHub
    Failed
3d0cc55
CcursorBot5h ago
Synced from GitHub

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: ce666297-e11e-42d7-9a4d-e927d89fbdfd)

Synced from GitHub

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

External image Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: f272d9de-fe69-4f56-b03d-94bb2e480ba2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • πŸ” Trigger review
  • Autofix Β· Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❀️ Share

Comment @coderabbitai help to get the list of available commands.

patches/rac/dev/window-screenshot-record.patchlines 103–109Outdated Β· c6d4403Open thread
……@@ -0,0 +1,397 @@
106++ base::WriteFile(
107++ dir.AppendASCII("frames.jsonl"), "");
108++ },
109++ dir_));
Ddevin-ai-integrationBoton lines 103–1095h ago

πŸ”΄ First recorded frame can disappear

When record starts in a new directory, its first PNG can write before the directory exists. EncodeAndWrite runs on another sequence, and OnWritten still logs the failed frame as captured.

Learn more

The recorder queues directory creation on log_, a sequenced background runner. It immediately calls RequestFrame, and OnFrame schedules encoding on an independent thread-pool task. No ordering guarantees that the directory exists before the PNG writer opens its output file. The encode return value is discarded, so OnWritten logs the frame as if its PNG exists.

Example: record /tmp/new-capture 500 requests frame zero before the log_ task runs. Its PNG write fails because /tmp/new-capture does not yet exist, but frames.jsonl includes i:0 and a done line.

Recommended fix: Create or verify the directory before calling RequestFrame, or start capture only after the directory-creation task replies on the UI sequence. Also propagate PNG-write failures to the frame accounting.

Devin Review


Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

patches/rac/dev/window-screenshot-state.patchlines 125–129Outdated Β· c6d4403Open thread
……@@ -0,0 +1,545 @@
126++ if (!base::StringToSizeT(words[1], &preset) ||
127++ !manager->spaces()->SetSpaceThemePreset(*space, preset)) {
128++ LOG(ERROR) << "rac window screenshot: bad preset " << words[1];
129++ return false;
Ddevin-ai-integrationBoton lines 125–1295h ago

🟑 Invalid theme request changes space colors

With a valid preset and invalid mode, space-theme saves the preset before rejecting the mode. A failed request still changes the space's colors.

Learn more

The space-theme verb can set both a preset and a light/dark mode in one request. SetSpaceThemePreset mutates the space immediately, while the mode validation below it happens afterward. Rejecting the mode does not roll back the preset, leaving the persisted space theme partially updated.

Example: space-theme 3 ligth logs a bad mode but still changes the space to preset 3, rather than leaving its previous colors untouched.

Recommended fix: Parse and validate both arguments before calling either SetSpaceThemePreset or SetSpaceThemeMode.

Devin Review


Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

devutils/rac/frames_to_video.swiftline 73Outdated Β· c6d4403Open thread
……@@ -0,0 +1,161 @@
70+ }
71+ if isDirectory.boolValue {
72+ let names = (try? FileManager.default.contentsOfDirectory(atPath: input)) ?? []
73+ return names.filter { $0.hasSuffix(".png") }.sorted().map { (input as NSString).appendingPathComponent($0) }
Ddevin-ai-integrationBoton line 735h ago

🟑 Burst videos scramble frames after 99

For a burst of at least 101 frames, framePaths sorts f100.png between f10.png and f11.png. The resulting video plays frames out of order.

Learn more

The existing burst handler writes names using %02d, which pads only to two digits. framePaths sorts those names as strings. After frame 99, numeric and alphabetical order diverge, so a normal two-second 60 fps burst produces a video with jumps.

Example: A directory with f09.png, f10.png, f11.png, and f100.png plays as f09, f10, f100, f11 rather than increasing frame numbers.

Recommended fix: Sort burst files by their parsed numeric frame index, while retaining a defined order for arbitrary PNG names; alternatively increase the burst filename padding and account for existing captures.

Devin Review


Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

patches/rac/dev/window-screenshot-record.patchlines 103–108Outdated Β· c6d4403Open thread
……@@ -0,0 +1,397 @@
105++ base::CreateDirectory(dir);
106++ base::WriteFile(
107++ dir.AppendASCII("frames.jsonl"), "");
108++ },
Ddevin-ai-integrationBoton lines 103–1085h ago

🟑 Repeated recordings include stale frames

When record reuses a directory, it truncates frames.jsonl but keeps old PNGs. A shorter second recording produces a video that appends frames from the first.

Learn more

A recording writes numbered files starting at f0000.png, and the directory initializer only truncates frames.jsonl. framePaths includes every PNG in that directory. A second recording that produces fewer frames overwrites its initial files but leaves the previous run's tail behind.

Example: Record 60 frames in /tmp/demo, then record 30 frames into the same folder. Converting /tmp/demo plays the 30 new frames followed by 30 stale frames.

Recommended fix: Require an empty output directory or remove stale numbered recording frames before recording starts, without deleting unrelated user files; verify initialization finishes before capture begins.

Devin Review


Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

devutils/rac/frames_to_video.swiftline 121Outdated Β· c6d4403Open thread
……@@ -0,0 +1,161 @@
118+ writer.startSession(atSourceTime: .zero)
119+
120+ for (index, path) in frames.enumerated() {
121+ while !input.isReadyForMoreMediaData { Thread.sleep(forTimeInterval: 0.005) }
Ddevin-ai-integrationBoton line 1215h ago

🟑 Failed video export hangs indefinitely

If AVAssetWriter fails during export, writeVideo waits forever for input readiness. The polling loop never checks the writer's failure status.

Learn more

AVAssetWriter can fail asynchronously while encoding, for example when its output volume fills. The writer input can then stay not ready for more data. This loop waits only for readiness, so the later append and finishWriting error checks never run.

Example: A video export starts successfully, but its output volume runs out of space while frames remain. Instead of reporting the writer error, the converter keeps sleeping and never exits.

Recommended fix: While waiting, check writer.status for .failed or .cancelled and exit with writer.error; use the same check before requesting the next pixel buffer.

Devin Review


Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

patches/rac/dev/window-screenshot-windows.patchlines 318–323Outdated Β· c6d4403Open thread
……@@ -0,0 +1,407 @@
320++ // finishing it does.
321++ profile->GetPrefs()->SetBoolean(prefs::kHeliumDidOnboarding,
322++ true);
323++ profiles::OpenBrowserWindowForProfile(
Ddevin-ai-integrationBoton lines 318–3235h ago

πŸ”΄ Existing profiles lose their welcome tour

When profile-window opens an existing profile with unfinished onboarding, it marks that profile finished. The welcome tour no longer appears on future launches.

Learn more

A profile's onboarding preference records whether its welcome tour has been completed. The profile-window verb accepts an existing profile as well as a new one, but the callback always sets that preference to true. ShouldShowWelcomeTourAtLaunch checks the preference before showing the tour. Opening an existing, unfinished profile with this test verb therefore changes persisted behavior beyond the test run.

Example: A profile named Work exists with kHeliumDidOnboarding=false. Running profile-window Work opens a window and saves true; after restarting, Work never receives its pending tour.

Recommended fix: Determine whether the profile was newly created before calling CreateProfileAsync; only mark onboarding finished for that case, or avoid changing the persistent preference and use a nonpersistent tour-suppression mechanism.

Devin Review


Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

Synced from GitHub

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] The PR expands screenshot and motion testing within developer builds.

The PR appears safe to merge, with non-blocking fixes recommended for pointer cancellation and recording/export errors.

Findings

  1. P2Β Released pointer takes over again β–Ά
  2. P2Β Frames can precede their directory β–Ά
  3. P2Β Missing frames look successful β–Ά
  4. P2Β Failed video export never exits β–Ά
Fix with agent prompt
markdown
1### Issue 1
2patches/rac/dev/window-screenshot-state.patch:291-293
3`pointer off` clears the held location but leaves an active `pointer-path` running. Its next queued step calls `MovePointer` and holds the pointer again. Later `pointer` and `pointer-path` commands also compete with the old path, making hover and sidebar captures unreliable. Cancel pending steps, or invalidate older paths whenever a new pointer command arrives.
4
5### Issue 2
6patches/rac/dev/window-screenshot-record.patch:103-109
7`Recorder` starts capturing without waiting for its output directory. `CreateDirectory` runs on `log_`, while PNG writes run independently on the thread pool. If the directory is new, an early write can run first and fail, leaving frames missing from the recording. Start capturing from the directory-creation reply, and stop if creation fails.
8
9### Issue 3
10patches/rac/dev/window-screenshot-record.patch:195-201
11`OnFrame` discards the result of `EncodeAndWrite` and always passes a frame entry to `OnWritten`. If writing fails, such as when the disk fills, `frames.jsonl` still lists the missing PNG and the skipped count stays unchanged. Return the write result to the reply, log only successful frames, and count failed writes as skipped.
12
13### Issue 4
14devutils/rac/frames_to_video.swift:121
15`writeVideo` waits for `isReadyForMoreMediaData` without checking whether `writer` has failed. If writing fails between frames, such as when the disk fills, the input can stay not ready forever. The export and any script waiting for it then hang. Check `writer.status` inside the wait and report `writer.error` when writing has stopped.
16
17---
18
19For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Adds developer-only frame logs, recordings, appearance controls, window selection, and pointer commands. It also adds motion/video helpers and preserves timestamps for unchanged string files.

  • Developers can trace presented frames and sidebar movement over time.
  • Developers can record window frames without blocking the frames being measured.
  • The harness can list, select, and capture different app windows.
  • The harness can set up spaces, open URLs, and move a simulated pointer.
  • Developers can set this app's color mode and contrast for a test run.
  • Screenshot harness switches and tools are limited to developer builds.
  • Unchanged string files keep their timestamps after the dev-name pass.

No builds or runtime checks were performed during this review.

Intentional exclusion: notkainoa states that browser-window captures skip the added WebView composite because it would square corners, cover views, and mix frames.

Reviews (1) Β· Last reviewed commit: "fix(devutils): keep string files' mtimes..." Β· Reviewed by Greptile

patches/rac/dev/window-screenshot-record.patchlines 103–109Outdated Β· c6d4403Open thread
……@@ -0,0 +1,397 @@
106++ base::WriteFile(
107++ dir.AppendASCII("frames.jsonl"), "");
108++ },
109++ dir_));
Ggreptile-appsBoton lines 103–1095h ago

P2 Frames can precede their directory

Recorder starts capturing without waiting for its output directory. CreateDirectory runs on log_, while PNG writes run independently on the thread pool. If the directory is new, an early write can run first and fail, leaving frames missing from the recording. Start capturing from the directory-creation reply, and stop if creation fails.

Prompt To Fix With AI
markdown
1This is a comment left during a code review.
2Path: patches/rac/dev/window-screenshot-record.patch
3Line: 103-109
4
5Comment:
6**Frames can precede their directory**
7
8`Recorder` starts capturing without waiting for its output directory. `CreateDirectory` runs on `log_`, while PNG writes run independently on the thread pool. If the directory is new, an early write can run first and fail, leaving frames missing from the recording. Start capturing from the directory-creation reply, and stop if creation fails.
9
10---
11
12For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
patches/rac/dev/window-screenshot-state.patchlines 291–293Outdated Β· c6d4403Open thread
……@@ -0,0 +1,545 @@
290++ }
291++ if (verb == "pointer" && words.size() == 2 && words[1] == "off") {
292++ SetHeldPointer(std::nullopt);
293++ return true;
Ggreptile-appsBoton lines 291–2935h ago

P2 Released pointer takes over again

pointer off clears the held location but leaves an active pointer-path running. Its next queued step calls MovePointer and holds the pointer again. Later pointer and pointer-path commands also compete with the old path, making hover and sidebar captures unreliable. Cancel pending steps, or invalidate older paths whenever a new pointer command arrives.

Prompt To Fix With AI
markdown
1This is a comment left during a code review.
2Path: patches/rac/dev/window-screenshot-state.patch
3Line: 291-293
4
5Comment:
6**Released pointer takes over again**
7
8`pointer off` clears the held location but leaves an active `pointer-path` running. Its next queued step calls `MovePointer` and holds the pointer again. Later `pointer` and `pointer-path` commands also compete with the old path, making hover and sidebar captures unreliable. Cancel pending steps, or invalidate older paths whenever a new pointer command arrives.
9
10---
11
12For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
patches/rac/dev/window-screenshot-record.patchlines 195–201Outdated Β· c6d4403Open thread
……@@ -0,0 +1,397 @@
198++ std::move(bitmap),
199++ dir_.AppendASCII(base::StringPrintf("f%04d.png", index))),
200++ base::BindOnce(&Recorder::OnWritten, weak_factory_.GetWeakPtr(), bytes,
201++ std::move(line)));
Ggreptile-appsBoton lines 195–2015h ago

P2 Missing frames look successful

OnFrame discards the result of EncodeAndWrite and always passes a frame entry to OnWritten. If writing fails, such as when the disk fills, frames.jsonl still lists the missing PNG and the skipped count stays unchanged. Return the write result to the reply, log only successful frames, and count failed writes as skipped.

Prompt To Fix With AI
markdown
1This is a comment left during a code review.
2Path: patches/rac/dev/window-screenshot-record.patch
3Line: 195-201
4
5Comment:
6**Missing frames look successful**
7
8`OnFrame` discards the result of `EncodeAndWrite` and always passes a frame entry to `OnWritten`. If writing fails, such as when the disk fills, `frames.jsonl` still lists the missing PNG and the skipped count stays unchanged. Return the write result to the reply, log only successful frames, and count failed writes as skipped.
9
10---
11
12For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
devutils/rac/frames_to_video.swiftline 121Outdated Β· c6d4403Open thread
……@@ -0,0 +1,161 @@
118+ writer.startSession(atSourceTime: .zero)
119+
120+ for (index, path) in frames.enumerated() {
121+ while !input.isReadyForMoreMediaData { Thread.sleep(forTimeInterval: 0.005) }
Ggreptile-appsBoton line 1215h ago

P2 Failed video export never exits

writeVideo waits for isReadyForMoreMediaData without checking whether writer has failed. If writing fails between frames, such as when the disk fills, the input can stay not ready forever. The export and any script waiting for it then hang. Check writer.status inside the wait and report writer.error when writing has stopped.

Prompt To Fix With AI
markdown
1This is a comment left during a code review.
2Path: devutils/rac/frames_to_video.swift
3Line: 121
4
5Comment:
6**Failed video export never exits**
7
8`writeVideo` waits for `isReadyForMoreMediaData` without checking whether `writer` has failed. If writing fails between frames, such as when the disk fills, the input can stay not ready forever. The export and any script waiting for it then hang. Check `writer.status` inside the wait and report `writer.error` when writing has stopped.
9
10---
11
12For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
CcursorBot2h ago
Synced from GitHub

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: 2c392cf7-62e7-4b83-a305-d4c8921b6c97)

Added 3 commits

  • fix(dev): address review findings on the screenshot harness3d0cc55
  • feat(dev): add the RAC_DEV_SWITCHES build flag5ff9880
  • feat(dev): add frame log, recording, window and state verbs to the screenshot harnessfa750a4
CcursorBot1h ago
Synced from GitHub

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: e9c71044-cd5c-4aef-9ab4-17f02c8741a7)