P0 RESIZE KEYS K3: a keyboard resize holds pane content through its spring and lays it out once after the landing

LA
3d ago
+421-8

Summary

P0 RESIZE KEYS K3 (cmux-ad; lead decision 2026-11-02 21:1xZ: "hold pane content during a key resize spring, one reflow at the landing"). With a browser page and an agent chat right of the moving divider, every Ctrl-Shift-H/L lost 4-8 refreshes of its spring (film rk-browser-agent).

Profile (xctrace on the app clock, rk-xtpa-browser-agent): no single item over 8.3 ms. Each dropped frame (9-26 ms of main thread) was the pane contents laid out at the spring's live size: the CA commit (2-8 ms: tracking areas over every subview, window drag regions, the tab label glyphs drawn again, constraint updates), the agent chat's SwiftUI graph, the CEF content view and its child window frame, BrowserChromeView, the tab strip and toolbar.

Fix, in three red-first steps (the third after review):

  1. PaneResize.press tells the screen (LayoutRootView.keyboardResizeWillChange); the screen's hosts hold their content through the spring (the PaneHostView content hold agent chats already use). After films: drops 4-8 -> 0-2 per press. The after profile named the rest: the one content layout still ran in the key turn (growing panes, 10-24 ms) or in the landing frame (shrinking panes, 11-17 ms).
  2. A key resize now holds each pane's content at its START size, growing or shrinking (clipped where the pane is smaller, beside the pane background where it is larger, pinned at the edge nearer its rest), keeps it through retargets, and releases it after the landing frame's commit (LayoutViewContext.afterCommit), when nothing moves: one layout per press, outside every motion frame.

Splits, closes and zooms keep their live resize (motion.pane.holdContent, Lawrence 2026-10-23); the agent chat's own hold is unchanged.

Testing

On the fleet (scripts/ci/package-test-lane.sh suite Packages/macOS/CmuxNext ...), compile-checks first:

  • Red 1, b4915efa1c5 (KeyboardResizeContentHoldTests): step fd8b8ee8192f0a3e01ed3b99 FAILED (content resized 16-17 times per press). Fix 1, 3e14e9205bb: green + GUI step ae755250d956d31e9c9d7df1 (cmux9s) PASSED, 13 cases, 0 skipped.

  • Red 2, 30053696eb8 (KeyboardResizeReflowAfterLandingTests): step 0c9a480d1edf51301c6fac89 (aws-m4pro-8) FAILED (each content laid out once inside the motion). Fix 2, fcd7cf32995: compile-check 356b12cd572dc3927ea5679b PASSED; green + GUI proof (display worker gui-session-v1, CMUX_TEST_REQUIRE_GUI=1) at the exact head fcd7cf32995ee72813219e525cfb8eb96c42f218: step 6eb3bf74690f4029f9834aa5 (cmux8s) PASSED: ReflowAfterLanding 2/2, ContentHold 2/2, ShownLimit 2/2, Rows 2/2, PaneResizeGesture 4/4; 15 cases, 0 skipped.

  • Films (120 Hz 2x, real HID keys, before = base ddcaf92 build fddf4464, same minis per STATUS 7645): fix 1 + #32626 (build f44441a2): H/L drops per press before 4-8, after 0-2 (cmux22, cmux24, 4+4 runs). Fix 2 films: below.

  • Red 3, b05cb877472 (KeyboardResizeHoldLifetimeTests): step 78d0cb77b1a0ce031797ff22 (aws-m4pro-9, headless) FAILED: 4 tests, 19 issues (held edge moves 59-60 pt before the landing; the flag stays set after a press with no spring and after landMotion; a split's new pane is 0x0 during a key spring). Fix 3, 593effbd3d7: compile-checks 8823c28f48d638b216a3a21c (fix) and 5991c58acd19270310ecb9c8 (red) PASSED; green + GUI proof (display worker gui-session-v1, CMUX_TEST_REQUIRE_GUI=1) at the exact head 593effbd3d7d3092b3ecb38b3f0b606f7125ace9: step 2bdfcdd669fdc9dc7f9d0163 (cmuxs-Mac-mini-4): HoldLifetime 4/4, ReflowAfterLanding 1/1, ContentHold 1/1, ShownLimit 2/2, Rows 2/2, PaneResizeGesture 4/4, PaneMotionContentHold 11/11, HiddenScreenMotion 2/2, EarlyTerminalGrid 3/3, 0 failed. PaneMotionWorkTests skipped its 4 tests there (gated on CMUX_PANE_BENCH=1); its own run with that env: step cd4911f149e8302844c180d4 (cmux9s, GUI) PASSED 4/4 (5 cases), 0 skipped.

  • Red 4, 2ed1779f521 (KeyboardResizeHoldTakeoverTests, second review FIX FIRST at 593effbd3d7, comment 6591798082): step 60347dfc474b93a39e7eb409 (aws-m4pro-4, headless) FAILED: 2 tests, 96 issues. onA2xScreenTheHeldContentKeepsItsEdgeThroughTheLanding (both directions, 18 issues): the held edge moves 60 pt on a 2x screen. aSplitDuringAKeySpringResizesThePanesThatWereMovingLive (78 issues): p1 and p2 keep their 600 x 801 pre-press content through the split's spring (bounds 583.5 x 801, 616.5 x 792). Fix 4, 72e02cae39e: compile-checks 87d3e9049aa87bced05e5cbd (fix) and b7f46bf5e50c9bbf200ce2ec (red) PASSED; green + GUI proof (display worker gui-session-v1, CMUX_TEST_REQUIRE_GUI=1, CMUX_PANE_BENCH=1) at the exact head 72e02cae39ecddbcca5d17060f1dd1f8909f2d58: step 4ac262b45fd49891347ea683 (cmux14; the first try 29dd1371 failed at checkout on cmux10s, DNS, no test ran) PASSED 11 of 11 suites, 0 skipped: HoldTakeover 2/2, HoldLifetime 4/4, ReflowAfterLanding 1/1, ContentHold 1/1, ShownLimit 2/2, Rows 2/2, PaneResizeGesture 4/4, PaneMotionContentHold 11/11, PaneMotionWork 4/4, HiddenScreenMotion 2/2, EarlyTerminalGrid 3/3.

Films, kit v5 (cp/resize-keys-kit, each press with the core tier it started on), before3 = feat 11e5aeaa (build 2b9d7c93), after3 = this head merged on that feat (build b44fc869), in turn on cmux24, H/L dropped refreshes per press:

  • before3: browser-agent [5,6,0,0,5,6,0,0], [4,4,0,0,2,1,0,1], [5,5,0,0,2,1,1,1]; idle (all H/L) [6,6,7,6,8,6], [4,5,4,4,4,5], [6,6,7,5,5,6].
  • after3: browser-agent [0,0,0,0,0,1,0,0], [1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0]; idle [1,1,1,1,1,0], [0,0,0,0,0,0], [0,0,0,0,0,0].
  • Every press of both builds started on S or P cores (none on E). H/L per press: before3 2-8 dropped refreshes (median 5), after3 0-1.
    Fix-2 films (build 46062c0d, without the tier probe): H/L 5-7 dropped refreshes before, 0-1 after, on cmux22 and cmux24.

Observed / Not run

  • Observed: the steps and films above; gallery https://cmux-orchestrator-1.tail137216.ts.net/resize-videos/.
  • The films are of fix 3 (593effbd3d7). Fix 4 (72e02cae39e) changes only the 2x edge choice and a structural takeover; it is not filmed again.
  • Not in this PR: a press that starts on E cores (a main thread woken from idle) still misses the next refresh: its key turn takes 11-14 ms there against 4-5 ms on S (rk-a2i-xi). That is a follow-up (drag-margin and tracking-area work in the commit, the presentation pass in the key turn).

No capture: motion, filmed by the RESIZE KEYS kit.

Changelog

  • Fixed: Ctrl-Shift-H/J/K/L and Ctrl-Cmd-arrows no longer stutter when a browser page or an agent chat is beside the divider; each pane lays out once when the motion ends.

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


Summary by cubic

Fixes keyboard resizes (Ctrl-Shift-H/J/K/L) stuttering when a browser page or agent chat sits beside the moving divider.

  • Each key press laid out pane contents on every spring frame — browser chrome, CEF views, chat graphs, tab strips — dropping 4-8 frames per press.
  • The screen now holds each pane's content at its start size through the spring, clipped where the pane is smaller, and lays it out once after the landing frame's commit.
  • Held content stays pinned at the edge nearer its rest through the landing so it does not jump, and the hold clears on every path (Reduce Motion, a motion landing at once, a split or zoom taking over, or a new spring during the previous hold's tail).
  • Splits, closes, and zooms keep their live resize behavior; the agent chat's own content hold is unchanged.