cmux NEXT: a link opened to the right shows in its split in the click's frame, never in the source pane first
Leo (2026-11-03): "it's so slow to open and close idk if there's some sort of threading issue but it's nigh instant for claude and codex so we nede to be at least as fast", and "the browser/tab opening animation still plays on the main pane before going". Earlier ask (#23032's title): "a link opened to the right appears in its split, never in the source pane first".
leo-named-fix. The daemon half, #32862, has landed (de2ecaf14b8).
What
A web link LinkOpener puts in a new split right or below (a chat link, a terminal Cmd-click, a file page's link) no longer gets made as an unselected tab of the source pane, then waits for the store to list it (up to listLimit, 30 s) before a TabMoves.toNewSplit and a second wait: two daemon round trips with nothing on screen, and the opening played on the source pane first.
Now, when the pane's daemon serves frontend-browser-tab-split-v1 (plus split-client-keys-v1):
BrowserTabSplitCommand(CmuxNextDaemonService) puts a provisional split with a stand-in browser tab in the store in the click's turn, and the window lays it out in that frame, the way an agent tab's split (ConversationTabSplit) and Cmd-D already do.- One
new-frontend-browser-tab {pane, split}makes the tab in the daemon's new pane, which replaces the provisional one by its client-minted id. Even split sizing is shown at once and committed on the reply, or rolled back on a refusal. LinkOpener.opentakes an optionalSplitMake;.splitRight/.splitBelowuse it and fall back to make-and-move when it answers nil (an older daemon, a remote pane without browser tabs, Home's pinned dock, an incognito pane, a pane without split room)..newColumn,.besideDockand.dockChatare unchanged here.
Review fixes (router-review gpt-6.1-sol BLOCK at 60274768): the open's turn ends only once the store lists the daemon's pane, not just at the reply, so the next queued link never aims at the provisional pane; incognito panes keep make-and-move, since their record holds about:blank until the reply registers the URL. The bench's quick arm skips commands with no key (link_right).
Not in this PR (#33021): folder and terminal opens to the right still use make-and-move, and turns.serially still serializes opens beside one source.
Carried from austinywang's #23032: PaneBrowserTabSplit (now BrowserTabSplitCommand, moved into CmuxNextDaemonService), the split request field and connection check, the stand-in ProvisionalTab.browser(_:), the split-room rule, and LinkOpenSplitDirectTests (adapted to today's opener). Those commits carry Co-authored-by: Austin Wang.
Also: LinkDragItem and LinkDropPlan moved from CmuxNextApp into CmuxNextAppCore and existingPane moved onto LinkOpenPlacement.Target, so the App target does not grow. debug.new_tab {action: bench_create, command: link_right} times a link opened to the right (click to the frame the new pane shows).
Tests
LinkOpenSplitDirectTests (CmuxNextAppTests): a link to the right shows a split intent with the stand-in at once, the source pane never lists the tab, and exactly one create goes out carrying split with the provisional ids; the open's turn waits for the daemon's pane, not just the reply; an incognito pane keeps the move; without the capability the tab is made in the source with no split; New Column still moves; a split maker that answers nil falls back.
Performance
Same fleet Mac for both arms (instant-new-surfaces-bench.py --commands link_right --arms warm --phases idle,load --runs 12). Before: 0d15fd4651a0 (#32862 plus only the bench command). After: 71fd6d36802 (this head).
| metric | before | after | delta | harness or run link |
|---|---|---|---|---|
| idle link_right visible_ms p50 | 340.8 | 103.6 | -237 (-70%) | cmux-ci steps 81efa5771658 / 20e57e757a53 |
| idle link_right visible_ms p95 | 378.1 | 106.9 | -271 (-72%) | same |
| load link_right visible_ms p50 | 336.1 | 188.8 | -147 (-44%) | same |
| load link_right visible_ms p95 | 522.5 | 206.2 | -316 (-61%) | same |
| idle frames to visible p50 / p95 | 4 / 4 | 1 / 1 | -3 | same |
| idle confirmed_ms p50 | 442.4 | 215.7 | -227 (-51%) | same |
| load confirmed_ms p50 | 448.8 | 294.2 | -155 (-34%) | same |
| key_ms (click's main-thread turn) p50 / p95 | 0.35 / 2.6 | 9.0 / 15.4 | +8.7 / +12.8 | same |
The split now shows in the first frame after the click (frames to visible 1, from 4) and never in the source pane. The click's turn costs more: it now records the split intent and lays out the window in that turn, as Cmd-D does, instead of doing nothing until the daemon replies. The p95 of 15 ms is above the 10 ms action budget; #33021 tracks trimming it.
Observed / Not run
- Ran on the fleet at 71fd6d36802: CmuxNext compile passed; LinkOpenSplitDirectTests, CmdClickOpensRightTests, SplitBrowserFailureTests, BrowserEnabledToggleTests, LinkDragDropTests and RightColumnAfterSplitTests all passed (6 of 6 suites).
- Regression tests for the review's two findings:
theTurnWaitsForTheDaemonsPaneNotJustTheReplyandanIncognitoPaneKeepsTheMove. - Not run: a tagged-build click-through by hand; the timing above is from the bench's scripted open.
Risk
risk:normal. Opens to the right on a current daemon change path; older daemons keep the old path. A refused create rolls the split back.
Changelog
Fixed: a link opened to the right shows in its new split at once, never as a tab of the pane it was clicked in first.
Agent session: agent session
š¤ Generated with Claude Code