cmux NEXT multi-view: a row dropped on Home's right or bottom edge shows its workspace beside Home (Debug toggle)

Merged
TE
12d ago
+210-16

Summary

Multi-view (#23437, #23651, #23924) lives at Debug Settings > Sidebar > sidebar.multiView ("Navigate on release (multi-view prototype)"). It is still off by default; this PR doesn't change that. With it on, hold a sidebar row and drag it onto an edge of the workspace on screen. That workspace then shows beside the current one, and every workspace on screen is lit in the sidebar.

Home (Chief) edge drops didn't work in that view. The #23651 dogfood found that a row dropped on Home's right edge did nothing, and one dropped on its bottom edge cut Home off. Both now place the dragged workspace beside Home:

  • Right edge. Home's pinned dock takes no tab drop, so the layout gave no pane target and the drag fell through to .cancel.
  • Bottom edge. The screen's bottom edge dock band answered first, so the drag made a new dock of Home instead of placing the workspace beside it.
  • The fix. With the toggle on, a drag over a workspace on screen goes beside it at the nearest edge (within a quarter of its size) wherever the layout has no split edge there: a pane that takes no drop, or an edge dock band (WindowController.besideEdge, WorkspaceDragResolver.outcome). Center and column drops still merge, and with the toggle off nothing changes.

For captures, debug.mouse (DEBUG and bench builds only, never a shipped app) takes row (a workspace's name or id, giving its sidebar row) and a drag's to_edge, so the new multi-view tour drives the real hold-then-drag on any window size.

Leo-ask: sr2-01a1608f-66bb
Leo-ask: ask-c7aeeb3219
Leo-ask: ask-f86b228564

Changelog

none

Testing

SidebarMultiViewHomeTests lists Home the way the daemon does (its page tab alone in a pinned left chat dock). It drags a row to Home's right edge and to its bottom edge, in the pane's split zone (15% in) and in the bottom dock band (4% in). Each drop must resolve to .beside(edge), show the workspace beside Home with its tabs unmoved and both rows lit, and leave Home's panes inside its half.

The dock-band case drops 8 pt from Home's bottom edge with the daemon's edge-docks-v1, where the layout offers a new bottom dock of Home. A scratch commit (scratch/mvhome-dockband-red, e005a416022b) is this head without the .newDock drop in WorkspaceMerge.hit, to show that case catches it. That run is queued (steps 843f489cdac3 and c6c8f8023d8d).

Red at 4cb01860eeb6 (test only, on base 35f14d980606), step 86c8c8da2d272d5edd011f0d on aws-m4pro-9: all three cases fail. The hover is .cancel, so nothing is placed, and SidebarMultiViewWindowTests passes.

cmux-ci run --class light --script scripts/ci/package-test-lane.sh --ref <sha> --key mvhome-before-4cb0 --target-worker aws-m4pro-9 --arg=suite --arg=Packages/macOS/CmuxNext --arg=SidebarMultiViewHomeTests,SidebarMultiViewWindowTests --env CMUX_CI_XCODE_APP=/Applications/Xcode_26.6.app

Green at d7d0749a3a42 (the fix, before the test-only follow-ups), step 263722e5a80e28c7090411fc on aws-m4pro-9: all 6 suites pass (SidebarMultiViewHomeTests, SidebarMultiViewWindowTests, SidebarMultiViewPressTests, SidebarMultiViewDropTests, DragGlassTests, WindowCloseNeighborTests). Green at head 42814b41b3f8 is queued (steps 5177550a4ada and 32366a52a320).

Compile: cmux-ci compile-check --app passed at head 42814b41b3f8 (job be3f9a08fcc11c126853d8ac).

At head aa23d2a8f277 (2026-10-23, adopted by sidebar-rows)

At head 242c1fb465b (2026-10-26, adopted by sr-rev24067-aa23d2a-2)

  • Two defects found and fixed at this head, both by review and CI rather than by the carried receipt:
    • DebugMouse+Rows.swift was #if DEBUG while the DebugMouse.swift it extends is
      #if DEBUG || CMUX_BENCH_HOOKS, so the bench configuration (reload.sh --config bench,
      check-release-compile.sh --bench-hooks: Release, no DEBUG) did not compile. Fixed in 6f8980778cb.
    • SidebarMultiViewHomeTests.swift:35 asked for the edge-docks capability through
      DaemonCapabilities.shared.edgeDocks. Base's DaemonCapabilities is a namespace of four static
      wire-name forwards with a private init and has neither member, so CmuxNextAppTests failed to
      compile and took down cmux-next swift test and cmux-next generated files. The base merge was
      conflict-free, so git hid it. Fixed in e56998e81f4 with DaemonCapability.edgeDocks.rawValue,
      the spelling the production code uses; same wire value edge-docks-v1.
  • Compile: cmux-next app compile (build fleet) passed at 242c1fb465b.
  • Review: Codex gpt-6-astra xhigh, SHIP at 242c1fb465b239790f7ce89c3e753c4f27091dc6
    (receipt), a delta review
    of the lander's automation base merge; the PR's own patch is byte-identical and none of its 9 files
    was touched by that merge.
  • Base reds only, each checked: nightly-guards / workflow-guard-tests / release-notary and
    nightly-guards / Guard status fail the same way on base;
    release-compile-derived-data.test.sh is red because base 9482d09c430 added
    -DCMUX_BLOCKING_CHECKS to the bench defines without updating that test's expected string, and the
    four files it exercises are byte-identical to base here; the 3-file GENERATED.md drift in
    cmux-next generated files reproduces identically on unrelated PR #25115.

Test execution: executed on a GUI mini at this head

The multi-view drag tests have now really run at 242c1fb465b, on the GUI capture mini
cmux7s-Mac-mini.local (step 0f41e7abb4ef2a93a9ac86b5, dispatched with --target-worker). Both of
this PR's key cases executed, the bottom dock-band case included:

◇ Suite SidebarMultiViewHomeTests started.
✔ Test aRowDroppedOnHomesRightEdgeShowsItsWorkspaceBesideHome() passed after 0.749 seconds.
✔ Test aRowDroppedOnHomesBottomEdgeStacksItUnderHome(points:) with 2 test cases passed after 1.110 seconds.
✔ Suite SidebarMultiViewHomeTests passed after 1.860 seconds.

SidebarMultiViewWindowTests ran its 13 tests on that host too, withTheToggleOffAnEdgeDropStillMerges()
and turningTheToggleOffShowsTheFocusedWorkspaceAlone() among them, so the toggle-off invariance is
covered by an executed test and not only by review.

A caveat worth keeping, because it made two earlier green reports meaningless: on a display-less
fleet host these suites skip and the lane's summary table still prints them as passed. In a focused
run at e56998e81f4 on aws-m4pro-6 (step 1eabb2b7a25cdb985eb6ce99) the step log shows

➜ Suite SidebarMultiViewHomeTests skipped: "the drag tests need a display"
➜ Test aRowDroppedOnHomesRightEdgeShowsItsWorkspaceBesideHome() skipped: "the drag tests need a display"

while the summary printed SidebarMultiViewHomeTests passed 10s. CMUX_TEST_REQUIRE_GUI=1 did not
change it and a --label gui dispatch is refused. So the earlier "all 6 passed" line at
aa23d2a8f277, on aws-m4pro-5, is not evidence that those drag tests ran. Target a GUI mini.

The in-CI cmux-next swift test job never produced a verdict on this PR: on e56998e81f4 it wedged
(1293 tests stuck past the 300 s detector, swift test exited 143 on SIGTERM, 4 of its 10 named reds
identical on unrelated PR #25115), and on 242c1fb465b it is refused at Set up runner by the
glaeda disk floor (12.0 GiB free, 40 GiB required on cmuxs-mac-mini-6, which is at 99% full;
cmux14 sat at 10.8 GiB against a 30 GiB floor across several attempts). That is a fleet disk
problem, not a failure of this PR, and it is why the suites were run directly on a GUI mini instead.

At head 6f8980778cb (2026-10-25, adopted by sr-rev24067-aa23d2a-2)

  • Base brought in once: feat-cmux-next b4bd1fe0596, no conflicts; the PR's own diff is unchanged (the nine files below, same per-file patch IDs as at aa23d2a8f277).
  • Reds at aa23d2a8f277 were all base debt that base has since fixed or still carries: the SwiftUI allowlist and canary coverage (fixed by #25021), test_cmux_next_perf_gate_unlit.py and the checks-job-structure test (#24822 and 4a793f4843b), and the Ghostty notices pins. All four pass at this head. The two reds left, nightly-guards / workflow-guard-tests / release-notary and nightly-guards / Guard status, fail the same way on base b4bd1fe0596 (run 40240146434, same failing steps), and release-compile-derived-data.test.sh is red on base too: base 9482d09c430 added -DCMUX_BLOCKING_CHECKS to the bench defines without updating that test's expected string, and this PR does not touch any of those three files.
  • Fix found by review at this head: DebugMouse+Rows.swift was #if DEBUG while the DebugMouse.swift it extends is #if DEBUG || CMUX_BENCH_HOOKS, so the bench configuration (reload.sh --config bench, check-release-compile.sh --bench-hooks: Release, no DEBUG) did not build. 6f8980778cb widens that one #if to match its siblings.
  • Review: Codex gpt-6-astra xhigh, SHIP at 6f8980778cb79146608947b7be25e56d7c3ccc37 (receipt). FIX FIRST at 5ff6e19f664 for the bench compile above, re-reviewed after the fix.

Risk

risk:normal. The whole behaviour sits behind Debug Settings sidebar.multiView, off by default, so with the toggle off nothing changes for anyone. The review traced each of the three production edits and confirmed the toggle-off path is identical to base: WindowController+MultiView.swift:98 returns no beside edge, WorkspaceDragResolver.swift:58 makes no beside fallback, and TabDragSession+WorkspaceMerge.swift:45 returns the original dock proposal. That makes this the contained kind of sidebar change that lands through the normal path (Leo, 2026-10-23), so the hold label is removed. With the toggle on, the known gaps are in "Observed / Not run" below: a fallback beside target draws no split preview, and a row dropped in a screen edge dock band goes beside instead of making a new dock.

Observed / Not run

Observed:

  • The fleet runs above.
  • prepush-gate.py reports no new violations.
  • GODFILES_WARN_SLACK=20 check-no-godfiles.sh adds nothing from this branch. It exits 1 on base debt only (for example WindowController.swift at 500 lines, unchanged here).
  • An independent review subagent read the full head three times. Its findings (the dock-band case missed the band, then the fixture had no edge docks) were fixed test-first.

Not run:

  • The suites on display-less hosts, where they are skipped.
  • A Home edge drop in the app by hand. The capture drives the right edge through the app's event queue; the bottom edge is covered by the tests only.

Known gaps (behind the Debug toggle):

  • A fallback beside target (Home's edge, a dock band) moves the drag's ghost to the half it will take, but draws no split preview in the layout.
  • With multi-view on, a workspace row dropped in a screen's edge dock band goes beside instead of making a new dock.

Capture

Before: base 4ae5de440131, with the toggle off (its default). Two workspaces were made; one is on screen.

Capture steps-f9e3e2cca4 at 4ae5de440131 (fleet build, capture mini, text checked for private data)

LightDark
lightdark

After: this head, tour:multi-view (scripts/cmux-next/media/tours/multi-view.json). It turns Debug Settings sidebar.multiView on, shows Home alone, then holds api's sidebar row and drags it onto Home's right edge (debug.mouse through the app's event queue). api's terminal now shows beside Home, Home keeps the focus, and api's row is lit as on screen.

Capture tour-multi-view at 42814b41b3f8 (fleet build, capture mini, text checked for private data)

LightDark
lightdark

video
Full quality:

Agent session: cosmic-gray

🤖 Generated with Claude Code