Skip to content

cmux NEXT captures: a window snapshot shows an open popover with its glass, and waits behind a busy main actor - #24240

Merged
teamleaderleo merged 9 commits into
feat-cmux-nextfrom
leo/capture-child-windows
Oct 26, 2026
Merged

teamleaderleo merged 9 commits into
feat-cmux-nextfrom
leo/capture-child-windows

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

The ask (from the capture lane, reported by chief-ui and projects-50): "(a) the capture tool's window snapshot leaves out child panels and popovers (NSPanel/child windows), so no popover PR can attach a capture" and "(b) the fleet window snapshot timed out and was refused." Done when "a capture of an open popover shows the popover."

Three causes, three fixes, all in the DEBUG capture path (debug.window_snapshot, which pr-capture's driver.py uses for every still):

  • The popover never opened in a capture slot. Slots run the app in the background (CMUX_NEXT_NO_ACTIVATE=1), so there is no key window. home.toggleChiefSettings then picked the front visible window, and AppKit lists a child window before its parent when the app is not active. The front window was Chromium's page window (a CefNSWindow child of the main window), no Home answered, and nothing opened. HomeChiefSettingsPopover.toggleTarget now walks a child window up to its parent, as it already did for a key child panel.
  • A glass popover came out as a flat grey card. The snapshot composited the window, then the overlay panels on their own, then menus. A glass or vibrancy panel composited alone has nothing behind it to blur. The window, its child windows and the app's windows over it (menus, cards, popovers that aren't its children) are now one window-server composite (NSWindow.compositedSnapshotWithOverlays()), so the glass blurs the window under it, as on screen. Where a Chromium page image is then painted over the composite, the overlays are cut from that same composite by their own coverage (overlays(cutFrom:includeChild:)) and painted back on top, so a popover over a web page stays on top too. As before, only this app's windows are composited, never another app's.
  • The snapshot timed out on a loaded capture mini. debug.window_snapshot ran under the 2 s control-plane deadline, and that deadline counts the wait for the main actor. The capture itself takes about 50 ms, but on cua-5 (load 30 to 44 on 14 cores, shared with builds and test suites) and during app launch, the wait passed 2 s. The driver then had no still, and pr-capture refused the capture. The deadline exists to catch a handler that hangs, but a snapshot queued behind main-actor work isn't hung, and the driver needs the still either way. So the method keeps its own 30 s deadline (DebugWindowSnapshot.controlMethod), which matches the driver's 30 s socket timeout. The route moves out of AppControl into DebugWindowSnapshot so a test can drive it through a real ControlRouter.

cmux window|pane|tab screenshot (AppWindowImage, WindowImageLayer) is left as on base. Two open PRs (#23972, #23983) rework that path, and this one doesn't touch it.

Testing

Red first (471c8b8), then the fix:

  • DebugWindowSnapshotDeadlineTests.aSnapshotWaitsBehindABusyMainActor: a router with a 50 ms request deadline, the main actor busy for 400 ms. On base the call fails with a timeout. On the head it answers (no such window for a made-up window number).
  • HomeChiefSettingsToggleTests.withoutAKeyWindowAChildInFrontStandsForItsWindow: with no key window and a visible child listed first, the toggle reaches the parent. On base it returned the child.
  • WindowSnapshotOverlaysTests.theWindowAndItsOverlaysAreOneCompositeTopmostFirst: the composite's window order (on-screen order first, then unlisted windows, each once).
  • WindowSnapshotOverlaysTests.aPopoverCutFromTheCompositeShowsOverAPageImage: pixel check. Where the popover covers the window, the cut shows the popover over a page image; elsewhere the page shows.

cmux-ci compile-check --app passed at the head d04352f (job 29e40325ba693a068a630a72).

Observed / Not run

  • Observed: a fleet build of this branch on capture slot cua-5 (load 22 to 40 on 14 cores while it ran). home.show then home.toggleChiefSettings from the CLI, with the app in the background. The window list showed the NativePopupPanel child, and debug.window_snapshot returned in 18 to 51 ms with child_windows: 5. The still shows the Chief Settings popover open with its glass over Home, in light and dark. Before the toggle fix, the same steps opened nothing. Before the composite change, the popover came out as an opaque grey card.
  • Observed: the pr-capture run in Proof below (fleet build, capture slot, OCR privacy check).
  • Not run: a popover over a Chromium page (the cut path) live; the pixel test covers that compositing.

Changelog

none

Proof

Capture steps-108f6bc705 at d04352ff7e7f (fleet build, capture mini, text checked for private data)

Light Dark
light dark

Steps: cmux action run home.show, then cmux action run home.toggleChiefSettings, with the app in the background as every capture slot runs it. Capture job (fleet build) bdb92487ed96664bf8987012.

Checklist

  • Behavior changes have added or updated tests
  • Reviewed with an independent reviewer before merge, and all bot and human review comments resolved

Agent session: cosmic-gray

🤖 Generated with Claude Code

teamleaderleo and others added 5 commits October 21, 2026 22:14
…toggle reaches the Home (red)

debug.window_snapshot is now built by DebugWindowSnapshot.controlMethod (no
behavior change) so a test can register it. Both tests fail on this commit:
the snapshot times out at the control-plane deadline while the main actor is
busy, and with no key window a child window in front takes the Chief Settings
toggle instead of its window.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oggle reaches the Home

debug.window_snapshot keeps its own 30 s deadline instead of the 2 s
control-plane one. On a capture mini that also runs builds and tests
(cua-5 at load 30 to 44 on 14 cores) the wait for the main actor passed
2 s, the snapshot timed out, and pr-capture refused the capture for want of
a still. The capture itself takes about 50 ms.

With no key window, home.toggleChiefSettings resolves the frontmost visible
window to the window it belongs to. Outside an active app AppKit lists
Chromium page child window first, so a toggle from the CLI with cmux in the
background (every capture slot) reached no Home and the popover never opened.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A window snapshot composited the window, then its overlay panels alone, then
the menus over it. A glass popover composited alone blurs nothing and came
out grey. The window, its child windows and the app's windows over it now go
to the window server as one composite, so the glass blurs the window under
it as on screen. Where a Chromium page image is painted over that, the
overlays come back on top through a coverage mask. Only this app's windows
are composited, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two open PRs (#23972, #23983) rework cmux window screenshot in
AppWindowImage and WindowImageLayer. Leave both files as on base: the
overlay cut is an NSWindow helper painted as an ordinary window layer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo teamleaderleo added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 22, 2026
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 53416d1: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr24240 -f ref=leo/capture-child-windows -f platform=macos -f backend_mode=local

web and size checks: green

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by deputy-2 on cosmic-gray · session

@blacksmith-sh

blacksmith-sh Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Found 9 test failures on Blacksmith runners:

Failures

Test View Logs
/tmp/tmpojodkr0j/summary-missing.json (live):/summary-missing.json (live): View Logs
/tmp/tmpx3588jkv/summary-fail.json (live):/summary-fail.json (live): View Logs
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows/
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows
View Logs
[new_workspaces] the window draws no frames/[new_workspaces] the window draws no frames View Logs
[tabs] debug.tab_switch timed 0 of 40 switches/
[tabs] debug.tab_switch timed 0 of 40 switches
View Logs
[tabs] the window draws no frames/[tabs] the window draws no frames View Logs
bench OTHER_SWIFT_FLAGS is 'OTHER_SWIFT_FLAGS=$(inherited) -DCMUX_BENCH_HOOKS -DCMUX_BL
OCKING_CHECKS'/
bench OTHER_SWIFT_FLAGS is 'OTHER_SWIFT_FLAGS=$(inherited) -DCMUX_BENCH_HOOKS -DCMUX_BL
OCKING_CHECKS'
View Logs
bench OTHER_SWIFT_FLAGS is 'OTHER_SWIFT_FLAGS=$(inherited) -DCMUX_BENCH_HOOKS -DCMUX_BL
OCKING_CHECKS'/
bench OTHER_SWIFT_FLAGS is 'OTHER_SWIFT_FLAGS=$(inherited) -DCMUX_BENCH_HOOKS -DCMUX_BL
OCKING_CHECKS'
View Logs
test_the_repository_highlights_validate (main.DigestTests.test_the_repository_highl
ights_validate)/
test_the_repository_highlights_validate (main.DigestTests.test_the_repository_highl
ights_validate)
View Logs

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

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Bead cx-vqhot created for this PR by the cmux coordinator.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Orphaned: no activity for 13 h, and no lane holds a lease on it. Adopted by the orphan sweep: merged feat-cmux-next in at 20141b1. A later pass queues it for the merge hub if it is reviewed, small and red only on base reds.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next crash-class rules / cmux-next crash-class rules is red on 12 of 12 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

Resolved NSWindow+Snapshot.swift: base split capture into main-actor
plans (WindowCapturePlan, FloatingWindowsCapturePlan) and nonisolated
window-server calls, dropping windowServerImage(ofNumbers:croppedTo:)
and isBlank. Kept base's plan/off-main API; ported the PR's
floatingWindowNumbers, compositedSnapshotWithOverlays,
overlays(cutFrom:includeChild:) and masked onto it (floating numbers now
read through a nonisolated floatingWindowNumbers(in:) shared with
capture(_:), crops via windowServerImage(ofNumbers:rect:), blank check
via isFullyTransparent), and kept the PR's frontToBack(_:onScreen:)
split under base's nonisolated frontToBack(_:).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1603a-6462-72f0-a4b0-6937eb58e4c3&host=cosmic-gray
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next guards / nightly-guards / workflow-guard-tests / release-notary is red on 18 of 21 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

…overlays before the page awaits

Where the overlays alone are translucent (a shadow, a fade, an edge), the cut
now takes their own pixels instead of the composite times their alpha, which
painted over a page image faded them twice. The overlays are cut right after
the composite, before the page images' awaits, so a popover that opens
meanwhile is not cut from a composite it is not in. The deadline test waits
for the request to start before it blocks the main actor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a1603a-6462-72f0-a4b0-6937eb58e4c3&host=cosmic-gray
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next fast gates / post cmux-next/fast-gates is red on 20 of 22 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@teamleaderleo
teamleaderleo merged commit be82570 into feat-cmux-next Oct 26, 2026
120 of 131 checks passed
@teamleaderleo
teamleaderleo deleted the leo/capture-child-windows branch October 26, 2026 02:25
@github-actions

github-actions Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

This branch was previously deployed

1 inactive deployment
ci-routing-agent — 705ea1b2 Deployed Oct 26, 2026 by teamleaderleo via namespace autofix #2873
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant