Skip to content

cmux-next agent pane: apply a render-rate change to the live page - #16517

Merged
teamleaderleo merged 5 commits into
feat-cmux-nextfrom
nx-pane-live-rate
Oct 1, 2026
Merged

teamleaderleo merged 5 commits into
feat-cmux-nextfrom
nx-pane-live-rate

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Follows #16487. The agent pane's render rate can now change on a live page. Before this, changing it with the adaptive governor or the full_rate debug action did nothing (measured). WebKit reads PreferPageRenderingUpdatesNear60FPSEnabled only when the page's visibility changes, so a pane kept the rate it was created with.

Change. When rendersAtFullRate changes, the pane briefly hides its web view and shows it again, which makes WebKit re-read the rate:

  1. It takes a snapshot of the page and lays it over the web view.
  2. It hides the web view for 33 ms, then shows it.
  3. It removes the snapshot 50 ms later.

If there's no snapshot, it skips this rather than blink.

The adaptive governor only changes the rate once a scroll has settled (250 ms after the last scroll), so the switch happens on an idle page and the snapshot matches what's on screen.

Testing

Unit test. AgentPaneRenderingTests.aLiveRateChangeReShowsThePageUnderASnapshot checks the sequence and that setting the current rate does nothing.

  • Red at ddbcef0fe88 (stubs only): no hide happens.
  • Green: see the next commit.

Live, on cmux-mac-mini (M4) with a 120 Hz virtual display (fleet vdisplay, cmuxterm-hq#1121), using an experiment build of the same mechanism. The pane launched capped, then each variant toggled the rate on and off with a fling after each toggle.

re-apply after toggling on after toggling off
none (main today) 181 frames, p50 17 ms 181, 17 ms
hide, 0 ms 181, 17 ms 181, 17 ms
remove from and re-add to the window 181, 17 ms 181, 17 ms
hide 50 ms 360, 8 ms 182, 17 ms
snapshot cover, hide 16 / 33 / 50 ms 361 / 362 / 360, 8 ms 182 / 181 / 181, 17 ms

Flicker. I recorded the virtual display during the toggles and checked the brightness of the pane's header in each frame.

  • The plain 50 ms hide shows a blank pane (header gone) for a frame.
  • None of the six snapshot-cover toggles shows one.
  • The recorder captures at most 60 fps and only when pixels change, so a single 8 ms glitch at 120 Hz could in principle slip through.

Not built locally (no local app builds on this Mac). The Swift test runs in CI.

Changelog

none

Red and green

  • aLiveRateChangeReShowsThePageUnderASnapshot:
    • Red at 2894973: (steps.first?.hidden → nil) == true. The first red commit, ddbcef0, didn't compile.
    • Green at 2221e87.
  • aLiveRateChangeKeepsKeyboardFocusOnThePage covers a review finding: hiding the web view moved keyboard focus to the window.
    • Red at e1ed3e1: (window.firstResponder → <NSWindow>) === (pane.webView → <WKWebView>).
    • Green at 9a9dc96, where all 38 checks passed, including cmux-next swift test.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RYQHfug1ZVQDp4eWgwVUtD


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


Summary by cubic

Fixes the agent pane's render rate so changing it via the adaptive governor or full_rate takes effect on a live page. WebKit only reads PreferPageRenderingUpdatesNear60FPSEnabled on a page visibility change, so a pane kept the rate it was created with; the pane now briefly hides and re-shows its web view under a snapshot of the page, so nothing visibly blinks.

  • On a rate change, the pane snapshots the page, hides the web view for 33 ms, shows it again, and removes the snapshot 50 ms later; without a snapshot it skips the blink, and a WebKit without the feature skips it too.
  • Hiding the web view hands keyboard focus to the next key view; the re-apply returns it to the page when the page had it and the user hasn't moved it.
  • Adds a snapshot and pause hook, plus tests verifying the re-show sequence, focus retention, and that setting the current rate changes nothing.

Written for commit 9a9dc96. Summary will update on new commits.

Review in cubic

WebKit reads PreferPageRenderingUpdatesNear60FPSEnabled only when the
page's visibility changes, so setting the rate on a live pane did
nothing (60 Hz stayed 60 Hz on a 120 Hz virtual display after a toggle).
The test expects the pane to hide and re-show its web view under a
snapshot cover. Stubs only, so it fails on behavior.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYQHfug1ZVQDp4eWgwVUtD
@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

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.

⚙️ Run configuration

Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 3d20e668-e5bf-4a78-8b9f-b8e96720a87b

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
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


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.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 2 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

teamleaderleo and others added 3 commits October 1, 2026 18:17
#expect cannot wrap allSatisfy with a key path (the macro treats it as
throwing), so the red test did not compile. Still stubs only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYQHfug1ZVQDp4eWgwVUtD
… changes

WebKit reads the 60 fps preference only when the page's visibility
changes. Setting rendersAtFullRate now lays a snapshot of the page over
the web view, hides the web view for 33 ms and shows it again, then
removes the snapshot 50 ms later. Without a snapshot the change waits
for the next visibility change rather than blink the page.

Red at 2894973: aLiveRateChangeReShowsThePageUnderASnapshot,
(steps.first?.hidden -> nil) == true.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYQHfug1ZVQDp4eWgwVUtD
Hiding the web view to re-apply the rate hands focus to the next key
view, and showing it again does not take it back, so the composer
loses its caret after a settled scroll. Found in review at 2221e87.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYQHfug1ZVQDp4eWgwVUtD

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 3 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Hiding the web view handed focus to the window, so the composer lost
its caret after a settled scroll. The re-apply now gives focus back to
the page when it held it and the user hasn't moved it since. A WebKit
without the 60 fps feature no longer re-shows the page for a rate it
cannot set.

Red at e1ed3e1: aLiveRateChangeKeepsKeyboardFocusOnThePage,
(window.firstResponder -> <NSWindow>) === (pane.webView -> <WKWebView>).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYQHfug1ZVQDp4eWgwVUtD
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Subagent review at 9a9dc96: APPROVE.

The two findings from the review at 2221e87 are fixed:

  • High: hiding the web view moved keyboard focus to the window. Focus now goes back to the page when it held focus and the user hasn't moved it. aLiveRateChangeKeepsKeyboardFocusOnThePage pins this; it was red at e1ed3e1 with firstResponder being the NSWindow.
  • Low: a WebKit without the feature re-showed the page for nothing. The re-apply is now skipped when setWebKitFeature returns false. No test covers it, because a missing feature can't be simulated.

Gap, not blocking: no test covers the case where the user moves focus during the 33 ms hide.

@teamleaderleo
teamleaderleo merged commit 516062b into feat-cmux-next Oct 1, 2026
39 of 42 checks passed
@teamleaderleo
teamleaderleo deleted the nx-pane-live-rate branch October 1, 2026 23:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant