Repository navigation
CI-Fix: Mount the watchOS runtime again before the watch tests when CoreSimulator has lost it - #6101
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
🟡 Changes recommended
A failed runtime query during recovery incorrectly reports success and can launch watch tests prematurely.
1 open issue
What changed in this PR
Adds runtime recovery to reduce watchOS CI failures caused by CoreSimulator losing mounted runtimes.
Changes:
- Detects missing runtime mounts and restarts simulator daemons to recover them.
- Checks watchOS availability before destination selection and retries watch tests once.
- Documents recovery alongside the existing CI cleanup step.
| File | Description |
|---|---|
| Tools/EnsureSimulatorRuntime.sh | Adds runtime detection, recovery, and polling. |
| fastlane/lanes/testing.rb | Integrates runtime checks and a watch-test retry. |
| .github/workflows/ci.yml | Updates comments to describe lane-level recovery. |
Review effort: Balanced
…ator has lost it About one CI run in three on the xcode-27 image loses the watch tests to the runner image, not to the code: simdiskimaged takes the usable watchOS 27.0 runtime volume down during the job even with the duplicate registration deleted up front. The disk image keeps reporting Ready while the runtime is gone from `simctl list runtimes`, and the watch tests fail with "The watchOS 27.0 simulator runtime is not available" or hang connecting to the fresh simulator. Tools/EnsureSimulatorRuntime.sh checks for an available runtime of a platform and, only when there is none, ejects that platform's volumes, restarts simdiskimaged and CoreSimulatorService and waits for the runtime to be mounted again, which takes about a second. The test lane runs it for watchOS before resolving the watch destination and gives the watch run one retry with the runtime checked again in between.
c6d5ff1 to
fdf33a1
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #6101 +/- ##
==========================================
+ Coverage 56.09% 56.22% +0.13%
==========================================
Files 1256 1256
Lines 83431 83476 +45
==========================================
+ Hits 46798 46933 +135
+ Misses 36633 36543 -90 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|

Since the CI was failing I looked at it. Obviously I couldn't verify if this fix is properly working but in theory it should fix the currenct CI instability issues.
AI Policy
Select exactly one option that describes AI usage in this contribution:
Summary
About one CI run in three on the
xcode-27image loses the watch tests to the runner, not to the code. The job deletes the duplicate watchOS 27.0 runtime up front (#6087), and that helps, butsimdiskimagedstill takes the usable copy's volume down at some point during the job. The disk image keeps reportingReady, the runtime itself is gone, and twenty minutes later the watch tests fail with "The watchOS 27.0 simulator runtime is not available" (#6100, run 39518843929) or hang connecting to the fresh simulator (run 39477194253).mainhas been lucky three times in a row, which is roughly what a one in three failure rate looks like.I reproduced the state on my Mac by force-unmounting the runtime volume:
simctl runtime liststill saysReady,simctl list runtimesno longer lists watchOS 27.0 at all, and it doesn't come back on its own. What does bring it back, within a second, is what Sentry's and dotnet's CI already do for the same daemon: eject the platform's runtime volumes, killsimdiskimagedandCoreSimulatorService, and let CoreSimulator mount everything registered again.Change
Tools/EnsureSimulatorRuntime.sh(new): compares the platform's disk images thatsimctl runtime listreportsReadywith whatsimctl list runtimesactually has mounted. Only when a Ready image has no mounted runtime does it eject that platform's volumes, restart the two daemons and poll for up to two minutes. Asimctlthat fails outright counts as not mounted, before the restart and while polling, so a half-restarted service can't pass for a recovered one.fastlane/lanes/testing.rb: thetestlane runs it for watchOS before resolving the watch destination, which also keeps the device list from coming up empty. The watchrun_testsgets one retry, with the runtime checked again in between, for the daemon striking during the run or the simulator not connecting. A genuine watch test failure costs one extra run of about two minutes..github/workflows/ci.yml: the cleanup step's comment points at the lane's recovery. The step itself stays.The recovery needs
sudo, which the runners grant without a password. On a developer machine it only prompts when the runtime is actually missing, so a normalfastlane testnever asks.Tests
Not unit-testable, so verified by hand on macOS 26.7.1 with Xcode 27.1:
Not mounted although its disk image is Ready: watchOS 27.0 (24R362)), restarts the daemons and reports it mounted again within a second. The watch tests then run green on it.bundle exec fastlane testwith the runtime unmounted beforehand: green, twice.Any other notes
Not part of the CPU series: it unblocks CI for it. The watch half of the test job fails on the runner image about one run in three, whatever the PR changes.