Repository navigation
Treat "no update available" as a success in Attempt Update - #9435
Conversation
…port install failure
… show an error pill
Fixes the red "Update Didn't Start / check your internet connection" pill shown when Attempt Update runs while already on the latest version.
📝 WalkthroughWalkthroughThe updater now treats ChangesUp-to-date update attempt
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 25✅ Passed checks (25 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@Packages/macOS/CmuxUpdater/Tests/CmuxUpdaterTests/UpdateControllerPipelineTests.swift`:
- Around line 417-418: Replace the fixed Task.yield loop in
UpdateControllerPipelineTests with a deterministic completion signal or bounded
predicate confirming attempt handling is complete, such as inactive coordination
and a disarmed watchdog, before asserting the absent state. In
cmuxUITests/UpdatePillUITests.swift lines 205-208, wait for a deterministic
UI-test signal that the command-palette attempt reached its terminal state
before asserting error absence; use fulfillment from the triggering event rather
than scheduler yields.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 5c49d9b9-55e6-417e-b731-2038bd1e1a85
📒 Files selected for processing (4)
Packages/macOS/CmuxUpdater/Sources/CmuxUpdater/AttemptUpdateCoordinator.swiftPackages/macOS/CmuxUpdater/Tests/CmuxUpdaterTests/AttemptUpdateCoordinatorTests.swiftPackages/macOS/CmuxUpdater/Tests/CmuxUpdaterTests/UpdateControllerPipelineTests.swiftcmuxUITests/UpdatePillUITests.swift
| // Give any erroneous reaction a chance to replace the state. | ||
| for _ in 0..<2_000 { await Task.yield() } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Wait for deterministic terminal handling before asserting the regression result.
The fixed yield loop and immediate absence check do not prove that queued .notFound handling is complete. Both tests can pass before the prior erroneous reaction replaces the normal result.
Packages/macOS/CmuxUpdater/Tests/CmuxUpdaterTests/UpdateControllerPipelineTests.swift#L417-L418: Replace the fixedTask.yield()loop with a completion signal or a bounded predicate for completed attempt handling, such as inactive coordination and a disarmed watchdog.cmuxUITests/UpdatePillUITests.swift#L205-L208: Assert error absence only after a deterministic UI-test signal confirms that the command-palette attempt reached its terminal state.
As per coding guidelines, “For scheduler or asynchronous ordering, fulfill continuations or expectations from the triggering event.”
📍 Affects 2 files
Packages/macOS/CmuxUpdater/Tests/CmuxUpdaterTests/UpdateControllerPipelineTests.swift#L417-L418(this comment)cmuxUITests/UpdatePillUITests.swift#L205-L208
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@Packages/macOS/CmuxUpdater/Tests/CmuxUpdaterTests/UpdateControllerPipelineTests.swift`
around lines 417 - 418, Replace the fixed Task.yield loop in
UpdateControllerPipelineTests with a deterministic completion signal or bounded
predicate confirming attempt handling is complete, such as inactive coordination
and a disarmed watchdog, before asserting the absent state. In
cmuxUITests/UpdatePillUITests.swift lines 205-208, wait for a deterministic
UI-test signal that the command-palette attempt reached its terminal state
before asserting error absence; use fulfillment from the triggering event rather
than scheduler yields.
Source: Coding guidelines
… update An accepted install attempt (Attempt Update palette command, Install and Relaunch buttons) re-resolves the feed with a fresh check. #9435 stopped the fresh check's own "no update" result from becoming the misleading "Update Didn't Start / check your internet connection" error, but two paths of the same class still raised it on an up-to-date machine: 1. AttemptUpdateCoordinator.awaitingFreshCheck treated a notFound from a still-finishing prior session as installFailed. Now it ends the attempt quietly: a completed check saying "no update" is a truthful, visible outcome regardless of which session produced it. The install watchdog still bounds genuinely stalled attempts. 2. updateDriverDidFinishCycle raised the error over a .notFound state observed while the coordinator had not yet drained that transition. notFound now counts as a visible terminal there, like .error. After an install is actually accepted (startingDownload phase), notFound still fails the attempt; nothing changes for real stalls. Fixes the remaining variants of #9262. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes #9262
Running "Attempt Update" from the command palette while already on the latest version showed a red pill: "Update Didn't Start — cmux couldn't start the update. Check your internet connection and try again." The check had succeeded and the network was fine; there was simply nothing to install.
Mechanism
AttemptUpdateCoordinator.handleStateChangeclassified.notFoundas.installFailedin the.awaitingResultphase. The controller then ransetInstallDidNotStartError, whose finalmodel.replaceActiveState(with: errorState)overwrote the model's correct.notFoundstate with the error, so the user never saw the true result of their own check..notFoundin.awaitingResultnow stops monitoring and returns.none, leaving the model's.notFoundto render as the normal up-to-date result. This also makes the coordinator agree withInstallWatchdog, which already classified.notFoundas resolved and non-stalled.Deliberately unchanged:
.idlein the same phase still returns.installFailed(the attempt ended with no result at all), and.notFoundin.awaitingFreshCheck/.startingDownloadstill fails, since anotFoundafter the user accepted an install is genuinely unexpected. The issue's wider question about whether the three palette update commands should stay distinct is out of scope here.Testing
Regression tests, split so CI goes red then green:
stopsMonitoringWhenFreshCheckFindsNothingto assert.none(it previously asserted.installFailed, locking the bug in) and addsreportsInstallFailedWhenFreshCheckEndsAtIdleto pin the.idlebehavior that is intentionally kept.UpdatePillUITests.testAttemptUpdateWithNoUpdateAvailableDoesNotShowError, which drives the real command palette entry point and asserts the "No Updates Available" pill appears instead of the error.acceptedInstallFailureAcknowledgesReplacedSparkleTerminalso it exercises the accepted-install path (.startingDownload) that still fails, rather than the up-to-date path that no longer does.Commands:
swift testinPackages/macOS/CmuxUpdater: 87 tests pass at the fix commit. At the pre-fix source,stopsMonitoringWhenFreshCheckFindsNothingand a new pipeline-level replay (upToDateAttemptShowsNoUpdateAvailableInsteadOfError) both fail, confirming they capture the bug.test-e2e.ymlrun ofUpdatePillUITests/testAttemptUpdateWithNoUpdateAvailableDoesNotShowError, dispatched at both the pre-fix commit and the fix head.Dev build:
./scripts/reload.sh --tag sym9262succeeded and the tagged app launched (the cloud builder failed on an unrelated stale zig toolchain). Driving the palette from the debug socket was not possible in this environment because the tagged window never became key, so the palette entry point is covered by the hosted XCUITest above rather than by a local socket transcript.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by cubic
Treat “no update available” as a successful outcome for “Attempt Update,” so users see “No Updates Available” instead of the red “Update Didn’t Start” error. Fixes #9262.
.notFoundduring the fresh check now ends the attempt quietly (stop monitoring, return.none) and keeps the model’s.notFoundstate;.idleand unexpected.notFoundin earlier phases still fail.Written for commit ea628a8. Summary will update on new commits.
Summary by CodeRabbit
Bug Fixes
Tests