Repository navigation
Conversation
…lator A runner retained after `close` owns its Simulator destination: when the Simulator is shut down externally, the retained xcodebuild's destination machinery silently reboots it and the device stays powered on until that runner dies (#3321). While a runner is warm-retained, hold one idle TCP connection to the runner's listener as a push signal. When an established watch connection closes during retention, read the device's boot identity once (bounded recheck, never a sample): a boot newer than the retention window proves Xcode rebooted the destination, so stop the retained runner — which powers the rebooted device back off — and record the typed `runner_destination_lost` reason the next `open` reports as a response warning. A same-boot close re-arms on the restarted generation; a never-established connection retries on a bounded backoff before being called `runner_unreachable`. Healthy warm reuse is untouched: killing a retained runner whose device was not rebooted leaves the device on (negative control), and the idle-stop policy still stands behind it. Mechanism evidence and per-claim measurements: PR body, issue #3321.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ined runner outright (#3321) Live runs showed three gaps: attach retries reset the window start, so a reboot looked older than the window; a shut-down device keeps its old launchd_sim listed for seconds, so the boot witness alone read a crash; and a graceful stop let the dying xcodebuild reboot the device again. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… and a verdict (#3321) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Size Report
Startup median (7 runs, lower is better):
|
There was a problem hiding this comment.
All reported issues were addressed across 13 files
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
…ment generations (#3321) Review round on #3357. Retention (idle stop, destination watch, retention fact) now enters through one retainRunnerForReuse and a failed ensureRunnerSession restores it, a re-attach that connects classifies the replacement generation, an unreadable device state counts as loss, the notice read waits for an in-flight decision on an open window, and a stale handler no longer deletes a newer watch. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ner and releases its lease (#3321) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
All reported issues were addressed across 7 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
…ouched it (#3321) A failed start that released a retained runner could re-arm retention over a runner a concurrent start was already using, because the restore keyed on session identity. Retention state changes now advance a per-device epoch and a restore is valid only at the epoch it released at. retainRunnerForReuse checks the session before it touches any retention state. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
All reported issues were addressed across 2 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
…eparately (#3321) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
I found one problem to fix in fbbf157, and the rest is minor. Checks are green: 21 checks, none failing. There are no conflicts. The new Not blocking, and you can take or leave these: in runner-destination-watch.ts, Could this be much smaller? If any loss of the retained runner's listener during retention (an established socket that closes, or a refused first attach) simply stopped the runner, the boot-identity classification, same-boot re-arm, replacement-generation retry loop, confirm/recheck/retry timers, their env vars and the On the open review threads, the cubic-dev-ai thread on runnerRetentionEpochs growth does not apply: the map grows by one integer per device, so it is bounded by device count, and reclaiming entries would reopen the restore race. You can resolve it. On evidence, the live 5/5 simulator runs appear only in the PR body and I saw no artifacts, and no live run is stated for the |
… that replaces rather than amends (#3321) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
4 issues found across 5 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/platform-apple/src/runner/runner-destination-watch.ts">
<violation number="1" location="packages/platform-apple/src/runner/runner-destination-watch.ts:113">
P3: These overrides can lengthen delays too: `readDurationEnvMs` accepts any finite non-negative value. Remove the shortening-only claim or cap overrides at their defaults.</violation>
<violation number="2" location="packages/platform-apple/src/runner/runner-destination-watch.ts:138">
P3: The doc says non-whole values fall back to the default, but `Math.floor` accepts fractional input and floors it. Either reject non-integers or fix the comment to say fractions are floored.</violation>
</file>
<file name="packages/platform-apple/src/core/simulator.ts">
<violation number="1" location="packages/platform-apple/src/core/simulator.ts:208">
P2: The doc comment says `null` means the listing is unreadable, but a timed-out `simctl` listing rejects instead. Document the throw here so callers do not assume `null`. Also note that the 2 s probe in runner-host.ts can fire on a healthy device, since this file's own comment cites ~0.7 s per spawn.</violation>
<violation number="2" location="packages/platform-apple/src/core/simulator.ts:209">
P3: This export creates a second `getSimulatorState` that duplicates the one in `src/simulator-state.ts`: same `simctl list devices -j` call, same null-on-failure, same parse. Consolidate on one implementation, or justify the second provider path in a comment, so the two cannot drift.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
|
Thanks for the review. State at Required change: done. Non-blocking, all taken:
Scope question, which needs a maintainer decision: keep the classification, or simplify to "any lost listener stops the runner"? What simplifying removes: boot-identity classification, same-boot re-arm, replacement-generation classification, confirm and recheck delays, and the Why I recommend keeping it, from the live runs:
If you prefer the smaller version: stop on any established close, keep the retry budget, drop the boot port and re-arm, and use one Evidence. The live runs are author-run, and I did not keep artifacts from the earlier ones. Here is a fresh run at Cycles 1 and 2 (6 s and 10 s gaps) end |
There was a problem hiding this comment.
All reported issues were addressed across 3 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
|
Follow-up to the probe thread: a state listing that times out or is unreadable ( |
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
Commit note for whoever reads history or squashes: |
…nd cause text (#3321) runner_unreachable meant both 'the runner stopped answering' and 'our own state probe could not be read'. The probe verdict is now runner_destination_unverified, and the open warning's cause text is a total map over the reasons. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
In 9c71e66 |
There was a problem hiding this comment.
All reported issues were addressed across 6 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
…3321) Comment-only; no behaviour change. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Summary
After
closeretains the iOS runner, an externalxcrun simctl shutdownmade the retainedxcodebuildreboot the simulator, which then stayed on for 20 s or more (#3321). Now the daemon:xcodebuildcannot reboot the device.runner_destination_lost,runner_unreachableorrunner_destination_unverified) as anopenwarning.Retention enters through one
retainRunnerForReuse; a failedensureRunnerSessionrestores it.This supersedes
fix/ios-warm-runner-reboot-3321, published without a PR and now deleted. Its reconnect-after-refusal classification, window-start carry and close-seam stop test are covered here.Closes #3321
Validation
Tested at
dd9c0ae57:pnpm check:affected --runexits 0.Live (iPhone 17, iOS 27.0, Xcode 27.1 beta): 7 of 7 runs with 6 to 14 s between
closeandsimctl shutdownleft the simulatorShutdownwith the runner gone within 1 s, and the nextopenwarned with the typed reason. Transcript: PR comment.Known residual: when the shutdown follows
closeby 3 s or less (4 of 4 runs), the open's runner prewarm starts a new runner and boots the device. That is the prewarm loop, tracked in #3359 and not fixed here.🤖 Generated with Claude Code