Repository navigation
fix(daemon): retain Apple runners for leases kept on close - #4195
Conversation
|
@muvaf is attempting to deploy a commit to the Callstack Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
1 issue found across 7 files
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/daemon/src/core/platform-resource-cleanup.ts">
<violation number="1" location="packages/daemon/src/core/platform-resource-cleanup.ts:19">
P3: `leaseWillEnd` is also `true` when lease inspection fails, yet the PR keeps that lease for recovery, so the name overstates what is known. Document the failure case on the field so callers do not read it as a confirmed lease end.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
| shutdownRequested: boolean; | ||
| hasScreenRecording: boolean; | ||
| hasLease: boolean; | ||
| leaseWillEnd: boolean; |
There was a problem hiding this comment.
P3: leaseWillEnd is also true when lease inspection fails, yet the PR keeps that lease for recovery, so the name overstates what is known. Document the failure case on the field so callers do not read it as a confirmed lease end.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. 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. At packages/daemon/src/core/platform-resource-cleanup.ts, line 19:
<comment>`leaseWillEnd` is also `true` when lease inspection fails, yet the PR keeps that lease for recovery, so the name overstates what is known. Document the failure case on the field so callers do not read it as a confirmed lease end.</comment>
<file context>
@@ -16,6 +16,6 @@ export type PlatformResourceCleanup = Readonly<{
shutdownRequested: boolean;
hasScreenRecording: boolean;
- hasLease: boolean;
+ leaseWillEnd: boolean;
}): boolean;
}>;
</file context>
| leaseWillEnd: boolean; | |
| /** True when the lease is not kept on close, or when its close decision could not be inspected. */ | |
| leaseWillEnd: boolean; |
|
At 6b3c132 a retained runner can outlive its lease, and the live lifecycle run is missing. There are no conflicts. Closing a local or proxy simulator session with retainOnClose retires the session but keeps its runner; release and expiry enumerate existing sessions, so they cannot stop that runner. The XCTest process and ownership can outlive the lease indefinitely when idle stop is disabled and another session keeps the daemon alive. Please preserve lease-to-host ownership after session retirement and have the shared release and expiry path stop retained hosts under device execution locks, reusing cleanupSessionlessExecutionHost and protecting replacement owners. Teardown Could you provide accessible commands and outputs tied to the head SHA, built daemon and simulator that show retainOnClose allocation, a served runner command, close with the lease present and session absent, reopening with the same runner generation, and release after another close stopping that generation while the daemon remains running? Please also show expiry cleanup, close --shutdown, graceful daemon shutdown after retained close, nonretained controls and final cleanup. The linked evidence was inaccessible, and the available summary does not establish cleanup at release. Runner path Could the existing lease-end owner enumerate retained execution hosts after preserving their lease association before session retirement, while keeping the existing Apple idle policy and cleanup port? One lower-priority inline thread still applies. Not blocking: You can take or leave updating the CLI help and session documentation to describe the retained-lease exception. The sole failing check is Vercel deployment authorization, corroborated by its bot comment and apparently unrelated to this daemon change. Before merge, fix release and expiry cleanup and provide accessible head-attributed lifecycle evidence; Vercel separately needs team deployment authorization. |
6b3c132 to
94a4db6
Compare
There was a problem hiding this comment.
3 issues found across 13 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/daemon/src/server/http/daemon-runtime.ts">
<violation number="1" location="packages/daemon/src/server/http/daemon-runtime.ts:305">
P2: `retryPending()` runs every second from the expiry sweep with no backoff or attempt cap. A retained host whose cleanup keeps failing will re-stop the runner under the device lock and log a warning each second. Throttle retries per lease, for example with a next-attempt timestamp or exponential delay.</violation>
</file>
<file name="src/commands/schema/cli-help.ts">
<violation number="1" location="src/commands/schema/cli-help.ts:483">
P2: `AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS=0` does not retain a lease-backed runner until daemon exit; releasing or expiring its `retainOnClose` lease still triggers lease-end cleanup. Clarify that `0` disables only idle stopping and that lease end takes precedence.</violation>
<violation number="2" location="src/commands/schema/cli-help.ts:483">
P2: Lease release or expiry does not always stop the retained runner: a replacement session can take over the same device first, and lease-end cleanup deliberately preserves that runner. Qualify this statement with “when no replacement session has taken it over” in the CLI help.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
| ); | ||
| const leaseExpirySweep = setInterval(() => { | ||
| leaseRegistry.consumeExpiredLeases(); | ||
| void leaseSessionEnd.retryPending(); |
There was a problem hiding this comment.
P2: retryPending() runs every second from the expiry sweep with no backoff or attempt cap. A retained host whose cleanup keeps failing will re-stop the runner under the device lock and log a warning each second. Throttle retries per lease, for example with a next-attempt timestamp or exponential delay.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. 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. At packages/daemon/src/server/http/daemon-runtime.ts, line 305:
<comment>`retryPending()` runs every second from the expiry sweep with no backoff or attempt cap. A retained host whose cleanup keeps failing will re-stop the runner under the device lock and log a warning each second. Throttle retries per lease, for example with a next-attempt timestamp or exponential delay.</comment>
<file context>
@@ -300,10 +300,10 @@ async function startDaemonRuntimeOnHost(
- );
+ const leaseExpirySweep = setInterval(() => {
+ leaseRegistry.consumeExpiredLeases();
+ void leaseSessionEnd.retryPending();
+ }, LEASE_EXPIRY_SWEEP_INTERVAL_MS);
leaseExpirySweep.unref();
</file context>
| open without --relaunch is idempotent-foreground for an already-running app, except native macOS app opens keep it in the background (help macos); neither restarts the process. open --relaunch restarts the app; on iOS simulators this collapses to one simctl launch --terminate-running-process call instead of a separate terminate-then-launch. | ||
| No runner read launches a session app that is not running: snapshot, wait, is, get, a reading find, and an interaction's leading reads (a gesture's viewport read, the capture that resolves a selector click/fill) answer the retriable APP_NOT_RUNNING instead of bare-launching over a launch SpringBoard still holds behind its deep-link confirmation. Only open, activate, and a command that mutates without a leading read bring a stopped app up. | ||
| close keeps a healthy iOS simulator XCTest runner warm by default so the next open on that simulator (same udid in the same simulator set) skips the runner build, unless --shutdown was requested, the session was recording, or the session held a device lease. A retained runner auto-stops after an idle window (default 5 minutes); set AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS to override, or 0 to disable idle stop and retain until daemon exit. Only a ready runner with an observed listener is retained; close retires unfinished prewarm recovery. Losing the retained listener stops that generation, and daemon shutdown stops idle retained runners rather than handing them off without supervision. | ||
| close keeps a healthy iOS simulator XCTest runner warm by default so the next open on that simulator (same udid in the same simulator set) skips the runner build, unless --shutdown was requested, the session was recording, or its device lease ends on close. A lease allocated with retainOnClose can keep the runner between sessions; releasing or expiring that lease stops the runner even after the session closes. A retained runner auto-stops after an idle window (default 5 minutes); set AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS to override, or 0 to disable idle stop and retain until daemon exit. Only a ready runner with an observed listener is retained; close retires unfinished prewarm recovery. Losing the retained listener stops that generation, and daemon shutdown stops idle retained runners rather than handing them off without supervision. |
There was a problem hiding this comment.
P2: AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS=0 does not retain a lease-backed runner until daemon exit; releasing or expiring its retainOnClose lease still triggers lease-end cleanup. Clarify that 0 disables only idle stopping and that lease end takes precedence.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. 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. At src/commands/schema/cli-help.ts, line 483:
<comment>`AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS=0` does not retain a lease-backed runner until daemon exit; releasing or expiring its `retainOnClose` lease still triggers lease-end cleanup. Clarify that `0` disables only idle stopping and that lease end takes precedence.</comment>
<file context>
@@ -480,7 +480,7 @@ Android physical-device prerequisites:
open without --relaunch is idempotent-foreground for an already-running app, except native macOS app opens keep it in the background (help macos); neither restarts the process. open --relaunch restarts the app; on iOS simulators this collapses to one simctl launch --terminate-running-process call instead of a separate terminate-then-launch.
No runner read launches a session app that is not running: snapshot, wait, is, get, a reading find, and an interaction's leading reads (a gesture's viewport read, the capture that resolves a selector click/fill) answer the retriable APP_NOT_RUNNING instead of bare-launching over a launch SpringBoard still holds behind its deep-link confirmation. Only open, activate, and a command that mutates without a leading read bring a stopped app up.
- close keeps a healthy iOS simulator XCTest runner warm by default so the next open on that simulator (same udid in the same simulator set) skips the runner build, unless --shutdown was requested, the session was recording, or the session held a device lease. A retained runner auto-stops after an idle window (default 5 minutes); set AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS to override, or 0 to disable idle stop and retain until daemon exit. Only a ready runner with an observed listener is retained; close retires unfinished prewarm recovery. Losing the retained listener stops that generation, and daemon shutdown stops idle retained runners rather than handing them off without supervision.
+ close keeps a healthy iOS simulator XCTest runner warm by default so the next open on that simulator (same udid in the same simulator set) skips the runner build, unless --shutdown was requested, the session was recording, or its device lease ends on close. A lease allocated with retainOnClose can keep the runner between sessions; releasing or expiring that lease stops the runner even after the session closes. A retained runner auto-stops after an idle window (default 5 minutes); set AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS to override, or 0 to disable idle stop and retain until daemon exit. Only a ready runner with an observed listener is retained; close retires unfinished prewarm recovery. Losing the retained listener stops that generation, and daemon shutdown stops idle retained runners rather than handing them off without supervision.
Each AGENT_DEVICE_STATE_DIR runs its own daemon. It self-exits after an idle window (default 5 minutes, matching the runner idle-stop default) once it has no open sessions, no in-flight requests, and no active recording; set AGENT_DEVICE_DAEMON_IDLE_TIMEOUT_MS to override, or 0 to disable idle reap.
A client starting a local daemon waits while the daemon process stays alive and keeps publishing startup progress, so an overloaded host makes startup slower, not failed. It stops at a ceiling (default 120 s; set AGENT_DEVICE_DAEMON_STARTUP_TIMEOUT_MS to a positive integer number of milliseconds to override) and names the outcome in error details.reason: startup-exited (the process ended before registering), startup-stalled (alive, no startup progress for a fixed 60 s window the ceiling variable does not change), or startup-ceiling (a startup was still live when the ceiling passed — this client's daemon or another client's; the client stops its own launch and never signals another client's live daemon. Only a progressing own launch outlasts the 60 s stall window, so a ceiling set below 60 s also ends a silent own launch this way). details.phases carries the startup phase timings it observed and details.startupTimeoutMs the effective ceiling. Branch on details.reason, never on the message. The variable is read only when a client must start a daemon: a value that is not a positive integer fails with INVALID_ARGS before the daemon spawns, and a client that only attaches to or reuses a running daemon never reads it.
</file context>
| open without --relaunch is idempotent-foreground for an already-running app, except native macOS app opens keep it in the background (help macos); neither restarts the process. open --relaunch restarts the app; on iOS simulators this collapses to one simctl launch --terminate-running-process call instead of a separate terminate-then-launch. | ||
| No runner read launches a session app that is not running: snapshot, wait, is, get, a reading find, and an interaction's leading reads (a gesture's viewport read, the capture that resolves a selector click/fill) answer the retriable APP_NOT_RUNNING instead of bare-launching over a launch SpringBoard still holds behind its deep-link confirmation. Only open, activate, and a command that mutates without a leading read bring a stopped app up. | ||
| close keeps a healthy iOS simulator XCTest runner warm by default so the next open on that simulator (same udid in the same simulator set) skips the runner build, unless --shutdown was requested, the session was recording, or the session held a device lease. A retained runner auto-stops after an idle window (default 5 minutes); set AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS to override, or 0 to disable idle stop and retain until daemon exit. Only a ready runner with an observed listener is retained; close retires unfinished prewarm recovery. Losing the retained listener stops that generation, and daemon shutdown stops idle retained runners rather than handing them off without supervision. | ||
| close keeps a healthy iOS simulator XCTest runner warm by default so the next open on that simulator (same udid in the same simulator set) skips the runner build, unless --shutdown was requested, the session was recording, or its device lease ends on close. A lease allocated with retainOnClose can keep the runner between sessions; releasing or expiring that lease stops the runner even after the session closes. A retained runner auto-stops after an idle window (default 5 minutes); set AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS to override, or 0 to disable idle stop and retain until daemon exit. Only a ready runner with an observed listener is retained; close retires unfinished prewarm recovery. Losing the retained listener stops that generation, and daemon shutdown stops idle retained runners rather than handing them off without supervision. |
There was a problem hiding this comment.
P2: Lease release or expiry does not always stop the retained runner: a replacement session can take over the same device first, and lease-end cleanup deliberately preserves that runner. Qualify this statement with “when no replacement session has taken it over” in the CLI help.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. 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. At src/commands/schema/cli-help.ts, line 483:
<comment>Lease release or expiry does not always stop the retained runner: a replacement session can take over the same device first, and lease-end cleanup deliberately preserves that runner. Qualify this statement with “when no replacement session has taken it over” in the CLI help.</comment>
<file context>
@@ -480,7 +480,7 @@ Android physical-device prerequisites:
open without --relaunch is idempotent-foreground for an already-running app, except native macOS app opens keep it in the background (help macos); neither restarts the process. open --relaunch restarts the app; on iOS simulators this collapses to one simctl launch --terminate-running-process call instead of a separate terminate-then-launch.
No runner read launches a session app that is not running: snapshot, wait, is, get, a reading find, and an interaction's leading reads (a gesture's viewport read, the capture that resolves a selector click/fill) answer the retriable APP_NOT_RUNNING instead of bare-launching over a launch SpringBoard still holds behind its deep-link confirmation. Only open, activate, and a command that mutates without a leading read bring a stopped app up.
- close keeps a healthy iOS simulator XCTest runner warm by default so the next open on that simulator (same udid in the same simulator set) skips the runner build, unless --shutdown was requested, the session was recording, or the session held a device lease. A retained runner auto-stops after an idle window (default 5 minutes); set AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS to override, or 0 to disable idle stop and retain until daemon exit. Only a ready runner with an observed listener is retained; close retires unfinished prewarm recovery. Losing the retained listener stops that generation, and daemon shutdown stops idle retained runners rather than handing them off without supervision.
+ close keeps a healthy iOS simulator XCTest runner warm by default so the next open on that simulator (same udid in the same simulator set) skips the runner build, unless --shutdown was requested, the session was recording, or its device lease ends on close. A lease allocated with retainOnClose can keep the runner between sessions; releasing or expiring that lease stops the runner even after the session closes. A retained runner auto-stops after an idle window (default 5 minutes); set AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS to override, or 0 to disable idle stop and retain until daemon exit. Only a ready runner with an observed listener is retained; close retires unfinished prewarm recovery. Losing the retained listener stops that generation, and daemon shutdown stops idle retained runners rather than handing them off without supervision.
Each AGENT_DEVICE_STATE_DIR runs its own daemon. It self-exits after an idle window (default 5 minutes, matching the runner idle-stop default) once it has no open sessions, no in-flight requests, and no active recording; set AGENT_DEVICE_DAEMON_IDLE_TIMEOUT_MS to override, or 0 to disable idle reap.
A client starting a local daemon waits while the daemon process stays alive and keeps publishing startup progress, so an overloaded host makes startup slower, not failed. It stops at a ceiling (default 120 s; set AGENT_DEVICE_DAEMON_STARTUP_TIMEOUT_MS to a positive integer number of milliseconds to override) and names the outcome in error details.reason: startup-exited (the process ended before registering), startup-stalled (alive, no startup progress for a fixed 60 s window the ceiling variable does not change), or startup-ceiling (a startup was still live when the ceiling passed — this client's daemon or another client's; the client stops its own launch and never signals another client's live daemon. Only a progressing own launch outlasts the 60 s stall window, so a ceiling set below 60 s also ends a silent own launch this way). details.phases carries the startup phase timings it observed and details.startupTimeoutMs the effective ceiling. Branch on details.reason, never on the message. The variable is read only when a client must start a daemon: a value that is not a positive integer fails with INVALID_ARGS before the daemon spawns, and a client that only attaches to or reuses a running daemon never reads it.
</file context>
94a4db6 to
db876b9
Compare
There was a problem hiding this comment.
1 issue found across 4 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="src/commands/schema/cli-help.ts">
<violation number="1" location="src/commands/schema/cli-help.ts:483">
P2: These lines promise retained-runner cleanup on an unqualified daemon shutdown, but cleanup only runs during graceful shutdown. Say `graceful daemon shutdown` in this help text and `client-api.md` so users do not assume cleanup after a crash or forced kill.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
| open without --relaunch is idempotent-foreground for an already-running app, except native macOS app opens keep it in the background (help macos); neither restarts the process. open --relaunch restarts the app; on iOS simulators this collapses to one simctl launch --terminate-running-process call instead of a separate terminate-then-launch. | ||
| No runner read launches a session app that is not running: snapshot, wait, is, get, a reading find, and an interaction's leading reads (a gesture's viewport read, the capture that resolves a selector click/fill) answer the retriable APP_NOT_RUNNING instead of bare-launching over a launch SpringBoard still holds behind its deep-link confirmation. Only open, activate, and a command that mutates without a leading read bring a stopped app up. | ||
| close keeps a healthy iOS simulator XCTest runner warm by default so the next open on that simulator (same udid in the same simulator set) skips the runner build, unless --shutdown was requested, the session was recording, or the session held a device lease. A retained runner auto-stops after an idle window (default 5 minutes); set AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS to override, or 0 to disable idle stop and retain until daemon exit. Only a ready runner with an observed listener is retained; close retires unfinished prewarm recovery. Losing the retained listener stops that generation, and daemon shutdown stops idle retained runners rather than handing them off without supervision. | ||
| close keeps a healthy iOS simulator XCTest runner warm by default so the next open on that simulator (same udid in the same simulator set) skips the runner build, unless --shutdown was requested, the session was recording, or its device lease ends on close. A lease allocated with retainOnClose can keep the runner between sessions; releasing or expiring that lease stops its runner unless a session outside the lease has taken over the device. A retained runner auto-stops after an idle window (default 5 minutes); set AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS to override, or 0 to disable idle stopping. Lease release, expiry, and daemon shutdown still clean up runners they own. Only a ready runner with an observed listener is retained; close retires unfinished prewarm recovery. Losing the retained listener stops that generation, and daemon shutdown stops idle retained runners rather than handing them off without supervision. |
There was a problem hiding this comment.
P2: These lines promise retained-runner cleanup on an unqualified daemon shutdown, but cleanup only runs during graceful shutdown. Say graceful daemon shutdown in this help text and client-api.md so users do not assume cleanup after a crash or forced kill.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. 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. At src/commands/schema/cli-help.ts, line 483:
<comment>These lines promise retained-runner cleanup on an unqualified daemon shutdown, but cleanup only runs during graceful shutdown. Say `graceful daemon shutdown` in this help text and `client-api.md` so users do not assume cleanup after a crash or forced kill.</comment>
<file context>
@@ -480,7 +480,7 @@ Android physical-device prerequisites:
open without --relaunch is idempotent-foreground for an already-running app, except native macOS app opens keep it in the background (help macos); neither restarts the process. open --relaunch restarts the app; on iOS simulators this collapses to one simctl launch --terminate-running-process call instead of a separate terminate-then-launch.
No runner read launches a session app that is not running: snapshot, wait, is, get, a reading find, and an interaction's leading reads (a gesture's viewport read, the capture that resolves a selector click/fill) answer the retriable APP_NOT_RUNNING instead of bare-launching over a launch SpringBoard still holds behind its deep-link confirmation. Only open, activate, and a command that mutates without a leading read bring a stopped app up.
- close keeps a healthy iOS simulator XCTest runner warm by default so the next open on that simulator (same udid in the same simulator set) skips the runner build, unless --shutdown was requested, the session was recording, or its device lease ends on close. A lease allocated with retainOnClose can keep the runner between sessions; releasing or expiring that lease stops the runner even after the session closes. A retained runner auto-stops after an idle window (default 5 minutes); set AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS to override, or 0 to disable idle stop and retain until daemon exit. Only a ready runner with an observed listener is retained; close retires unfinished prewarm recovery. Losing the retained listener stops that generation, and daemon shutdown stops idle retained runners rather than handing them off without supervision.
+ close keeps a healthy iOS simulator XCTest runner warm by default so the next open on that simulator (same udid in the same simulator set) skips the runner build, unless --shutdown was requested, the session was recording, or its device lease ends on close. A lease allocated with retainOnClose can keep the runner between sessions; releasing or expiring that lease stops its runner unless a session outside the lease has taken over the device. A retained runner auto-stops after an idle window (default 5 minutes); set AGENT_DEVICE_IOS_RUNNER_IDLE_STOP_MS to override, or 0 to disable idle stopping. Lease release, expiry, and daemon shutdown still clean up runners they own. Only a ready runner with an observed listener is retained; close retires unfinished prewarm recovery. Losing the retained listener stops that generation, and daemon shutdown stops idle retained runners rather than handing them off without supervision.
Each AGENT_DEVICE_STATE_DIR runs its own daemon. It self-exits after an idle window (default 5 minutes, matching the runner idle-stop default) once it has no open sessions, no in-flight requests, and no active recording; set AGENT_DEVICE_DAEMON_IDLE_TIMEOUT_MS to override, or 0 to disable idle reap.
A client starting a local daemon waits while the daemon process stays alive and keeps publishing startup progress, so an overloaded host makes startup slower, not failed. It stops at a ceiling (default 120 s; set AGENT_DEVICE_DAEMON_STARTUP_TIMEOUT_MS to a positive integer number of milliseconds to override) and names the outcome in error details.reason: startup-exited (the process ended before registering), startup-stalled (alive, no startup progress for a fixed 60 s window the ceiling variable does not change), or startup-ceiling (a startup was still live when the ceiling passed — this client's daemon or another client's; the client stops its own launch and never signals another client's live daemon. Only a progressing own launch outlasts the 60 s stall window, so a ceiling set below 60 s also ends a silent own launch this way). details.phases carries the startup phase timings it observed and details.startupTimeoutMs the effective ceiling. Branch on details.reason, never on the message. The variable is read only when a client must start a daemon: a value that is not a positive integer fails with INVALID_ARGS before the daemon spawns, and a client that only attaches to or reuses a running daemon never reads it.
</file context>
|
At db876b9 the lease-release cleanup is fixed: failed inspection, retry deadlines, idle stopping and replacement ownership are all handled, and I found no new code issues. One open thread on the graceful cleanup wording still applies. The other threads from the last round are fixed and can be resolved. Your evidence artifacts cover the local SDK, daemon and XCTest validation. Coverage now passes; the only failing check is the Vercel deploy, which needs team authorization for this fork. There are no conflicts. |
db876b9 to
ea3dbea
Compare
|
The code looks good at ea3dbea. The reworded help now says graceful shutdown stops retained runners, which settles the last open shutdown wording thread; the retry, idle-stop and replacement-session threads no longer apply either. Your live lifecycle evidence is linked in the PR body. All other checks pass; the only failing check is the Vercel deploy, which needs team authorization for this fork. There are no conflicts. |
Summary
Keep a healthy iOS simulator runner when its client-owned lease survives session close. Preserve ownership after session retirement so release and expiry stop the runner; retry failed cleanup and protect replacement sessions. Docs now specify graceful daemon shutdown.
Sixteen files; lifecycle fix requested in #4174. Allocate with
retainOnClose: true;closeends the session, andleases.release()ends the retained lease and runner.Related work
Independent siblings: Android installer #4194, recordings #4196. Apple hooks follow #4194; native Limrun XCTest follows all layers to replace AX.
Validation
Base
a2c169fa502a53f1f2a1da25b1cd16b9c731af39; tested headea3dbea24f2f71f631226c0ced937f7ab37cb505.pnpm check:affected --run --base <base> --head <head>passed (exactCommit:true): 17,152 unit tests, one skipped; 304 focused tests. Independent delta review passed. This round changes wording only.Simulator evidence remains attributed to
db876b9(identical runtime): 45 successful SDK calls covering served XCTest commands, retained reuse, release, expiry, shutdown and nonretained controls. Cleanup/race regressions fail without their fixes.Physical-device comparison and current receipts: iPhone 14 Pro, iOS 27.0.1. Stock replay fails on both base/head at step 3 because General is off-screen; a temporary copy adding scrolling/waits passes on both. All test sessions and daemons cleaned up; no device claims remain. Stock lane remains a recorded limitation.
GitHub owns coverage/provider/device checks skipped locally. Vercel requires maintainer authorization.
Open in [code]smith · Need help on this PR? Tag
@codesmith-botwith what you need.