fix(next): the sidebar's content hold changes the content's frame once; per-frame trace of both modes
Toggling the sidebar no longer shifts the content and snaps it back in either sidebar mode. This PR fixes the opt-in content hold so it changes the content's frame once and leaves it still. It also adds a per-frame trace that proves both modes reach their landing with no bounce.
Leo:
when i toggle the sidebar on and off I STILL SEE THE ENTIRE OTHER PART OF THE APP SHIFT LAYOUT FOR NO REASON AND SNAP BACK
Cause
The slide's content hold (MainPaneCardView.contentHold) was added by the GPU audit of 2026-10-21 so panes lay out once per toggle, not on every frame. It kept the content at the widest width of the slide and pinned it to the sidebar's moving edge:
- Show: the old wide layout rode the sidebar's edge across the window, its far side clipped, then laid out narrower when the slide landed. Centred and trailing content slid right and jumped back.
- Hide: the content was laid out at its final width at once, but at the card's old edge, then rode back.
#29894 (a carry of #28894), which landed while this was in flight, made the default sidebar.slideHoldsContent: false. The content now follows the card on every frame, so the default no longer snaps. This PR keeps that default.
Fix
The hold, still in Debug Settings, now takes the card's landing width when the slide starts. It pins the content to the card's far edge, which doesn't move (ContentHold.pinsTrailingEdge: the trailing edge for a left sidebar, the leading edge for a right one). The content is laid out once, on the first frame, at its final size and place, and clearing the hold at the landing changes nothing. That's still one layout per toggle, so the GPU audit's saving holds when it's on. A reversal mid-flight lays out once more, at the new landing width. The rail style, the sidebar's own animation and the default path are unchanged.
Performance
Per-frame trace from SidebarToggleContentTraceTests: real display ticks, a 1100x700 window, a 300 pt left sidebar. Each sample is the content's frame in window coordinates on one display frame. Steps: red 8ee6ecb4d5e2d4e91b046149 at 0a4c827a92f (base plus tests), green d5b6044761f6125b5e255ae5 at c9f93278319.
| Metric (one toggle) | Before | After | Delta | Harness |
|---|---|---|---|---|
| Hold on, show: content frame changes | 15 (rides the edge 6 → 47 → 79 → … → 306 at 1088 wide, then snaps to 788) | 1 (306+788 from frame 1) | −14 | trace, steps above |
| Hold on, hide: content frame changes | 11 (241 → 204 → … → 6 at 1088 wide) | 1 (6+1088 from frame 1) | −10 | same |
| Hold on: content layouts per toggle | 1 | 1 | 0 | same |
| Default (follow), show: frames that turn back toward the start | 0 (13 steps 6+1088 → 71+1023 → … → 306+788) | 0 (14 steps, 42+1052 → … → 306+788) | 0 | same |
| Default (follow), hide: frames that turn back toward the start | 0 (11 steps) | 0 (11 steps, 249+845 → … → 6+1088) | 0 | same |
| Default (follow): changes after the slide lands | 0 | 0 | 0 | same |
The default is #29894's behaviour on both sides. The trace pins it: the content's minX, maxX and width only move toward where they land, and nothing changes after the landing. It does resize the content on every frame, the cost the GPU audit measured at 6.7–7.4 ms of main thread a frame. The hold avoids that.
Tests
Red first: 0a4c827a92f is the base's production code plus the tests; the fix is c9f93278319.
cmux-ci run --class light --script scripts/ci/package-test-lane.sh --display --env CMUX_TEST_REQUIRE_GUI=1 --arg=suite --arg=Packages/macOS/CmuxNext --arg=SidebarSlideHoldsContentTests,SidebarToggleContentTraceTests,SidebarToggleSettlementTests
-
Red at
0a4c827a92f:SidebarSlideHoldsContentTestsfails 3 of 9:- hide: the content moved 208 pt on screen;
- show: the content stayed 988 wide instead of its 780 landing width, and the landing changed its frame;
- turnaround: also fails.
SidebarToggleContentTraceTestsfails for the hold, with 15 and 11 frame changes; its default cases pass. -
Green at
c9f93278319:SidebarSlideHoldsContentTestspasses 9 of 9,SidebarToggleContentTraceTestspasses all 4 cases (hold and default, show and hide), andSidebarToggleSettlementTests(#29894) passes.
Observed / Not run
- Observed: the runs above, on fleet display workers (Xcode 26.6, macOS SDK 26.5). The pre-push gate passes. An independent Opus review at
c9f93278319returned SHIP. - Not run: a full app session with a live transcript, terminal and Chromium page. The trace uses a plain content view. Only a left sidebar was traced; the right sidebar is covered by unit tests.
No capture: the change is motion and opt-in; the trace is the evidence.
Prior art: #29894 / #28894 (the default), #24342 (introduced the hold), #18840 (classic sidebar), #21125 (right-sidebar pane widths). Owner note in plans/cmux-next/sidebar-owner.md.
Changelog
Fixed: With "Hold content size in sidebar slide" on (Debug Settings), showing or hiding the sidebar no longer shifts the rest of the window and snaps it back.
🤖 Generated with Claude Code
Agent session: agent session