Skip to content

cmux NEXT updates: a staged update gives way to a newer build of the ring - #24183

Merged
teamleaderleo merged 11 commits into
feat-cmux-nextfrom
release-rings/staged-yields-to-newer
Oct 23, 2026
Merged

teamleaderleo merged 11 commits into
feat-cmux-nextfrom
release-rings/staged-yields-to-newer

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Leo-ask: ask-cd2e53c2ac (and ask-3d0b80c786)

"but how are the dev build hot swaps? like the update ready i want the latest dev builds to be able to show up..."

Leo: "how are the dev build hot swaps? like the update ready i want the latest dev builds to be able to show up"

What was wrong

Sparkle never reads the feed while an update waits:

  • When this app's driver holds the ready reply, the session stays open, so Sparkle's scheduled check is skipped (SPUUpdater.updaterTimerDidFire checks _sessionInProgress).
  • checkForUpdates() returned early with "check while an update waits: showing the staged update".
  • Picking a ring (follow(ring:), e.g. Nightly to Dev) also lands in checkForUpdates(), so a staged Nightly build stayed on the card. The ring switch did not reset a staged update.

The result: once build N was staged, a newer Dev build N+1 never reached the Update Ready card until a restart.

What changes

StagedUpdateRefresh (new, CmuxNextUpdater). While Update Ready shows, it probes the feed with the existing read-only probe, which filters by the followed ring the way Sparkle's allowedChannels does. It probes:

  • once per updates.checkIntervalSeconds (default 3600), and
  • at once when the person checks or picks a ring.

When the ring has a strictly newer build, it cancels the staged installer and calls UpdateController.checkInBackground(). The cancel replies Skip to Sparkle's held ready reply, the same path dropStaleStagedUpdate already used. It records no skipped version and touches no user data. Sparkle then downloads the newer build and stages it, and the card shows it.

Guards:

  • Never during an install. Only the Update Ready phase arms or runs it. A click to install ends it: the phase leaves .ready, flow.installRequested is checked, and the driver's cancel handle is gone once the install starts.
  • Only installers this app can replace. The new UpdateController.canCancelStagedUpdate must be true (this driver holds the installer), and downloadsUpdatesInBackground must be on. Sparkle's own silent install-on-quit and deferred downloads (Low Data Mode, metered link, managed channel) are left alone, and nothing is fetched for them.
  • No empty card from delta holds. On nightly, a build newer than the staged one but still inside Sparkle's pending-delta window (45 min with no deltas listed) waits for the next interval. Otherwise Sparkle would hold it once and nothing would be staged.

Stop condition and cleanup:

  • One one-shot DemandTimer on the injected clock (owner UpdaterService.stagedRefresh).
  • It is armed only in Update Ready, and only with updates.checkAutomatically on.
  • It is cancelled when the phase leaves Update Ready (install, relaunch, swap, cancel).
  • One probe runs at a time, and a check joins the probe in flight. After a probe that keeps the staged build, the next one waits a whole interval.
  • The timer cancels its sleep when the object goes. A probe in flight ends at the fetcher's 15-second deadline.
  • Nothing blocks the main thread: the fetch and parse run off the main actor (UpdateProber, @concurrent).

God-type ratchet. dropStaleStagedUpdate moves into the same type as dropStale(updater:), since both are staged-update upkeep. The UpdateActionDelegate conformance moves to its own file. Both are pure moves, so the over-budget UpdaterService type and file shrink instead of growing: 1881 to 1864 lines and 501 to 481.

Coverage limits (read before dogfooding)

On the cmux NEXT nightly track, installsUpdatesWhenIdle is on. A staged build normally goes straight to the idle install: the relaunch gate waits up to updates.idleInstallMaxWaitSeconds, default 900 s. That wait is an install in progress, so this PR leaves it alone. The next build then arrives through the launch check after the relaunch.

This PR covers a staged build that waits for a click:

  • the automatic install was declined (preflight failed), or
  • updates.downloadAutomatically was off and the person clicked to download.

It does not cover Sparkle's own silent install-on-quit (SUAutomaticallyUpdate on, a preference shared with the legacy NIGHTLY app). Sparkle has no API to cancel that installer.

No capture: no visible UI change; the existing Update Ready card shows whichever build Sparkle stages, and this only changes which build that is.

Tests

UpdateStagedYieldsToNewerTests (CmuxNextAppTests) uses a counting fake feed, a ManualClock and stubbed Sparkle seams:

  • a newer Dev build replaces the staged one at the next scheduled check
  • the newest staged build is kept, and the feed is read once per interval, not sooner
  • picking Dev while a Nightly build is staged replaces it at once
  • the person's check while staged finds the newer build
  • an install in progress is never probed or cancelled
  • a staged update this app cannot replace reads no feed
  • a fresh Dev build with no deltas waits an interval
  • with automatic checks off, there is no scheduled probe

Red commit d28e156 (an inert skeleton plus the tests), then the fix e304565. The Codex review then asked for four more fixes, each landed after its own red test where one could be written: 9213fd4 (the swap checks through this app's driver, never Sparkle's silent driver; a ring picked during a probe is read again; schedule changes replace the pending probe; the delta wait applies only to scheduled swaps of items with no sparkle:deltas), red 834eb6b then 178083f, and red c3f1b2a then 89a3307 (a check while staged that keeps the build, or that starts no probe, ends the person's ask, so a later check nobody asked for stays silent).

The same tests also cover: a fresh build that lists deltas swaps at once; a check the person asked for takes a fresh build at once; a ring picked during a probe reads the new ring, both ways; a schedule change replaces the pending probe.

If the newer build's download fails after the swap, nothing is staged until Sparkle's next scheduled check. Its timer restarts when the session ends, and that check stages the newest build again. The reviewer accepted this as non-blocking.

Command: cmux-ci run --class light --script scripts/ci/package-test-lane.sh --arg=suite --arg=Packages/macOS/CmuxNext --arg=UpdateStagedYieldsToNewerTests --ref <sha>

  • On the red commit (--red): queued on the fleet (the suites queue has been backed up for over an hour). I will post the result as a comment.
  • On the head, with UpdateReadyNotNewerTests, UpdateRingProbeTests, RingReturnTests and SilentBackgroundUpdateTests: queued on the fleet. Hosted PR CI runs the cmux-next Swift tests on the head.

Observed / Not run

  • Observed: the fleet compile-check --app passed at every head (e304565, 9213fd4, 178083f, 89a3307). Codex (xhigh, on cmux16) reviewed four passes: CHANGES, CHANGES, CHANGES, then SHIP at 89a3307. prepush-gate.py reported no new violations. check-concurrency.sh passed. check-no-godfiles.sh --base origin/feat-cmux-next on the changed files passed; the type and the file both shrank. Fleet results are listed above.
  • Not run: a live swap on a real NIGHTLY with a real Dev build. That needs two signed Dev builds published in sequence. No DEV app build or capture: there is no UI change, and the card shows whichever build Sparkle stages.
  • Read, not run: Sparkle 2.10.0 SPUUpdater.m (updaterTimerDidFire skips while a session is in progress; checkForUpdatesWithDriver resumes an installer in progress instead of reading the feed). That is what confirmed the bug.

Risk: high (updater). This is not behind a default-off toggle, although docs/ci/risk-tiers.md says a user-noticeable high-tier change ships dark: Leo asked for this exact behavior, and only a newer signed build of the ring the person chose replaces a staged one. A revert is gh-merge-green --revert. The PR swaps a downloaded update only for a strictly newer signed build of the same ring, through the existing cancel path.

Changelog

  • Changed: A staged update now gives way to a newer build of your update channel at the next scheduled check, or at once when you check or switch channels, so Update Ready always offers the newest build.

Agent session: huge-blue

🤖 Generated with Claude Code

teamleaderleo and others added 2 commits October 22, 2026 04:20
… (red)

Leo: "how are the dev build hot swaps? like the update ready i want the
latest dev builds to be able to show up". Sparkle never reads the feed
while an update waits, so a Dev build published after the staged one
waits for a restart. These tests expect a probe once per check interval
(and on the person's check or ring pick) that swaps in a strictly newer
build, never during an install, never more than once per interval.

StagedUpdateRefresh is an inert skeleton here; the fix fills it in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c1c-9365-71b3-b73b-dc961610d618&host=huge-blue
Leo: "how are the dev build hot swaps? like the update ready i want the
latest dev builds to be able to show up".

Sparkle never reads the feed while an update waits (the held ready reply
keeps its session open, so its scheduled check is skipped, and a check
answers with the waiting update). While an update waits,
StagedUpdateRefresh now probes the feed with the read-only probe,
filtered by the ring as Sparkle filters, once per
updates.checkIntervalSeconds, and at once when the person checks or
picks a ring (follow(ring:) checks). A strictly newer build cancels the
staged installer (Skip on the held reply: no skipped version, no user
file touched) and starts Sparkle's background check, which downloads
and stages the newer build.

Never during an install: only Update Ready arms or runs it, a click to
install ends it, and only an installer this app's driver holds is
replaced (UpdateController.canCancelStagedUpdate), with downloads on.
A build fresh enough that Sparkle would hold it for its deltas waits an
interval. Stop condition: one one-shot DemandTimer, armed only in Update
Ready with automatic checks on, cancelled when the phase leaves it; one
probe at a time; the next a whole interval later.

dropStaleStagedUpdate moves into the same type (staged-update upkeep),
and the UpdateActionDelegate conformance into its own file, so the
UpdaterService god type and file shrink instead of growing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c1c-9365-71b3-b73b-dc961610d618&host=huge-blue
@teamleaderleo teamleaderleo added the risk:high Risk tier (docs/ci/risk-tiers.md) label Oct 22, 2026
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

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

Review e4bf66b: 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=pr24183 -f ref=release-rings/staged-yields-to-newer -f platform=macos -f backend_mode=local

red: cmux-next checks (god files, concurrency, crash safety, l10n); no finished base run on 44fc3d3 to compare; do not merge until green; see lane-rules

Tour of e4bf66b256 (run)

The path-selected recorder failed for core-after, core-before; see the run artifact and failed manifests.

Path-selected interactions

Interaction Changed paths
core Packages/macOS/CmuxNext/Sources/CmuxNextUpdater/AppcastItem.swift
Packages/macOS/CmuxNext/Sources/CmuxNextUpdater/AppcastParser.swift
Packages/macOS/CmuxNext/Sources/CmuxNextUpdater/StagedUpdateRefresh.swift
Packages/macOS/CmuxNext/Sources/CmuxNextUpdater/UpdateFlow.swift
Packages/macOS/CmuxNext/Sources/CmuxNextUpdater/UpdaterService\+ActionDelegate.swift
Packages/macOS/CmuxNext/Sources/CmuxNextUpdater/UpdaterService\+Flow.swift
Packages/macOS/CmuxNext/Sources/CmuxNextUpdater/UpdaterService\+Indicator.swift
Packages/macOS/CmuxNext/Sources/CmuxNextUpdater/UpdaterService.swift
Packages/macOS/CmuxNext/Tests/CmuxNextAppTests/UpdateStagedYieldsToNewerTests.swift

Core UI (before): FAILED — 16 ok, 3 failed, 1 unavailable

tour

Video (mp4)

# Step Result Command
1 Launch ok
2 New workspace ok cmux workspace new --name Tour
3 Type in the terminal ok cmux workspace name:Tour screen current pane current tab current terminal current write --text "echo hello from the cmux-next tour\r"
4 A command reports progress: tab loading spinner ok cmux workspace name:Tour screen current pane current tab current terminal current write --text "clear; printf '\\033]9;4;3\\007'; sleep 900\r"
5 Split right failed: exited 1 cmux action run splitRight
6 Split down failed: exited 1 cmux action run splitDown
7 New terminal tab failed: exited 1 cmux action run newSurface
8 Browser tab ok cmux tab new-browser --url https://example.com
9 Hide the sidebar ok cmux action run toggleSidebar
10 Show the sidebar ok cmux action run toggleSidebar
11 Notification ok cmux notify --title Tour --body "Hello from CI"
12 Notifications panel ok cmux action run showNotifications
13 Agent chat ok cmux agent new-chat
14 Agent workspace ok cmux workspace new --name Agent
15 Agent starts ok cmux workspace name:Agent screen current pane current tab current terminal current write --text "clear; printf '\\033]7501;state=working\\033\\\\'; sleep 8; printf '\\033]7501;state=done\\033\\\\'; sleep 900\r"
16 An agent works: row working spinner ok cmux workspace new --name Notes
17 The agent finishes: done mark in the spinner's place ok
18 Session tree: keycaps on the first rows ok cmux settings set sidebar.sessionTree true
19 Session tree back off for later tours ok cmux settings set sidebar.sessionTree false
20 Profile menu unavailable: exited 1 (the menu shot needs a screen capture route) cmux action run sidebar.profileMenu

Failed steps:

5. Split right
Split right

6. Split down
Split down

7. New terminal tab
New terminal tab

Screenshots (12)

1. Launch
Launch

2. New workspace
New workspace

3. Type in the terminal
Type in the terminal

4. A command reports progress: tab loading spinner
A command reports progress: tab loading spinner

8. Browser tab
Browser tab

9. Hide the sidebar
Hide the sidebar

11. Notification
Notification

12. Notifications panel
Notifications panel

13. Agent chat
Agent chat

16. An agent works: row working spinner
An agent works: row working spinner

17. The agent finishes: done mark in the spinner's place
The agent finishes: done mark in the spinner's place

18. Session tree: keycaps on the first rows
Session tree: keycaps on the first rows

### Core UI \(after\): FAILED — 16 ok, 3 failed, 1 unavailable

tour

Video (mp4)

# Step Result Command
1 Launch ok
2 New workspace ok cmux workspace new --name Tour
3 Type in the terminal ok cmux workspace name:Tour screen current pane current tab current terminal current write --text "echo hello from the cmux-next tour\r"
4 A command reports progress: tab loading spinner ok cmux workspace name:Tour screen current pane current tab current terminal current write --text "clear; printf '\\033]9;4;3\\007'; sleep 900\r"
5 Split right failed: exited 1 cmux action run splitRight
6 Split down failed: exited 1 cmux action run splitDown
7 New terminal tab failed: exited 1 cmux action run newSurface
8 Browser tab ok cmux tab new-browser --url https://example.com
9 Hide the sidebar ok cmux action run toggleSidebar
10 Show the sidebar ok cmux action run toggleSidebar
11 Notification ok cmux notify --title Tour --body "Hello from CI"
12 Notifications panel ok cmux action run showNotifications
13 Agent chat ok cmux agent new-chat
14 Agent workspace ok cmux workspace new --name Agent
15 Agent starts ok cmux workspace name:Agent screen current pane current tab current terminal current write --text "clear; printf '\\033]7501;state=working\\033\\\\'; sleep 8; printf '\\033]7501;state=done\\033\\\\'; sleep 900\r"
16 An agent works: row working spinner ok cmux workspace new --name Notes
17 The agent finishes: done mark in the spinner's place ok
18 Session tree: keycaps on the first rows ok cmux settings set sidebar.sessionTree true
19 Session tree back off for later tours ok cmux settings set sidebar.sessionTree false
20 Profile menu unavailable: exited 1 (the menu shot needs a screen capture route) cmux action run sidebar.profileMenu

Failed steps:

5. Split right
Split right

6. Split down
Split down

7. New terminal tab
New terminal tab

Screenshots (12)

1. Launch
Launch

2. New workspace
New workspace

3. Type in the terminal
Type in the terminal

4. A command reports progress: tab loading spinner
A command reports progress: tab loading spinner

8. Browser tab
Browser tab

9. Hide the sidebar
Hide the sidebar

11. Notification
Notification

12. Notifications panel
Notifications panel

13. Agent chat
Agent chat

16. An agent works: row working spinner
An agent works: row working spinner

17. The agent finishes: done mark in the spinner's place
The agent finishes: done mark in the spinner's place

18. Session tree: keycaps on the first rows
Session tree: keycaps on the first rows

Tours are data in scripts/cmux-next/media/tours: add a step or a tour file to show your feature.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Owned by release-rings on huge-blue · session

@blacksmith-sh

blacksmith-sh Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Found 9 test failures on Blacksmith runners:

Failures

Test View Logs
/tmp/tmp1aq5qjk5/summary-fail.json (live):/summary-fail.json (live): View Logs
/tmp/tmp3cb3xkyp/summary-missing.json (live):/summary-missing.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_base_passes (main.NoticesPairTests.test_base_passes)/
test_base_passes (main.NoticesPairTests.test_base_passes)
View Logs
test_targets_outside_the_app_go_to_the_mac_canary (main.SwiftCanaryFleetCoverage.te
st_targets_outside_the_app_go_to_the_mac_canary)/
test_targets_outside_the_app_go_to_the_mac_canary (main.SwiftCanaryFleetCoverage.te
st_targets_outside_the_app_go_to_the_mac_canary)
View Logs
test_the_repository_highlights_validate (main.DigestTests.test_the_repository_highl
ights_validate)/
test_the_repository_highlights_validate (main.DigestTests.test_the_repository_highl
ights_validate)
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

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

… and schedule changes

From the Codex review of #24183:
- The swap's check is a foreground check through this app's driver
  (UpdateController.checkForUpdates), never Sparkle's silent driver, so
  the newer build is staged replaceable again for the next swap.
- A probe of the old ring in flight when the person picks another ring
  is read again for the new ring, never taken as its answer.
- A changed updates.checkAutomatically or checkIntervalSeconds replaces
  the pending probe deadline (off ends it; a new interval counts anew).
- The delta wait matches Sparkle's: only a scheduled swap, only for a
  build that lists no sparkle:deltas yet (AppcastItem.listsDeltas); a
  check the person asked for takes the build at once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c1c-9365-71b3-b73b-dc961610d618&host=huge-blue
@cursor

cursor Bot commented Oct 22, 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 and others added 2 commits October 22, 2026 05:25
…behind (red)

Codex re-review of #24183: a check while Update Ready left the flow's
pending ask set, so a later check nobody asked for showed its progress.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c1c-9365-71b3-b73b-dc961610d618&host=huge-blue
The probe that answers a check while Update Ready shows clears the flow's
pending ask when it keeps the staged build (UpdateFlow.askAnswered), so
a later check nobody asked for stays silent. A swap the person started
marks its Sparkle check as theirs (userCheckRunning), so another check
joins it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c1c-9365-71b3-b73b-dc961610d618&host=huge-blue
@cursor

cursor Bot commented Oct 22, 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

Review (Codex gpt xhigh via acpmux on cmux16): SHIP at 89a3307

An independent reviewer from a different model, after four passes. Passes 1-3 at e304565, 9213fd4 and 178083f asked for changes; all are fixed on this head (see the PR body). The fleet compile-check --app passed at this head (job 847482d0faf7e663225b4852).

…rings/staged-yields-to-newer

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

cursor Bot commented Oct 22, 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

Review (Codex gpt xhigh via acpmux on cmux16, diff only): SHIP at dfcb302

A fresh independent review at the merged head. The merge of feat-cmux-next a3feffa (#24227) touched no updater source or test; the earlier SHIP was at 89a3307. The fleet compile-check --app passed at this head (job b9c10430c9aae3fffa2ac9f1).

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next guards / nightly-guards / workflow-guard-tests / release-notary is red on 9 of 14 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.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next / cmux-next checks (god files, concurrency, crash safety, l10n) › Checks job structure is red on 11 of 12 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.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next / cmux-next checks (god files, concurrency, crash safety, l10n) › No fleet host names in gallery fixtures is red on 11 of 12 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.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next crash-class rules / cmux-next crash-class rules is red on 9 of 10 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.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

cmux-next / cmux-next checks (god files, concurrency, crash safety, l10n) › No new SwiftUI (macOS UI is AppKit) is red on 16 of 18 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.

teamleaderleo and others added 2 commits October 23, 2026 03:27
…n Install click ends the staged-update probes

Red on 501dca4: the away-and-back probe's old answer is taken, and a probe or the
scheduled timer still cancels the installer after the click (review at 501dca4, gpt-6-sol).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c1c-9365-71b3-b73b-dc961610d618&host=huge-blue
…l click ends the staged-update probes

Ring picks are counted (ringMoved), so a probe that began before one is not taken as the
ring's answer, even after away and back. A click on Install (the gate's install effect) cancels
the pending probe, arms none, and a probe in flight cancels nothing, until Update Ready ends.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c1c-9365-71b3-b73b-dc961610d618&host=huge-blue
@cursor

cursor Bot commented Oct 23, 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

Review (independent, Codex gpt-6-sol, xhigh, diff-only on cmux16, no checkout): SHIP at e4bf66b

The earlier review at 501dca4 (gpt-6-sol) raised two blocks. Both are fixed in e4bf66b, with regression tests in f96f943:

  1. A probe that began before a ring pick is read again, even after picking away and back (ringMoved() counts picks). Test: aRingPickedAwayAndBackWhileAProbeRunsIsReadAgain.
  2. A click on Install ends the staged-update probes. The gate's .install effect cancels the timer and arms nothing, and a probe in flight cancels nothing until Update Ready ends. Tests: anInstallClickedWhileAProbeRunsKeepsItsInstaller, anInstallClickEndsTheScheduledProbes.

Verdict text: "No blocking findings. The generation counter, install gate, replaceability checks, timer cancellation, and race tests cover the requested failure modes. The remaining test gap is recovery when a replacement check fails without a phase transition."

Observed

  • cmux-ci compile-check --app --ref e4bf66b256a5d0624a5d64b5fadd070b21fbba3b: passed (job 1b43e42d02f962e6569f00f4).
  • Fleet scripts/ci/run-swift-testing-suites.sh Packages/macOS/CmuxNext at e4bf66b (step db20530a7a75aa4e6501be1a): all 18 UpdateStagedYieldsToNewerTests pass. That step's other reds are unrelated suites (Home type-to-focus, sidebar, ClassicUpgradeSimulation) that are also red at 501dca4.
  • At 501dca4, the hosted cmux-next swift test red is 3 base tests (NativeTooltipGuard, BrowserProfileLinkMenu, HiddenPageHibernation) plus a run truncation. None of them are in this PR's files.
  • The cmux-next checks, crash-class rules, release-notary and Guard status reds are base reds; base-red-watch confirms them on this PR.

Not run

  • A real Sparkle install handoff. The tests stub the installer seams (enableSparkle: false).

@teamleaderleo
teamleaderleo merged commit cd97e9c into feat-cmux-next Oct 23, 2026
120 of 126 checks passed
@teamleaderleo
teamleaderleo deleted the release-rings/staged-yields-to-newer branch October 23, 2026 04:20
@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

This branch was previously deployed

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

Labels

risk:high Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant