Skip to content

cmux NEXT: resolve rapid bottom placements from current rows - #26153

Merged
teamleaderleo merged 13 commits into
feat-cmux-nextfrom
lane/nx-sidebar-rapid-bottom-placement
Oct 30, 2026
Merged

teamleaderleo merged 13 commits into
feat-cmux-nextfrom
lane/nx-sidebar-rapid-bottom-placement

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

HOLD: defaults-guard receipt reconciliation remains outstanding. The shared Swift and sidebar dogfood holds are lifted.

Rapid bottom placements can persist in the wrong order when rendered sidebar rows lag the store. Pending placements retain registration order and refresh the normal rows projection once per window. Personal placement plans share one queue across windows: optimistic rows update immediately; each plan uses the store after the preceding placement and any empty-group deletion have applied on the same connection. Failed writes stop dependent queued placements and release command-scope tickets. A placement skipped because its window or workspace is gone settles its pending edit and allows subsequent placements to continue.

Addresses the stale-rendered-row reproduction in #26152. The broader ordering race remains under separate investigation; this PR does not claim to resolve it. The reported example is: “The stale rendered list resolves index 1, producing [k1,k3,k2]; expected [k1,k2,k3].” The empty-rendered-list guard is preserved. Tab drops capture both neighboring row/item identities before their asynchronous create, so a refresh cannot reinterpret a saved numeric gap.

Risk: this changes cross-window personal placement sequencing and group cleanup timing. Captured source group IDs are rechecked after the move; pinned groups and groups with another live member remain. No new timer or observer is introduced. Each queued operation releases its scope ticket on success or failure, and the final completed operation clears the queue tail.

Validation

Current head: 051c630fd560b2961c19fcd893485b68a10c49f2. The last merged base is 8e36e526f9c592b30333ff8d0d1dd506fb6f45e8 (merge commit 9166d799d735b59fda5245dbb6bf899440467a14).

  • Exact-head independent correctness review: SHIP after reviewing the skipped-placement repair and full diff. Earlier reviews at 18ae60bc are historical evidence only.
  • Focused managed native step 2ac597eefc4c1b25f0235566 compiled and passed all five suites: PlacementStaleRowsTests, PlacementWriteOrderTests, WorkspaceGapTests, ModelMatrixPersonalOrderTests, and NewWorkspaceInGroupTests, including skipped versus failed queue outcomes. Script exit code was 0; the controller job remains failed because the requested output artifact path did not exist. Test-summary SHA-256: dbf5a61bdc42858477ab71e1b42726113a9882d70c683cec5b92c2ed02a6f34f. This is passing behavioral evidence, not a green controller-job claim.
  • The pre-fix assertion run 8d3046df5118aca153aba2ef at test-only cf168eaf2dba5c5682e11a89c1cac6d12d8654cc compiled, then failed persisted-order/write-order assertions. It remains the reproduction; its GUI-gated no-result is excluded.
  • Exact-head app build 811fd5597cf9626d40bb1fd1 completed; artifact SHA-256 d2a25029d16dc8dfb7bba3416503b6ec5777c71de9b41882bac9530d7c16be6c. A successful build alone is not a structural dogfood interaction result.
  • Hosted defaults guard remains red after one supported failed-job rerun: run 40785685307, attempt 3, job 123715584296. It still reports a missing exact-head review. The existing member SHIP above is accepted by both receipt_verdict and complete approval replayed from the trusted base guard against the live review payload. Gate-owner reconciliation is outstanding; no exemption or green hosted result is claimed.

Screenshots

After at the exact head: real native AppKit gallery fixtures exercise production placement with a scripted daemon and stale rendered rows. Managed native suite 2c3bc831ab5d49d3e1a02a0d compiled and passed its one gallery test with no skips. All four captured states paint first/second/third, and the recorded daemon write uses index 2. The PNGs are unedited 300 × 320 transparent fixture captures; light ink has low contrast in viewers that render transparency as black. These are native sidebar fixture screenshots, not whole-app dogfood captures. Tesseract OCR through the shared privacy checker, with the private terms list, passed all four files; its canary was correctly refused.

Mode / theme Before (test-only baseline cf168eaf) After (exact head 051c630f)
plain / dark Before After
plain / light Before After
mixed / dark Before After
mixed / light Before After

Before is the existing native fixture run 64698b493dbe2916a500c4d1 at test-only cf168eaf2dba5c5682e11a89c1cac6d12d8654cc, showing first/third/second with write index 1. Those four published images were re-read with the same privacy/OCR check. Current after artifact SHA-256: d0a6fc1ff7feb82afb18cb72b355a117ecbeeb52da2f0b435d838c49961c9c94. Historical 18ae60bc after images are superseded by the exact-head captures above.

Performance

The following Classic rows are observed assertion issue counts, not failing-pass counts or causal performance improvements. Both jobs ran scripts/ci/package-test-lane.sh suite Packages/macOS/CmuxNext Classic for ten consecutive iterations (24 suites / 107 tests, default Swift Testing parallelism, class light, CPU 6). There was no deliberate load generator; concurrent work is unknown. Base c8f95c77c316d7112c56c59712e36074edd7c7b8 used a cold worker and locally built daemon tree 68640f91; head 051c630 used a different warm worker and published daemon tree 181771c0. Both jobs failed. These observations are not a controlled A/B experiment and do not establish that this PR fixes terminal parking or the remaining ordering race. A paired run with matched worker, filters and concurrency is pending separately.

Metric Before After Delta Harness or run link
backgroundWorkspacesStartTheirTerminalsWhenFirstShown :266, “not parked” issues 13 1 -12 issues Classic ×10; base 73b29c197a211e4357bba2f4 / head c2f69b2d0bc5e369cb9e202b
backgroundWorkspacesStartTheirTerminalsWhenFirstShown :281 issues 10 0 -10 issues same Classic jobs
Above two assertions combined 23 1 -22 issues same Classic jobs; uncontrolled observation
huge :70, ordering issues 127 120 -7 issues same Classic jobs; ordering remains
FirstLaunch :56 issues 35 30 -5 issues same Classic jobs; ordering remains
FirstLaunch :49 issues 31 19 -12 issues same Classic jobs; ordering remains
onlyPreviousCopy :133 issues 2 0 -2 issues same Classic jobs; too few observations for a conclusion

Separate timing receipts used scripts/measure/instant-new-surfaces.sh --runs=12, class exclusive: base e275db3f6916daa1bf86e1e2b45d8927b9194f11, job 6d54e43cc5e8a83312a72af9, and exact head 051c630, job 29709636a3a301b0e19c25cf, both completed with exit 0. They ran on different hardware (14 versus 10 logical CPUs), and source/daemon trees differ. These are adjacent interaction timings from the same harness, not a controlled placement-latency comparison; positive and negative deltas must not be attributed to this fix. Head timing artifact SHA-256: 293eb1f3637186f4e3168bc1fdaabfa1001c5b268709d40f828213b65d477143.

Metric (p50 milliseconds) Before (e275) After (051c) Delta Harness or run link
idle/split_right / visible_p50 21.860 24.707 +2.847 instant-new-surfaces, 12 runs
idle/split_right / confirmed_p50 64.612 68.108 +3.496 instant-new-surfaces, 12 runs
idle/split_down / visible_p50 23.525 26.860 +3.335 instant-new-surfaces, 12 runs
idle/split_down / confirmed_p50 48.427 65.300 +16.873 instant-new-surfaces, 12 runs
idle/new_tab / visible_p50 13.175 15.045 +1.870 instant-new-surfaces, 12 runs
idle/new_tab / confirmed_p50 43.914 40.418 -3.496 instant-new-surfaces, 12 runs
idle/new_terminal / visible_p50 22.517 25.656 +3.139 instant-new-surfaces, 12 runs
idle/new_terminal / confirmed_p50 60.124 66.995 +6.871 instant-new-surfaces, 12 runs
idle/new_workspace / visible_p50 65.090 55.450 -9.641 instant-new-surfaces, 12 runs
idle/new_workspace / confirmed_p50 141.014 126.930 -14.084 instant-new-surfaces, 12 runs
load/split_right / visible_p50 25.942 34.888 +8.946 instant-new-surfaces, 12 runs
load/split_right / confirmed_p50 160.891 146.407 -14.484 instant-new-surfaces, 12 runs
load/split_down / visible_p50 33.417 28.434 -4.983 instant-new-surfaces, 12 runs
load/split_down / confirmed_p50 158.339 147.251 -11.087 instant-new-surfaces, 12 runs
load/new_tab / visible_p50 35.600 38.381 +2.781 instant-new-surfaces, 12 runs
load/new_tab / confirmed_p50 115.871 145.138 +29.267 instant-new-surfaces, 12 runs
load/new_terminal / visible_p50 29.457 33.770 +4.313 instant-new-surfaces, 12 runs
load/new_terminal / confirmed_p50 149.054 160.544 +11.490 instant-new-surfaces, 12 runs
load/new_workspace / visible_p50 110.987 118.168 +7.181 instant-new-surfaces, 12 runs
load/new_workspace / confirmed_p50 390.492 436.515 +46.023 instant-new-surfaces, 12 runs

Duplicate #26947 is closed as superseded by this canonical PR.

Agent session: agent session

teamleaderleo and others added 2 commits October 27, 2026 10:53
…sidebar rows

No fix: the test fails on today's code. For the sidebar placement owner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-cc8bff1c3ddb4ec353c5
@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

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

Review 051c630: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr26153 -f ref=lane/nx-sidebar-rapid-bottom-placement -f platform=macos -f backend_mode=local

web and size checks: green

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Bead cx-nuc3ac created for this PR by the cmux coordinator.

@blacksmith-sh

blacksmith-sh Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Found 7 test failures on Blacksmith runners:

Failures

Test View Logs
/tmp/tmp9wqu29tq/summary-missing.json (live):/summary-missing.json (live): View Logs
/tmp/tmpe3hteqqh/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
test_every_routed_input_triggers_the_workflow (main.PullRequestTiers.test_every_rou
ted_input_triggers_the_workflow) (path='.claude/settings.json')
View Logs

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

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by an agent session · took over from an earlier session · session

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Hosted red comparison for the exact head 23d8e9a7753a9dfed7ce6ae23a3ae38c0aae2ba3: cmux-next checks is an aggregate red whose routed guard failures are base debt. The same nightly-guards / Guard status and nightly-guards / workflow-guard-tests / release-notary failures are present on base e7cbb89faba911430fa3ee8e76a5a19f3e9a7821; the base also has tooling/iOS guard reds outside this PR. The PR's own native proof is green: PlacementStaleRowsTests, ModelMatrixPersonalOrderTests, and ClassicUpgradeSimulationTests passed in step 5a76e8f254d0b1c27cdc60b0 on aws-m4pro-3; app compile passed in job 1907f773e1026208a1780bdd (48 s). A real before/after capture is still pending the fleet capture route.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra xhigh, next-review): BLOCK at 23d8e9a

  • Packages/macOS/CmuxNext/Sources/CmuxNextApp/Windows/WindowManager+Placement.swift:51 — Refreshing rows before every pending placement breaks tab drops onto sidebar gaps. Such drops store a resolved numeric WorkspaceSlot.at index. If another workspace is inserted before the daemon confirms the new workspace, that same index is applied to a different row set (e.g. a gap after k1 becomes before k1), so the new workspace lands beside the wrong neighbor. Preserve the resolved gap/anchor instead of rebasing .at against refreshed rows.

@cursor

cursor Bot commented Oct 27, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot 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.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next / cmux-next checks (god files, concurrency, crash safety, l10n) › No literal state roots (per-build isolation S7, cx-is1kf.8) is red on 13 of 21 fresh feat-cmux-next PR heads in the last 2:00:00, so it is most likely a base red, not this PR's. The base-reds lane has it; a base merge picks up the fix once it lands.

@cursor

cursor Bot commented Oct 27, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot 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.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Orphaned: no activity for 15 h, and no lane holds a lease on it. Adopted by the orphan sweep: merged feat-cmux-next in at cfa73ae. A later pass queues it for the merge hub if it is reviewed, small and red only on base reds.

@teamleaderleo
teamleaderleo marked this pull request as draft October 30, 2026 01:11
@teamleaderleo
teamleaderleo marked this pull request as ready for review October 30, 2026 01:11
@teamleaderleo
teamleaderleo marked this pull request as draft October 30, 2026 01:16
@teamleaderleo
teamleaderleo marked this pull request as ready for review October 30, 2026 01:16
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

The defaults guard now passes at 051c630fd560b2961c19fcd893485b68a10c49f2 (run 40984819686) on the existing exact-head member SHIP (comment 6483350726). Nothing on this PR changed: no push, no new receipt.

It took two gate fixes:

(The guard's sticky comment above didn't refresh on this run because of an installation rate limit; the check result is what counts.)

@teamleaderleo
teamleaderleo merged commit 373ec0c into feat-cmux-next Oct 30, 2026
283 of 306 checks passed
@teamleaderleo
teamleaderleo deleted the lane/nx-sidebar-rapid-bottom-placement branch October 30, 2026 01:27
@github-actions

Copy link
Copy Markdown
Contributor

The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40986973295 at daa9794 failed: cmux-next checks (god files, concurrency, crash safety, l10n).
Those jobs last passed at cec0a36. This pull request is one of 3 merged since: #26153, #26825, #27541.
If the failure is in your change, fix forward on feat-cmux-next. Pull requests run only the tiers their paths reach (docs/ci/cmux-next-tiers.md); label a batch PR full-ci to run them all before merging.

austinywang added a commit that referenced this pull request Oct 30, 2026
Resolve the personal placement queue (#26153) against the optimistic saves:
PersonalGroupLife.commit keeps one request on the reply's connection with its
`completed` callback, through `perform` so `failed` gets why; the queued
placement settles through the queue and reports a failed save or a lost
connection with the reorder's notice; the other callers keep the base's
captured `ending` recheck and the PR's reported failure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

The feat-cmux-next push run https://github.com/manaflow-ai/cmux/actions/runs/40985942029 at 373ec0c failed: cmux-next checks (god files, concurrency, crash safety, l10n).
Those jobs last passed at cec0a36. This pull request is one of 1 merged since: #26153.
If the failure is in your change, fix forward on feat-cmux-next. Pull requests run only the tiers their paths reach (docs/ci/cmux-next-tiers.md); label a batch PR full-ci to run them all before merging.

lawrencecchen added a commit that referenced this pull request Oct 30, 2026
36 newer trunk commits; 11 conflicted files:
- PersonalGroupLifecycle.commit: trunk #26153 (cleanup on the reply's connection after
  appliedThroughReply, completed callback) ported onto perf's off-main task with
  main-actor Steps.
- WindowManager+Placement: trunk's ordered pendingPlacementOrder with perf's
  controllerBuildingIfWaiting.
- PaneHostView: trunk's rest clip from the rest cell plus perf's !isOnRenderSpring.
- SidebarListView: perf's docStore observation plus trunk's drawnSelectionOrder.
- acpmux App.tsx: trunk #27541 (quiet start, one line past the deadline) onto
  perf's RetryBackoff (RECOVERING_RETRY_MAX_MS in hostRetry.ts).
- settings search: perf's hidden rows plus trunk's scope/revision cache keys.
- pane-perf-terminal.py: perf's omnibar-toggle/--tunable plus trunk's page action.
- JoinConsent, acpmux hub mod list: both sides.
@github-actions

Copy link
Copy Markdown
Contributor

Shipped in:

@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

teamleaderleo added a commit that referenced this pull request Oct 30, 2026
…ts trail the run

The run's sidebar placements go through PersonalPlacementQueue (#26153),
one after another. On a loaded runner that queue trails the run, which
broke the upgrade in two ways:

- The migration put each new workspace in its classic group right after
  the create, while the workspace's own slot placement (`.bottom`) was
  still queued. That placement landed afterwards, cleared the group again
  and deleted the group it emptied. The import now waits for the slot
  placement to be listed (bounded at 5 s) and through the queue before it
  returns, so the group write comes after it.
- The simulator's settle() saw 0.5 s of quiet while placements were still
  queued, and verify() read the daemon's own order instead of classic's.

PersonalPlacementQueue gains isIdle and drained(). The tests read the tree
through AppServices.placementsSettled() (queue through, store caught up
with the daemon), from ClassicUpgradeSimulator.settle() and the
ClassicMigrationTests launch helper, and settle() no longer counts a busy
queue as quiet. No retry, skip or longer timeout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 30, 2026
…placements trail the run (#28362)

* cmux-next tests: the classic upgrade check reads the order once queued placements land (red)

A placement held ahead of the run keeps the personal placement queue busy
past the settle window. settle() returns while the run placements still
wait, and verify reads the daemon own order: red on current code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* cmux-next: a classic upgrade keeps its groups and order when placements trail the run

The run's sidebar placements go through PersonalPlacementQueue (#26153),
one after another. On a loaded runner that queue trails the run, which
broke the upgrade in two ways:

- The migration put each new workspace in its classic group right after
  the create, while the workspace's own slot placement (`.bottom`) was
  still queued. That placement landed afterwards, cleared the group again
  and deleted the group it emptied. The import now waits for the slot
  placement to be listed (bounded at 5 s) and through the queue before it
  returns, so the group write comes after it.
- The simulator's settle() saw 0.5 s of quiet while placements were still
  queued, and verify() read the daemon's own order instead of classic's.

PersonalPlacementQueue gains isIdle and drained(). The tests read the tree
through AppServices.placementsSettled() (queue through, store caught up
with the daemon), from ClassicUpgradeSimulator.settle() and the
ClassicMigrationTests launch helper, and settle() no longer counts a busy
queue as quiet. No retry, skip or longer timeout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 30, 2026
…ck (#28425) (#28430)

theFirstLaunchBringsEverythingOnce("multiWindow") fails intermittently on
base and on unrelated PRs: workspaces show in swapped order at
ClassicUpgradeSimulationTests.swift:45 and :52. The sidebar placements a
run queues (#26153) trail it on a loaded runner. The fix is #28362.

Until it lands, that one case's verify runs inside withKnownIssue
(isIntermittent) naming #28425. Every other case and check is unchanged.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
lawrencecchen added a commit that referenced this pull request Oct 31, 2026
…r 0.5 s of quiet (#28425) (#28526)

* cmux-next: classic upgrade checks wait for placements to land, not for 0.5 s of quiet (#28425)

ClassicUpgradeSimulator.settle() treated 0.5 s with no visible change as
done. Since #26153 a classic import places each new workspace at its slot
through the sidebar document (a `sidebar.apply` move, not the personal
placement queue that #28362 waits for), so on a loaded runner a move or an
adopt could still be on its way after the quiet window: the check then read
an order or a group the late move changed (#28331 attempts 1 and 2, #28425).

Product: SidebarDocStore counts the changes and adopts it sent and not yet
answered, and exposes isSettled and settled() (event-driven: each reply and
load end resumes the waiters). The classic import waits for it after the
personal queue, so a workspace's group write is sent after its slot move
is committed on the daemon, on the document path too.

Tests: settle() and the ClassicMigrationTests launch helper read the tree
only once every completion signal holds: the personal queue through, the
document settled, the store applied through an event barrier taken after
those replies, no live workspace still waiting for its new-workspace
placement, and the document projection current. No quiet window; a hang
guard records an issue naming what is still in flight.
SidebarDocSettledTests covers the new signal.

SidebarDocStore.swift: the remote protocol, its reply and SidebarDocUnsettled
move to SidebarDocRemote.swift (no change), so the file shrinks.

Sidebar-Look: no visual change
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* cmux-next tests: time the classic import's wait for the sidebar document (#28425)

The import now waits for its slot move's reply before each group write.
ClassicUpgradeSimulationPerfTests records that wait per imported workspace
through a DEBUG bench span (BenchSpans, nothing recorded in release) and
prints n, sum and p50/p95/max per profile (CLASSIC-SIM-PERF-SETTLE). The
perf suite also holds the one SidebarDocStore (.ownsSidebarDocStore), as
the other live-daemon suites do.

Sidebar-Look: no visual change
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* cmux-next tests: the parked check waits for the shells to exit, not for settle()'s quiet window (#28425)

backgroundWorkspacesStartTheirTerminalsWhenFirstShown read the parked state
right after settle(). `park-tabs` answers before the shells exit; a tab shows
dead with `relaunch` only once its host exited. The 0.5 s quiet window that
settle() no longer has covered that by chance; without it the last
workspace (scratch) read "not parked: [(false, nil)]" in 5 of 10 runs at
7f80b7d (step 815e7963). The check now reads once every background tab
shows parked (the daemon's tab-exit events), with a 60 s hang ceiling.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* cmux-next tests: forced-order red for #28425, sidebar document moves held past any quiet window

ClassicUpgradeHeldDocumentTests holds every sidebar document change and
adopt (the classic import's slot moves) for 4 s before it reaches the
daemon, as a loaded runner's slow reply does. The check must read the tree
only once those moves have landed. The test seam is a
`wrapping:` parameter of SidebarDocWiring.start (default: the daemon remote
as is), passed by ClassicUpgradeSimulator(documentRemote:).

The red is on a scratch never-merge ref (this test over the base logic:
settle() with its 0.5 s quiet window and the import without the document
wait); this commit and the branch head are the green.

Sidebar-Look: no visual change
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* cmux-next tests: the held-document red holds each move until someone waits for it, with no clock (#28425)

The 4 s hold was still a clock. HeldRemote now holds every sidebar document
change and adopt until someone waits in SidebarDocStore.settled() (the
store's onSettledWait test seam releases them; one sent while someone waits
goes on at once). The test reads, in the turn settle() returns in, how many
are still held: a settle that does not wait on the document returns with
moves held (red, every time); the new one cannot return until they are
released and answered (green). placementsSettled() now awaits the store's
settled() instead of polling isSettled.

Sidebar-Look: no visual change
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* cmux-next tests: a placement wait that hangs names what is pending (#28425)

placementsSettled() keeps the event-driven SidebarDocStore.settled() wait,
with a 60 s hang guard (a ceiling, not a quiet window): if the store has
not settled by then, the recorded issue says what is pending, from the
store's new pendingDescription (changes and adopts unanswered, a running
load, changes a load must settle, waiters). The held-document test prints
it in its failure too.

Sidebar-Look: no visual change
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* cmux-next tests: fix the compile of the held-document test and the placement wait (#28425)

Compile 6af24f9b at 08910ed failed:
- ClassicUpgradeHeldDocumentTests.swift:73: the trailing closure matched
  ClassicUpgradeSimulator.init's `ssh:` parameter (String), not
  `documentRemote:`; it is passed by label now.
- AppServices+PlacementsSettled.swift:41,50: `pendingDescription` is
  internal to CmuxNextSidebar; the helper imports it @testable.

Also: the held remote's `waiting` is typed @mainactor, the local in
release() no longer shadows it, and after the read nothing more is held
(shutdown's changes go through). The await on the settled wait is its own
statement.

Sidebar-Look: no visual change
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@lawrencecchen

Copy link
Copy Markdown
Contributor

Heads-up from #30961 (chat-open latency): it moves this PR's failure-path line in WorkspaceSpawner.shown (windows.pendingPlacementOrder.removeAll { $0 == key.rawValue }) into a shared WindowManager.forgetCreate(_:). That helper still clears the pending placement order, plus the placement and the pending row as before. Cmd-N's two failure paths and the new instant chat open call it, so the behavior this PR added is kept. The risk-evidence check reads the moved line as a take-back, and #30961's body says so with Takes back #26153: ....

This branch was previously deployed

1 inactive deployment
ci-routing-agent — 051c630f Deployed Oct 30, 2026 by teamleaderleo via namespace autofix #6794
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hold cmux-next batch queue: keep this PR out of the batch (docs/ci/cmux-next-batch.md) risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants