Skip to content

cmux NEXT: a drag during a spring takes over where the edge shows; shared edges never open (FRAME OWNER S2B) - #35036

Merged
lawrencecchen merged 21 commits into
feat-cmux-nextfrom
fix/frame-owner-s2b-shared-edge
Nov 4, 2026
Merged

lawrencecchen merged 21 commits into
feat-cmux-nextfrom
fix/frame-owner-s2b-shared-edge

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

FRAME OWNER REFACTOR S2B. A drag that starts while panes still spring (a key resize, a release, a column growing) takes over where its edge shows. Two panes that share an edge show it at one place in every frame, the press moves nothing, the pane follows the pointer 1:1, and no pane shows a negative size. Before, the shell showed between neighbours (up to 92 pt) or they overlapped (up to 80 pt), and a regrabbed divider kept sliding under a still pointer.

Root cause

During a pointer gesture, ScreenContentView.place snapped a whole frame (all four edges) whenever the drag retargeted it, and a drag measured the pointer against the rest layout. If a spring still moved a neighbour, the dragged column's panes jumped to rest while the neighbour stayed on its spring. A release fling wrote velocity to whole frames.

Fix: rule C (lead decision; the motion rule "an animation is interruptible from its current value")

Behind motion.frameOwner.sharedEdges (Debug, default on), latched when a drag starts. With the switch off, the old path is unchanged.

  • The press (DividerDrag.catchShown): the drag's own value (the split's ratio, the column's width) is set to where its edge shows from its anchor. The anchor is the nearest edge among the panes the layout puts on the other side. The value is written in the drag's own transaction, and the window syncs it in one pass in which every frame keeps where it shows and its velocity. Each edge then gets its share of the change of speed that stops the dragged line against its anchor (SharedEdgeMotion.Influence: how far the edge moves when the value moves, from an unrounded probe layout), so shared edges always get the same change. The drag then starts from that layout.
  • Each move (SharedEdgeMotion.place): each component of a retargeted frame moves by its target's change and keeps its velocity. A component at rest lands on its target exactly, so a drag with no spring places frames as before.
  • The release (SplitMotion.seed): a fling seeds only the edges the release moved. A frame that is new in that pass keeps the motion it rides.
  • Cancel (a click, Escape): the unconfirmed release the catch replaced is sent again in a new transaction. A modifier mode that stops setting the caught key puts it back at the caught value.
  • Fallback to the old drag (whole retargeted frames snap to rest, as shipped today):
    • the press finds no anchor frame, or its probes cannot move the line;
    • the caught value, laid out on the screen's own pixel grid, does not put the line within 0.5 pt of where it shows (a value the layout clamps);
    • any pane's width or height spring, followed along its whole path, could go further under its rest size than a pane's minimum (any drag mode can shrink a rest size only to that minimum).
  • Row-edge drags: no press catch. They take the old drag while the screen moves.

Changelog

  • Fixed: dragging a divider or a column edge while panes still animate no longer opens a gap or an overlap between neighbouring panes, and the pane follows the pointer from where it shows.

Tests

SharedEdgeDuringSpringTests (new, 10 cases, checked at every 120 Hz frame tick). Run on the fleet:
cmux-ci run --class light --script scripts/ci/run-swift-testing-suites.sh --arg=Packages/macOS/CmuxNext --env CMUX_SWIFT_TEST_SUITES=SharedEdgeDuringSpringTests

The checks in every case:

  • shared pane edges, and the split divider against b1's edge, stay within 0.5 pt of their rest gap;
  • no spring shows a negative size;
  • the press moves no frame, and a still pointer holds the dragged edge;
  • the fling seed is set, and a new pane keeps its neighbour's speed;
  • every frame lands at rest on its target.

The red proof is the tests-only branch scratch/s2b-red4 (the feat tip + the test file only), so the commit order on this branch is not red-first.

  • Red at 9b2cc36 (step c19136345aa4c31e07759827): 7 of 10 fail. clickDuringReleaseSpring, releaseSpringThenKeyPress and shrinkColumnDuringInnerSpring pass on feat too; they are guard cases for the rule.
  • The new-pane case grows A by width, because a key press trades width between A and B and does not move C.
  • Probe without the negative-size guard (scratch/s2b-probe-noguard b6dbb1e, step b62adaeed572bb2da01ba796): shrinkColumnDuringInnerSpring fails (b1 at -105 pt, edges open by about 100 pt).
  • Green at 3fbd40a:
    • step 5aedc96a4d4d1f8a75d8a0c4: 28/28 (SharedEdgeDuringSpringTests 10/10, DividerDragFollowsPointerTests, and the 26 S2 suites);
    • step 4d571a35206f3b81c5f57f34: 32/32 extra layout suites.

Review

Codex (gpt-6.1-sol, no tools; the pack held the full diff, the changed files and the model, sync, reconcile and spring code it calls):

  • Reviews 1 to 6 said FIX. Their blockers were the shift rule's spring leftovers, the catch edge selection, velocity-only catches, a missing-anchor fallback, stale override restore, negative sizes in other drag modes, and clamped catches. Each is fixed.
  • Review 7: Review (codex): SHIP at 3fbd40a34c1e33c4b40e81d78e8b7e3ac1480fca.
  • Not done here, from its should-fix list: a fractional-clamp test, vertical and dock-edge catch cases, and a comment that still says a clamped catch springs to the nearest value. These go to the switch-delete PR, so this head and its films stay valid.

Bench (switch OFF vs ON, same host, interleaved OFF/ON/OFF/ON)

No regression (pixel-perfect). cmux22, LayoutDragBench + PaneMotionBench, CMUX_DRAG_BENCH_ROUNDS=5, runs OFF, ON, OFF, ON (OFF: scratch/pixel-perfect-s2b-off-3fbd40a 81642f1, only the switch default false). Per-frame main-thread ms:

case p50 OFF p50 ON p95 OFF p95 ON max OFF max ON
drag column 0.220-0.221 0.217 / 0.217 0.231-0.232 0.234 / 0.227 0.52 0.88
drag split 0.212 0.212 / 0.213 0.220-0.223 0.221 / 0.224 1.31 1.32
  • Five pane cases (close x2, splitDown x8, zoom x2, zoom x30, zoom x8) were outside the OFF spread in the first ON run only (job 08b285d1). The second ON run (job 7a2839f2) is inside the spread or its 5 % band in each, for example zoom x30 p95 0.463 then 0.355 (OFF 0.332-0.345). All p50s are inside. Outside a drag, S2B adds only a constant guard per place call.
  • Every case is under 0.65 ms p95. The only max over 4 ms is unzoom x30, in both arms (OFF 5.22, ON 6.11).
  • Table: /work/tmp/pixel-perfect/logs/s2bd-bench-compare.txt.

Films

GREEN for S2B's scope (pixel-perfect). Release build 9453c297 at 3fbd40a, cmux22, terminal-only layouts at x0.125, OFF then ON in one launch, judge_pixel 3d+C f6c2ef7. Both presses grabbed the edge (column drag travel 170-171.5 pt, split drag 120 pt; 20-21 pt of the key spring left at the mouse-down).

OFF ON
p0|p1 divider off the middle of its panes' gap (trace samples, max) column 84 (15 px), split 85 (15.5 px) 0, 0
Shell past rest on p0's right and p1's left edges up to 16 px none (split drag: 2 px on two edges)
p0's right content edge off 121-123 frames (8 px; rings hidden 25 frames, settle 26) 3-4 frames (2 px)
Clock fit (3d) split film +1 refresh late; column 0 0

Frames notes (not blockers):

  • Dragged pane (terminal): OFF shows the content at its old size for about half the drag (57 of 111 drag frames: the old drag path's hold); ON keeps the content at the moving edge in every frame (175 of 175), within 10 px (its own size steps), with no shell gap. Measured against p1's own tab strip right edge in the same frame (pixel-perfect's correction: the first count missed the frames where OFF's content was not at the edge at all).
  • In both arms, the panes the key moves keep the key-resize content hold through the drag (K3/S3), so their terminal content leads or trails the moving edge by 3-15 px in 290-440 frames. That is m6 1a (S4 changes the key-resize path), not S2B. With ON the hold goes on into the drag instead of the OFF snap.
  • The first round with Chromium-page layouts (ab-s2b-sw-3fbd40a) gave no verdict: the page window beside the moving edge took the mouse-down (a PL-motion-cef defect, reported in STATUS), so the films use terminal-only layouts with the same geometry.

Judge reports: /work/tmp/pixel-perfect/judge/s2b/ (s2bt-col-, s2bt-split-).

Observed / Not run

  • Observed: the fleet runs above (red, probe and green step ids), the prepush gate, check-no-godfiles (no god type grew) and check-motion.
  • Not run or not covered:
    • catch tests for a vertical split and docked column edges (the same rule on the other axis or edge);
    • pressing during a structural change;
    • a minimum smaller than the style minimum (tiny windows).
  • Pre-existing and unchanged: the screen's step stops on positions, not on velocities.

No capture: the change is frame timing during motion; the films from the refactor owner are the evidence.

…ery frame, also when two motions overlap (FRAME OWNER S2B)

FRAME OWNER REFACTOR stage S2B, the test that decides whether S2B is needed (the
refactor owner's rule: today's films show no gap between two springs; a fix lands only
if this test is red at the feat tip).

SharedEdgeDuringSpringTests (CmuxNextAppTests): layout A | B (split x: b1 | b2) | C, the
test as the display clock (120 Hz). At every frame tick, each pair of panes that shares a
vertical edge at rest shows the same gap as at rest (no shell gap, no overlap), and a
dragged edge moves with the pointer from where it showed at the press. Three overlaps:
- a key press grows column A (its edge springs) and, during that spring, a drag starts on
  B's column edge;
- the same, with the drag on the split divider inside B;
- a Shift drag of the split lands on a snap (its release springs) and, during that spring,
  a key press grows column A.

Why it may be red (code reading): each pane and divider frame is its own spring, and a
drag snaps only the frames it retargets (`ScreenContentView.place`, M3), so a column on a
key spring and the dragged column beside it can show from different motions; and a drag
starts from the rest geometry (`DividerDrag.start`), not from where a springing edge shows.
…during a key spring keep shared edges together

Two more cases in SharedEdgeDuringSpringTests, before the S2B fix (the refactor owner's
conditions for the fix):
- keySpringThenPushDrag: a key press grows column A and, during that spring, an Option drag
  of the split in B (B grows and pushes C);
- keySpringThenFlingRelease: a key press grows column A and, during that spring, a Shift drag
  of the split in B released at 600 pt/s: the release lands on the snap and seeds its
  spring's velocity (`SplitMotion.seed`) while A still springs.
The first red run (step 8cf32b98462d7aedc9d4cf18 at c43f92c) showed the two drag cases
red (59 pt shell gap, 47 pt overlap, the dragged edge 65 pt off the pointer) and the
release-then-key case green.
…d starts under the pointer (FRAME OWNER S2B)

FRAME OWNER REFACTOR stage S2B. A divider, column-edge or row-edge drag that starts
while a spring runs (a key resize, a release) showed a shell gap or an overlap between
two panes that share an edge, and the dragged edge jumped off the pointer:
SharedEdgeDuringSpringTests, red at the feat tip (step 8cf32b98462d7aedc9d4cf18 at
c43f92c; with the push and fling cases, step 67c6e5f135ea7fb24cc9e311 at
9680ddd: 4 of 5 cases red, e.g. a|b1 59 pt open and b2|c 47 pt overlapping in the
first drag frame, the dragged edge 65 pt from the pointer).

Causes:
- During a gesture `ScreenContentView.place` snapped the WHOLE frame a drag retargets
  (M3). A column whose right edge the drag moves also had its left edge snapped to where
  the key spring was still taking it, while the pane beside it was still on that spring.
- `DividerDrag.start` measured the grab offset from the rest layout, so a drag that
  started on a springing edge put that edge at its rest place plus the pointer's move.
- A release's fling (`SplitMotion.seed`) set the velocity of whole frames, so an edge the
  release did not move lost the speed of the spring it was on.

Fix (`SharedEdgeMotion`, no change to the spring model):
- During a drag, an edge whose target changed lands on it; every other edge keeps where
  it shows and its velocity. Both neighbours of a shared edge see the same target change,
  so they land together or spring on together.
- The drag measures the pointer from where its edge shows (split, column edge, and so the
  Option push and the Shift landing too).
- A release seeds only the edges its layout moved.

Kill switch, default ON: `motion.frameOwner.sharedEdges` (MotionTunables, Debug Settings
Springs), latched when a drag starts (`DividerDragState.sharedEdges`, also carried to its
release). OFF is exactly the path before this commit. It goes after the films and the
first dogfood gate pass.

Also: `ScreenContentView.dividerLineRects` (a forwarder) is gone; its two callers build
`ScreenDividers` themselves, so the ScreenContentView type does not grow (2052 lines).
S1's TabStripFollowsPaneTickTests builds the release with the new field.

Sidebar-Look: no visual change
…gged edge is read in its column's frame

The split case dragged b1's edge 30 pt left, but b1 is 13 pt above its minimum width: on any rule the divider stops
at the minimum after 13 pt (red run 67c6e5f1: 844, 841, 838, 835, then 834 for the other frames). It now drags right.

A divider pressed while its column still slides on a spring cannot both stay under the pointer and leave the layout
as it is at the press: the column moves under the pointer, so the pane would change by the column's remaining
travel (65 pt here) on a press alone. The drag measures the pointer against the rest layout, so the pointer's travel
changes the dragged pane 1:1 and the edge rides its column's spring. The test now reads the dragged edge from
column B's left edge, which only the key spring moves.

Sidebar-Look: no visual change
…hange, on the spring it rides

The first rule landed every edge whose target the drag changed on that target. In a column that still slides on a
key spring, that put the dragged split edge at its rest place while the column's other edge was 65 pt short of
its own: the pane jumped by the column's remaining travel (fleet step 8c204f56). Measuring the grab from where the
divider shows clamped the split at b1's minimum width instead.

Now each component of a retargeted frame (x, y, width, height) moves by as much as its target and keeps its
velocity, so each edge moves by its own target's change and stays on the spring it rides; both neighbours of a
shared edge see the same change. A component at rest lands on its new target exactly, so a drag with no spring
running places frames as before. The grab offset is measured from the rest layout again, as on feat, so a press
changes no size and the pointer's travel changes the dragged pane 1:1. shownDrift is gone.

Sidebar-Look: no visual change
…width below zero, a new pane at a release keeps its column, motion stops

Three new cases (regrab during a release spring, shrink during growth, a new pane at a release) and stronger checks
in all eight: the press moves nothing, a still pointer holds the dragged edge, the split divider stays at b1's edge,
no frame shows a negative size, a fling's seed is set, the new pane keeps c's speed, shared edges agree within
0.5 pt, and the motion stops on its targets. Red at the tests-only branch scratch/s2b-red4 (feat tip + this file).

Sidebar-Look: no visual change
…kes over where the edge shows

Lead decision (2026-11-04): rule C, the motion rule that an animation is interruptible from its current value. The
shift rule alone kept the dragged pane's own size spring: a divider grabbed again during its release spring kept
sliding under a still pointer, and a pane shrunk while it still grew could show a negative width (Codex review FIX
at 54af943).

At the press (DividerDrag.catchShown, only with motion.frameOwner.sharedEdges latched and the screen moving), the
drag's value (the split's ratio, the column's width) goes to where its edge shows from its anchor (the edge across
the pane or span it resizes), in the drag's own transaction, and the screen lays that out in one pass that moves
nothing on screen: the edges on the dragged line take the anchor's offset and velocity, every other edge the new
value moves keeps where it shows and its velocity. The drag then starts from that layout, so the pointer's travel
changes the pane 1:1 and nothing shows past its minimum. Each move after the press shifts the edges it changes by
their targets' change, on their springs (as before). A release's fling no longer seeds a frame that is new in its
pass: a split's new pane keeps the motion it rides.

Sidebar-Look: no visual change
…lease spring changes nothing, the switch is on

Review (Codex FIX at d221f9d): the press check now compares every pane and divider frame right after the mouse
down, before any frame; a ninth case clicks the divider during its release spring (press and release, no move) and
expects nothing to move and the release's ratio to stay; the suite requires motion.frameOwner.sharedEdges on.

Sidebar-Look: no visual change
…nd stops the dragged line by influence

Review (Codex FIX at d221f9d): the catch found the dragged line's edges by distance (it could take a neighbour on
another spring), missed a catch with no target change (an edge crossing its target), moved the edge on the press
when the value clamped at a minimum, and fell back to the shift rule when it found no anchor.

Now the press's pass keeps every frame where it shows and its velocity and only sets the targets of the caught
value. The change of speed that stops the dragged line against its anchor goes to each edge in proportion to how far
that edge moves when the value moves (a probe layout 8 pt further, either way: SharedEdgeMotion.Influence): the line
stops against its anchor, the panes after it move as one block, inner edges of a split take their share, and the two
edges of a shared edge always get the same change. The anchor is the nearest edge among the panes the layout puts on
the anchor's side (the split's first side, the column's panes). A clamped value moves nothing on the press; that
edge springs to its minimum. The press syncs through the window (scroll, chrome, overlay as any layout change), and a
cancel (a click, Escape) puts back the value the catch replaced, an unconfirmed release's included.

Sidebar-Look: no visual change
…the red run compiles on a base without the switch

Sidebar-Look: no visual change
…ing needs every velocity at rest

Review (Codex FIX at 83bf2ef): CGRect.width is the standardized width, never negative, so the size check read the
springs' own values; landing now checks every component's velocity.

Sidebar-Look: no visual change
…old drag; a cancel sends the replaced release again

Review (Codex FIX at 83bf2ef):
- No anchor frame, a value no probe can move, or a row edge, while the screen moves: the drag turns
  motion.frameOwner.sharedEdges off for itself (whole frames snap, as before S2B), never the shift rule with a size
  spring's leftover. The screen counts as moving when a frame is off its target or has any velocity (a spring can
  cross its target with speed); the press no longer needs hasMotion.
- The influence layouts are laid out off the pixel grid, so the two edges of a shared edge get the same change.
- A cancel (a click, Escape) after a catch sends the unconfirmed release it replaced again, in a new transaction:
  it settles or is refused as any release, never a stale local value put back. A modifier mode that stops setting
  the caught key puts it back at the caught value (the drag's start), not the daemon's.
- A shown extent the layout cannot hold (under a minimum, past the ratio range) is caught at the nearest one it can
  hold and springs there from where it shows (documented policy).

Sidebar-Look: no visual change
…ws shows no negative width

Review (Codex FIX at 87f82ae): a column whose own edges are at rest while an inner split springs (an equalize, a
release) kept b1's spring leftover under the shift rule; shrinking B to its minimum then showed b1 with a negative
width. A tenth case grows b1 by far more than a pane's minimum with an equalize and drags B's edge in to B's
minimum while it grows. Green on feat (whole frames snap there): a guard for the rule.

Sidebar-Look: no visual change
…e past zero takes the drag from before S2B

Review (Codex FIX at 87f82ae):
- The press now also checks a drag whose line is at rest against its anchor: for every pane the drag resizes
  (its size changes between the caught layout and a probe), a pane that shows narrower than its rest size by more
  than a pane's minimum would show a negative size when the drag shrinks it (a move keeps each edge's leftover).
  Such a press turns motion.frameOwner.sharedEdges off for its drag: whole retargeted frames snap to rest, as before
  S2B, which shows no negative size. The check runs before anything changes.
- Compile: DividerDrag+Catch imports CmuxNextDesign (AnimatedFrame); apply's targets is declared once.

Sidebar-Look: no visual change
… a negative size, in every drag mode

Review (Codex FIX at c9236aa): the guard looked only at the panes the plain drag resizes and only at the leftover at
the press. A modifier mode (Command uniform widths, Option trading) resizes other panes, and a size spring's speed
can carry a pane below zero after the press.

Now the press follows every pane's width and height spring (its leftover from the caught rest size and its speed,
with the catch's share of the change of speed) along its whole path on the panes' spring, and takes the drag from
before S2B when any could go further under its rest size than a pane's minimum: any drag mode can shrink a rest size
to that minimum, never under. The check runs before anything changes, also when the line is at rest; a catch whose
probes cannot move the line takes the old drag too.

Sidebar-Look: no visual change
…three moves), so b1 still grows when it is shrunk

The probe without the guard (scratch/s2b-probe-noguard, step a25345332c72fcabdaa150ca) passed the slow version: b1's
spring settled during 18 small moves before its rest width got small.

Sidebar-Look: no visual change
…'s minimum in one move, one frame into the spring

The fast version (three moves) also passed without the guard (probe step 4ed66a09e176d6c7126b003a): b1's spring
settled faster than its rest width shrank.

Sidebar-Look: no visual change
…g from before S2B

Review (Codex FIX at 1355c29): a shown extent under a minimum (a shrinking spring past it) or past the ratio range
was caught at the nearest value the layout can hold, and the line then sprang on to it under a still pointer. The
press now lays the caught value out and takes the old drag when it does not put the line where it shows (1 pt: the
rest layout is on the pixel grid, the check's own is not).

Sidebar-Look: no visual change
…within the shared-edge tolerance

Review (Codex FIX at 87af13f): the 1 pt allowance passed a catch whose value the layout clamps by less than a point
(a shrinking spring's undershoot past a minimum, grabbed at 0.75 pt under it); the line then sprang 0.75 pt under a
still pointer. The press now lays the caught value out as the screen will (its viewport and pixel scale) and compares
the line's rest place there with where the line shows from its anchor: 0.5 pt or more apart, the press takes the drag
from before S2B.

Sidebar-Look: no visual change
@lawrencecchen lawrencecchen added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Nov 4, 2026
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Review (codex): SHIP at 3fbd40a

Independent review by Codex (gpt-6.1-sol), seventh round. The reviewer had no tools: the pack held the full diff from the merge base, the full changed files (SharedEdgeMotion, DividerDrag+Catch, DividerDrag, DividerDragState), and the reconcile geometry code. Rounds 1 to 6 at d221f9d, 83bf2ef, 87f82ae, c9236aa, 1355c29 and 87af13f said FIX; each blocker was fixed in the commits after them. Round 7 answer:

  1. DividerDrag+Catch.swift, abs(moved - caught.lineMove) >= 0.5 — no blocker found. This closes review 6’s demonstrated 0.75 pt clamp hole: acceptance now checks the pixel-rounded installed layout against baseGeometry, which is also the source of the catch calculation. Canvas is excluded. The column-edge sign is already incorporated in lineMove; the comparison should remain in coordinate space without another sign adjustment. Area and row offsets are applied after baseGeometry, so comparing two base geometries avoids mixing those spaces.

    Full verification remains limited by omitted implementations: ScreenGeometry.compute, geometry shifting, hit-frame construction, and spring stepping. In particular, the shown code establishes a residual under 0.5 pt, but alone cannot prove that rendered rounding or spring overshoot never produces 0.5 pt of travel from the initially caught position.

  2. SharedEdgeDuringSpringTests.swift, catch and fallback coverage — should-fix. Add the specific fractional-clamp regression: a shown extent 0.75 pt below minimum must disable shared edges, then remain stable with a still pointer. Current cases do not directly exercise the new rejection threshold. Vertical, dock-edge, and velocity-driven guard cases also remain useful omissions. These are coverage gaps, not demonstrated blockers.

  3. SharedEdgeMotion.swift, introductory “caught at the nearest one it can hold” paragraph — nit. This describes the superseded behavior for material clamps. The implementation now falls back when the installed line differs by at least 0.5 pt; update the comment accordingly.

No additional concrete blocker is demonstrated by the supplied code. The extra layout computation occurs once per catching press; its actual latency cannot be established from these excerpts.

@blacksmith-sh

blacksmith-sh Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

Found 6 test failures on Blacksmith runners:

Failures

Test View Logs
/tmp/tmpoj2o1vj7/summary-missing.json (live):/summary-missing.json (live): View Logs
/tmp/tmpvbtzspze/summary-fail.json (live):/summary-fail.json (live): View Logs
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows/
[new_workspaces] debug.new_workspace timed 0 of 50 new workspace rows
View Logs
[new_workspaces] the window draws no frames/[new_workspaces] the window draws no frames View Logs
[tabs] debug.tab_switch timed 0 of 40 switches/
[tabs] debug.tab_switch timed 0 of 40 switches
View Logs
[tabs] the window draws no frames/[tabs] the window draws no frames View Logs

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

@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

red: cmux-next checks (god files, concurrency, crash safety, l10n); NEW: red check: Base-red classifier (per test) (+1 more) is not red on the base 83c6b99; do not merge until green; see lane-rules

Default changes

This pull request changes 3 defaults at 6aad7d8406b2 (what everyone gets without configuring anything):

  • tunable-source.CmuxNextDesignTokens/Motion/MotionTunables.swift:all: "b9ea0ec6c2ccaee815194404730141c795aecbf18e304cb76d17b3909b8fe873" -> "9b26b4e2b2220e51de94275a1100461cecf18ff3926e74ffddca281e426e8c0d"
  • tunable-source.CmuxNextDesignTokens/Motion/MotionTunables.swift:frameOwnerSharedEdges: (none) -> "877405565523a4df1eb194f24510cc20c894201c9d279191974c3439f5555771"
  • tunable.motion.frameOwner.sharedEdges: (none) -> true

Signed off on this commit by review (codex), carried from 3fbd40a34c1e across base merges.

Merge receipt: merged as 0b006a521245 with these defaults changed, signed off by review (codex), carried from 3fbd40a34c1e across base merges.

Regenerate the snapshot with python3 scripts/ci/defaults_guard.py snapshot.

Shipped in:

@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Red-check triage for head 3fbd40a: cmux-next checks is red on two base findings in files this PR does not touch:

  • No fleet host names in gallery fixtures: webviews/src/agent-session/acpmux/subagents/SubagentTray.gallery.ts:157 (on the feat tip, not at this branch's merge base 23cc8e5).
  • Base-red classifier (per test): .github/workflows/ci-guards.yml job portable-placement vs scripts/ci/base_red_excuse.py.

Both are fixed by open #34979 ("ci(cmux-next checks): clear base reds (fixture host name, rollup placement job)"). They do not hold this PR.

@lawrencecchen
lawrencecchen marked this pull request as ready for review November 4, 2026 08:06
@lawrencecchen lawrencecchen added the ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds label Nov 4, 2026
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 4, 2026 08:25 Inactive
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 4, 2026 08:25 Inactive
@cmux-bot
cmux-bot Bot temporarily deployed to ci-routing-agent November 4, 2026 08:29 Inactive
@lawrencecchen
lawrencecchen merged commit 0b006a5 into feat-cmux-next Nov 4, 2026
148 of 152 checks passed
@lawrencecchen
lawrencecchen deleted the fix/frame-owner-s2b-shared-edge branch November 4, 2026 08:32
@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Swift logic follow-up (tip watcher swift-logic row, STATUS 13027 "SWIFT LOGIC CULPRITS"; lead order).

This PR raised swift_logic_lines by +423 at its merge commit 0b006a5: scripts/cmux-next/swift-logic-lines.py before and after the merge, with the same table (the tip's, c6be943). The largest declarations of the rise:

  • extension SharedEdgeMotion in Packages/macOS/CmuxNext/Sources/CmuxNextLayout/Views/SharedEdgeMotion.swift: +165 lines counted as Swift logic (no row in plans/cmux-next/swift-logic-classes.tsv)
  • extension DividerDrag in Packages/macOS/CmuxNext/Sources/CmuxNextLayout/Views/DividerDrag+Catch.swift: +100 lines counted as Swift logic (no row in plans/cmux-next/swift-logic-classes.tsv)
  • enum SharedEdgeMotion in Packages/macOS/CmuxNext/Sources/CmuxNextLayout/Views/SharedEdgeMotion.swift: +85 lines counted as Swift logic (no row in plans/cmux-next/swift-logic-classes.tsv)
  • extension SharedEdgeMotion in Packages/macOS/CmuxNext/Sources/CmuxNextLayout/Views/SharedEdgeMotion.swift: +36 lines counted as Swift logic (no row in plans/cmux-next/swift-logic-classes.tsv)

plans/cmux-next/layer-ownership.md says Rust owns every state, list and rule and Swift is the platform shell. Please move the new logic of this PR in a follow-up: to Rust (the crate that owns the area; the owner lists in STATUS 12147-12165 name the target per area), or at least out of the app into its package. If a declaration above is platform code (AppKit, Core Animation, OS calls, strings, tokens, DEBUG tooling), reply here and the table gets a PLATFORM row with your reason instead.

The swift-logic row is a report, not a gate: nothing blocks on this comment.

lawrencecchen added a commit that referenced this pull request Nov 5, 2026
…size

Conflicts:
- CmuxNextApp/LaunchWarmup.swift: feat moved the display UUID prewarm into LaunchSystemWarmup.displays() (CmuxNextDesign) and added appleMenuDevice(); feat's side, and its doc comment names NSScreen.stableDisplayID (the S7 branch moved WindowPlacementFallback.displayID there).
- CmuxNextDesign/Diagnostics/LayoutPassGuard.swift: both additions (S7's windowLayoutsBegun, feat's per-window pass counts for debug.frames).
MotionTunables.swift: feat added and then deleted motion.frameOwner.sharedEdges (#35036, #35908): no net change there.

This branch was previously deployed

1 inactive deployment
ci-routing-agent — 6aad7d84 Deployed Nov 4, 2026 by cmux-bot[bot] via wait for same-key tree publisher #110666
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-land Reviewed at this head; next-autoland merges it into feat-cmux-next when its only reds are base reds risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant