Repository navigation
carry of #24287: cmux NEXT sidebar lineage nesting - #28103
teamleaderleo wants to merge 25 commits into
Conversation
Agent-started workspaces nest under the workspace whose agent started them, at any depth, with only person-started sessions at the top level. A parent below depth 1 starts folded behind a count chip and its state roll-up; the user's open/fold persists per parent. Debug Settings sidebar.lineageNesting (on by default) turns nesting off. sidebar.sessionTree keeps its keycaps, chat history and pull request reads. The Done fold and row limit move whole subtrees with their top-level row. Leo-ask: ask-18a79e54a3 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16162-3eb9-7ce3-a6c8-07fec063b18a&host=cosmic-gray Sidebar-Look: no visual change
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16162-3eb9-7ce3-a6c8-07fec063b18a&host=cosmic-gray Sidebar-Look: no visual change
….sessionTree on Review findings at d41b76f: SidebarTreeRollUp.isEmpty counts total; the deep tree roll-up expectation includes total; the keycap row test enables sidebar.sessionTree, and a new test pins that nesting alone draws no keycaps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16162-3eb9-7ce3-a6c8-07fec063b18a&host=cosmic-gray Sidebar-Look: no visual change
Review finding at a18f826: hidesInFold and reveal walked the global parents map, so a row whose parent sits in another list (drawn as a root there) read as hidden and its selection opened folds in the other list; a cycle did too. Both now walk only the ancestors the layout nests it under (same list, no cycle), through SidebarModel.sharesList. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16162-3eb9-7ce3-a6c8-07fec063b18a&host=cosmic-gray Sidebar-Look: no visual change
Review finding at 2b7e5de: a pairwise same-list test let a chain hop lists through a workspace listed twice. hidesInFold and reveal now take one membership test per list holding the row (SidebarModel.listsHolding, O(1) through the row index) and walk each list on its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16162-3eb9-7ce3-a6c8-07fec063b18a&host=cosmic-gray Sidebar-Look: no visual change
Review finding at d4c5c0e: the tree feed starts after restored windows, so the first render's reveal ran with no lineage and a later tree change did not retry it; a depth-2 selection stayed in its parent's fold. A change of parents now re-reveals the selection (a fold the person makes keeps). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16162-3eb9-7ce3-a6c8-07fec063b18a&host=cosmic-gray Sidebar-Look: no visual change
Sidebar-Look: no visual change
Keep the roll-up total meaning explicit in French and avoid new identical-English localization debt. The existing validate_localization check rejects the old value and accepts the new value. Sidebar-Look: no visual change
Track selected rows drawn ancestor paths after applying grouping preferences. Moving a selected session under a deep parent opens its new folds, while manual folds and unrelated structural changes keep their state. Add a regression covering the move, explicit fold, and unrelated row insertion. Sidebar-Look: no visual change
Preserve the original sidebar lineage nesting behavior while integrating current-base host-scoped session parents and layout gap handling. Agent-Session: https://cmux.com/deeplink/agent?id=aid-7c72d5ff80192ea8137c
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on 4165f6f to compare; do not merge until green; see lane-rules Default changesThis pull request changes 2 defaults at
Signed off on this commit by Regenerate the snapshot with |
This comment has been minimized.
This comment has been minimized.
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
Review (codex gpt-6-astra high, next-review): BLOCK at 96f7c85
|
|
Owned by an agent session · took over from an earlier session · session |
With lineage nesting on, `dragUnfolds` returns false whenever the session tree is set, but the Done fold now runs with the tree (it moves whole runs). A drag of a Done root or a Done nested row keeps the folds, so the dragged row leaves its slot and the drop gap opens where the row will not show (Astra review BLOCK on #28103). Fails on 96f7c85: the first two expectations. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-63b9964940c20354b639
…he tree The Done fold runs with lineage nesting and moves whole runs, but `dragUnfolds` returned false whenever the session tree was set, so a drag of a Done row kept the folds: the dragged row left its slot and the drop gap opened where the row would not show (Astra review BLOCK on #28103). `dragUnfolds` now drops the tree guard and, with the tree, also unfolds a drag that carries a row under a Done ancestor (that root's run folds with it; with the dragged row gone from the base rows a run that held the active row folds too) or the parent of a Done row (the base rows lack the parent, so the Done row would draw top-level and fold). The list passes the model's workspace lookup. The walk follows `parents` across lists, so it can unfold a drag the fold would not move; that drag draws as before drags kept the folds, never with a moved row. The owner note logs f0803b4, which reached the branch without a trailer. Test: SidebarLineageNestingTests.aDragOfADoneRowUnfoldsWithTheTree (red at the previous commit; not run here: this Linux lane VM has no Swift toolchain, so the fleet runs it). Sidebar-Look: no visual change Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-63b9964940c20354b639
`SidebarNestedFixture.lineageGroup` (DEBUG): a person's own row, then a group whose members an agent started from Release week: Settings pass, itself a parent and so folded behind its count, and Release notes. `scripts/cmux-next/media/states/sidebar-lineage-group.json` shows it with `sidebar.lineageNesting` off (flat, the base's drawing) and then on, in one build, so the before and after use the same rows. `tour.py --check` passes; the capture runs on the fleet. Sidebar-Look: no visual change Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-63b9964940c20354b639
|
Awareness note from an agent lane that does not own this PR; it is not a review or a request to take the PR over. This PR is the build for Leo's ask ask-0dbbb0b936 (2026-10-21): he saw sub-sessions nested under their parent in the acpmux dashboard and asked why his actual cmux NEXT nightly sidebar doesn't do that. The ask is 12 days past its 1 h SLA. Current state: CONFLICTING with feat-cmux-next, no review at head cc6384a after the 0614c4a BLOCK (manual folds reopened by unrelated lineage updates), last commit 2026-10-30 22:51Z. Owner: please merge base, address the BLOCK, get a review at the new head and land it, or release it ( |
Conflicts kept base's newer sidebar work beside lineage nesting: - SidebarSessionTreeFeed: the pull request capture fixture (no GitHub reads) and the nesting-only pass. - SidebarLayout+DoneFold: the Archived (N) fold and Archive-section drag unfold, folding whole runs. - SidebarLayout+Fold: archived-group fast-path exits plus the lineage one. - SidebarRowIndex: a folded session's step lays nothing out (#31783), with the per-list fold check. - SidebarTreeRollUpView: the running spinner ring (#31455) beside the total chip. - SidebarNestedFixture: soleMember and lineageGroup scenarios. - SidebarListView+Layout: a drag unfolds Done, Archived and the Archive section, lineage-aware. The Archive section no longer turns off with the session tree, which nesting now sets for everyone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-63b9964940c20354b639
|
Review (codex gpt-6-astra high, router-review): BLOCK at 9f6d9cd BLOCK at 9f6d9cd Visual verdict: supplied before/after pairs show the intended nesting; no fresh head capture [follow-up].
Follow-ups:
|
…eage nesting (red) Router review BLOCK on #28103 at 9f6d9cd: with the session tree the drawn order is the tree's preorder, but the drop gap opened at the raw model index, so a tab dropped before a nested row landed after the next root. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-63b9964940c20354b639
…ry the row lands at `gapEntry` placed the gap by drawn order only for lists with a fold. A list that nests (the session tree) draws its rows in tree preorder, so the gap opened at the raw model index, inside an earlier root's run, while the dropped row (a root) draws after that run. It now also handles nesting lists: the gap opens before the first drawn top-level row at or past the gap's index, else before the first fold row, else after the list's last entry (`gapAtEnd`), and the per-row raw gap is skipped for such lists. Test: SidebarLineageNestingTests.aDropGapOpensWhereTheDroppedRowWillDraw (red at the previous commit). Sidebar-Look: no visual change Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-63b9964940c20354b639
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
Review (codex gpt-6.1-sol xhigh, router-review): BLOCK at 4a49300 BLOCK at 4a49300 Visual verdict: no images; Leo tries the build
|
…neage nesting Lineage nesting (on by default) publishes the session tree for everyone, and the tray drew whenever a tree was set, so blocked, failed or unread sessions added the tray and its bottom inset with `sidebar.sessionTree` off (router review BLOCK on #28103 at 4a49300). `SidebarNeedsYou.trayTree` passes the tree to the tray only while the session-tree preference is on. Test: SidebarNeedsYouTests.nestingAloneDrawsNoTray. Sidebar-Look: no visual change Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-63b9964940c20354b639
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
This comment has been minimized.
This comment has been minimized.
|
Review (codex, router-review): SHIP at 5d04973 Reviewer: codex gpt-6-astra high, fast tier. SHIP at 5d04973 Visual verdict: stale pre-head after images show the expected nesting; no fresh head capture, Leo tries the build. Reviewed the changed lineage, fold, drag-gap, tray, feed, and selection-reveal paths plus targeted tests. No correctness findings. Follow-ups: none |
…24287-sidebar # Conflicts: # Packages/macOS/CmuxNext/Sources/CmuxNextSidebar/Views/SidebarListView+Layout.swift
…24287-sidebar # Conflicts: # Packages/macOS/CmuxNext/Sources/CmuxNextSidebar/Model/SidebarModel.swift
|
Found 43 test failures on Blacksmith runners: Failures
...and 33 more test failures. View all on Blacksmith
|
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
HOLD: structural sidebar change: waits for a dogfood build for Leo to try
Leo-ask: ask-0dbbb0b936
Carry of #24287 (#24287).
Original purpose: “cmux NEXT sidebar: agent-started sessions nest under their parent by default.”
This carry keeps the original commits and authorship, integrates the current
feat-cmux-next, and resolves the current sidebar feed/layout conflicts against the base's host-scoped session-parent and gap-handling changes. It preserves the default lineage-nesting setting, avoids GitHub reads when only lineage nesting is enabled, and retains tree fold/roll-up metadata for grouped rows.Validation: merge completed cleanly;
git diff --checkon the carry delta has no new whitespace errors. Native validation belongs on the fleet.Leo 2026-10-21 (ask-18a79e54a3, recorded in
design/sidebar.mdas default-on): "A LOT OF THESE SESSIONS ID IMAGINE DIDNT NECESSSARILY NEED TO SHOW UP ON THE SIDE BY DEFAULT". Lineage nesting stays on by default.Drag fix (Astra review BLOCK):
SidebarLayout.dragUnfoldsreturned false whenever the session tree was set, but the Done fold now runs with the tree and moves whole runs, so a drag of a Done row kept the folds and the drop gap opened where the row would not show. It now understands the tree: a drag unfolds when it carries a Done row, a row under a Done ancestor, or the parent of a Done row (the drag's base rows lack that parent, so the Done row would draw top-level and fold). The walk followsparentsacross lists, so it may unfold a drag the fold would not move; that drag draws as it did before drags kept the folds. Regression:SidebarLineageNestingTests.aDragOfADoneRowUnfoldsWithTheTree, committed red first ("test(sidebar): a drag of a Done row unfolds with lineage nesting (red)"), then the fix.plans/cmux-next/sidebar-owner.mdgets the lineage entry and logs f0803b4, which had noSidebar-Look:trailer.Defaults: this PR intentionally changes
tunable.sidebar.lineageNestingfrom none totrue.design/sidebar.mdrecords it as default-on from Leo's ask-18a79e54a3: "A LOT OF THESE SESSIONS ID IMAGINE DIDNT NECESSSARILY NEED TO SHOW UP ON THE SIDE BY DEFAULT". The defaults guard's change list matches this.Reveal fix (router review BLOCK at 0614c4a):
revealsSelectionforced a reveal whenever the wholeparentsmap changed, so an agent started or closed anywhere reopened a fold the person made above the selected row. Now only three things reopen folds above the selection: a new selection, lineage arriving for the first time (no parents before, some now), or a change in the selected row's own drawn ancestor chain (SidebarSelectionTreeReveal: a reparent, or a move to another list). Tests:SidebarLineageNestingTests.anUnrelatedSpawnOrCloseKeepsAFoldAboveTheSelection(committed red first),reparentingTheSelectionUnderAFoldRevealsIt,theFirstLineageRevealsTheSelection.Performance:
SidebarHugeGroupTests.oneGroup10kopened slower at 0614c4a than on base (862 ms vs 693 ms). That group has no lineage. The nesting path in it buildstreeRowsand a member lookup per layout, and a reveal pass after each structural change, which calledlistsHoldingand rebuilt the model's row index (O(rows)). Two cheap trims are in: the reveal skips its walk while there is no lineage, and the group's tree lookup holds only parents (rows with a chevron), not all 10k members.treeRowsstays O(members) per layout. Neither trim is measured yet; recheck this bench at the head after #28556 lands.Merge of feat-cmux-next (9f6d9cd)
Merged
origin/feat-cmux-next(17b7593) as a merge commit. Seven files conflicted; each keeps base's newer sidebar work beside lineage nesting:SidebarSessionTreeFeed: base's pull request capture fixture (sample badges, no GitHub reads) plus the nesting-only pass (shaped, no GitHub reads when only nesting is on).SidebarLayout+DoneFold: base's "Archived (N)" fold and Archive-section drag unfold, now folding whole runs as the Done fold does;dragUnfoldskeeps its lineage walk and folds archived rows too.SidebarLayout+Fold: base's archived-group fast-path exits plus the lineage one.SidebarRowIndex/SidebarSessionTree: base's perf(sidebar): a folded session's step lays nothing out, only its roll-up state does #31783 (a folded session's step or title lays nothing out) with this PR's per-list fold check (patchChangesRollUp(..., lists:)).SidebarTreeRollUpView: base's running spinner ring (cmux NEXT: the working spinner is a faint ring with a turning sweep, not the 3/4 arc or spokes #31455) beside this PR's total-count chip.SidebarNestedFixture: bothsoleMemberandlineageGroupscenarios.SidebarListView+Layout: a drag unfolds Done, Archived and the Archive section, lineage-aware.One behavior call: base turned the Archive section off whenever the session tree was set. With nesting on by default the tree is set for everyone, so that would have removed the Archive section for every user. It now draws with the tree; a row whose parent moved to the archive draws as a root of its list. Test:
SidebarArchiveSectionTests.theSessionTreeKeepsTheArchiveRow.Fleet at 9f6d9cd:
cmux-ci compile-check --package CmuxNextpassed (job ff5be5652660ddb5941bf5ef). Swift suites on a fleet Mac (step 0eabab2bd3b8fc10e8beffb6), all passed: SidebarLineageNestingTests, SidebarSessionTreeTests, SidebarArchiveSectionTests, SidebarArchivedFoldTests, SidebarDeepTreeTests, SidebarDoneFoldTests, SidebarDragKeepsDoneFoldTests, SidebarLayoutFoldTests, SidebarFoldKeyboardTests, SidebarFoldAccessibilityTests.Drop-gap fix (router review BLOCK at 9f6d9cd)
With the session tree a list draws its rows in tree preorder, but the drop gap for a tab dropped from a pane opened at the raw model index. Model
[parent, other, child]draws[parent, child, other]. A drop beforechildopened its gap there, but the new row is a root, so it landed afterother.SidebarLayout.gapEntrynow covers nesting lists as well as folded ones. The gap opens before the first drawn top-level row at or past the gap's index; failing that, before the first fold row; failing that, after the list's last entry (gapAtEnd). This works for loose rows and group members. Test:SidebarLineageNestingTests.aDropGapOpensWhereTheDroppedRowWillDrawchecks that the gap's y equals the dropped row's y after the drop, for every index, loose and grouped. It failed at 46d224f (red commit, fleet step bc265bac1251980375083cda: 52 pt apart) and passes at 4a49300.Fleet at 4a49300:
compile-check --package CmuxNextpassed (job 6cb56d6194019113441d448f). Swift suites (step 062a61e564cf192a227610d0) all passed: the ten above plus SidebarUniformRowSpacingTests and SidebarSingleMemberGroupTests.Needs-you tray fix (router review BLOCK at 4a49300)
Lineage nesting sets the session tree for everyone, and the needs-you tray drew whenever a tree was set. So with
sidebar.sessionTreeoff, blocked, failed or unread sessions added the tray and its bottom inset.SidebarNeedsYou.trayTreenow passes the tree to the tray only whilesidebar.sessionTreeis on. Test:SidebarNeedsYouTests.nestingAloneDrawsNoTray.Fleet at 5d04973:
compile-check --package CmuxNextpassed (job 00a879738ce5979d57d6e788). Swift suites (step 13a7bdee9db6412b9a77b8da) all passed: the twelve above plus SidebarNeedsYouTests.Observed / Not run
prepush-gate.py --only sidebarover the PR's commits reports 0 findings (it named f0803b4 before); the full pre-push gate reports no new violations.Captures
Viewed after image:
lineage-after-17c0923e-light.pngbelow. Release week shows its two agent-started children, Settings pass and Release notes, one level in; each folds its own child behind a1count chip with the state roll-up. The before (4c12180f, nesting off) lists the same rows flat. These are real fleet captures from the carried PR #24287, at 17c0923 (a commit in this branch), of theneedsYoufixture's loose rows, withsidebar.sessionTree=false. They are not stills of this head. This lane VM can't runcmux-ci capture.Fresh stills of lineage nesting in a group are pending a fleet capture. The new state shows a group with a parent and two children, one folded, first with
sidebar.lineageNestingoff and then on, in one build:cmux-ci capture <head sha> --state scripts/cmux-next/media/states/sidebar-lineage-group.json --pr 28103The sidebar is native AppKit, so the webview gallery doesn't cover it.
Performance
SidebarHugeGroupTests.oneGroup10k, head cc6384a vs base 7050ae30, fleet runs (head and base could not share a host:--target-workerpins fall back after about 10 minutes queued).The head is no slower. The earlier 27-35% gap was the host, not this change. The four ceilings (open<540, unfold<175, fold<80, reorder<290 ms) fail on both head and base on every host, so they are a base red. The four group tests (groupHeaderPlusMakesTheNewWorkspaceInThatGroup, pinGroupFromTheHeaderMenuPinsAndUnpins, groupMovesAtTheEdgeSayWhy, newWorkspaceInGroupIsAwaitedByTheCLI) and the GroupHeaderNewWorkspace, WorkspaceGroupPinLive and Sidebar/WorkspaceNothingToDoRefusal suites pass at head and base. The base results come from one run on a Mac mini. The earlier full-suite reds were load flakes.
Agent session: agent session
Agent session: agent session