P0 RESIZE KEYS: a keyboard resize press starts its spring in the key's own turn (first frame in the next refresh)

Merged
LA
3d ago
+30-0

Summary

P0 RESIZE KEYS (cmux-ad; lead 2026-11-02 21:1xZ, Lawrence's case: "the first frame of the move is in the next refresh after the key"). A keyboard resize press (resizePane*, Ctrl-Shift-H/J/K/L and Ctrl-Cmd-arrows) wrote the layout model; the layout heard it through its observation task, a later main-actor turn, so a display tick that ran first moved nothing and the first moved frame came a refresh later. PaneResize.press now calls LayoutRootView.syncWithModel() after the model write (the call the App already makes after a daemon tree, so a split's frame has its panes): the spring starts in the key's own turn and the very next display frame moves. The observation finds nothing new afterwards; no extra layout work.

Measured (films at 120 Hz, real HID keys, before = base ddcaf92 build fddf4464, after = this fix + K3 hold build f44441a2, same minis): the first film frame that shows the move, median 2.81 -> 2.00 refreshes after the key (max 4 -> 3). A divider drag, which moves panes in its own event turn, shows 2.7 (dogfood-2f3a572-rv5-120x1/col-drag-fast): the rest is the compositor and capture pipeline, the same for every input.

Testing

On the fleet (scripts/ci/package-test-lane.sh suite Packages/macOS/CmuxNext ...), compile-checks first (c8da2865 red, 88ad54f3 head: passed):

  • Red d8c15d4a863 (KeyboardResizeFirstFrameTests): step 7feeecc6f9ee88f61ff483ee (aws-m4pro-9) FAILED: the first display frame after the press did not move (.left, .right).

  • Green + GUI proof (display worker gui-session-v1, CMUX_TEST_REQUIRE_GUI=1) at the exact head 1b1f02a02e4a7a511c0d1e1b2581c028bbb26130: step 2656ce63b22d79998fdd4459 (cmux10s) PASSED: KeyboardResizeFirstFrameTests 2/2, KeyboardResizeShownLimitTests 2/2, PaneResizeGestureTests 4/4; 0 skipped.

  • Independent review: SHIP at the exact head (comment 6590259429). Its follow-up note: equalizeSplits likely has the same one-refresh delay (no sync in its handler); not in this PR.

Observed / Not run

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

Changelog

  • Fixed: a keyboard pane resize starts moving in the next display frame after the key.

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 pane resize so the spring starts in the key's own turn: the very next display frame moves the pane, instead of one refresh later.

Previously, a resize press (Ctrl-Shift-H/J/K/L, Ctrl-Cmd-arrows) wrote the layout model, but the layout only heard the change through its observation task in a later main-actor turn, so a display tick that ran first moved nothing. PaneResize.press now calls LayoutRootView.syncWithModel() immediately after the model write — the same call the App makes after a daemon tree — so the observation finds nothing new and no extra layout work runs. Adds KeyboardResizeFirstFrameTests verifying the first display frame after the press moves, for both left and right directions.