You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ios: a shutdown within seconds of close lets the open's runner prewarm boot the simulator again #3359
Track a path to the symptom in #3321 that #3357 does not cover: a simulator shut down with xcrun simctl shutdown right after close is booted again, this time by a runner the daemon starts, not by the retained runner. #3357 stops the retained runner; this is a different mechanism, so do not reopen #3357 for it.
Evidence
Measured on an iPhone 17 (iOS 27.0, Xcode 27.1 beta), Settings app, agent-device built from the #3357 branch, isolated --state-dir:
agent-device open com.apple.Preferences --relaunch --platform ios --udid "$A"
agent-device snapshot -i
sleep 2
agent-device close
xcrun simctl shutdown "$A"# less than 1 s after close
3 of 3 runs: the device shows Booted within 2 s, the original xcodebuild is gone, and about 15 s later the daemon (the parent of the new xcodebuild) has started a replacement runner. The device ends Booted with a runner alive and nothing reported.
Gap sweep with refactor(apple): simplify warm runner ownership #3357 in (head dd52602c3): 6 s and 10 s between close and shutdown end Shutdown; a 3 s gap ends Booted with a daemon-started runner, so the window is wider than 1 s. Earlier, 5 of 5 runs at 6 to 14 s ended Shutdown.
Origin of the replacement runner, from a stack trace on launchRunnerProcess: prewarmRunnerSession → prepareLocalIosRunner → runPrepareAttempt → ensureRunnerSession → startRunnerSessionWithLease. That is the open's background runner prewarm (packages/platform-apple/src/runner/runner-lifecycle.ts), whose attempt loop re-enters ensureRunnerSession when its runner is gone.
Not measured: a baseline on main without refactor(apple): simplify warm runner ownership #3357, and whether the prewarm is still in its attempt loop when close runs or is re-entered by something else. Both decide the owner below.
Required behavior
A runner start that a prewarm loop makes after the session's close has retained the runner must not boot a device that was shut down in between.
Decide the owner. The refactor(apple): simplify warm runner ownership #3357 watch cannot cover this: it only guards a retained runner, and here the runner that boots the device is a new session started by the prewarm loop. Candidates: a retaining close retires the prewarm loop's start admission for the device (non-retained close already fences admissions through fenceRunnerStartAdmissionsForTeardown), or the prewarm loop refuses to start a runner for a device with no live session.
Key the decision on session and admission state, never on a timing window or message text.
Completion
The sequence above, with shutdown 1 to 3 s after close, ends with the device Shutdown and no daemon-spawned xcodebuild for it, in 3 of 3 live runs.
A test at the owning seam shows a prewarm attempt after a retaining close starts no runner.
changed the title [-]ios: a shutdown under 1 s after close lets the open's runner prewarm boot the simulator again[/-][+]ios: a shutdown within seconds of close lets the open's runner prewarm boot the simulator again[/+]on Oct 10, 2026
Purpose
Track a path to the symptom in #3321 that #3357 does not cover: a simulator shut down with
xcrun simctl shutdownright aftercloseis booted again, this time by a runner the daemon starts, not by the retained runner. #3357 stops the retained runner; this is a different mechanism, so do not reopen #3357 for it.Evidence
Measured on an iPhone 17 (iOS 27.0, Xcode 27.1 beta), Settings app, agent-device built from the #3357 branch, isolated
--state-dir:Bootedwithin 2 s, the originalxcodebuildis gone, and about 15 s later the daemon (the parent of the newxcodebuild) has started a replacement runner. The device endsBootedwith a runner alive and nothing reported.dd52602c3): 6 s and 10 s betweencloseandshutdownendShutdown; a 3 s gap endsBootedwith a daemon-started runner, so the window is wider than 1 s. Earlier, 5 of 5 runs at 6 to 14 s endedShutdown.launchRunnerProcess:prewarmRunnerSession→prepareLocalIosRunner→runPrepareAttempt→ensureRunnerSession→startRunnerSessionWithLease. That is the open's background runner prewarm (packages/platform-apple/src/runner/runner-lifecycle.ts), whose attempt loop re-entersensureRunnerSessionwhen its runner is gone.mainwithout refactor(apple): simplify warm runner ownership #3357, and whether the prewarm is still in its attempt loop whencloseruns or is re-entered by something else. Both decide the owner below.Required behavior
closehas retained the runner must not boot a device that was shut down in between.closeretires the prewarm loop's start admission for the device (non-retained close already fences admissions throughfenceRunnerStartAdmissionsForTeardown), or the prewarm loop refuses to start a runner for a device with no live session.Completion
shutdown1 to 3 s afterclose, ends with the deviceShutdownand no daemon-spawnedxcodebuildfor it, in 3 of 3 live runs.closestarts no runner.