Repository navigation
wait: a runner restart inside the wait is reported as a capture stall, and outlives the whole budget #2103
Description
A wait that spans a runner restart reports a capture stall, and the restart alone outlives the wait's whole budget. Traced from an iOS smoke failure on an unrelated PR (run 33098577026, #2059, which changes only a dispatch-only workflow and a script it calls).
What the user sees
agent-device wait text "Agent Device Tester" 10000 --platform ios …
COMMAND_FAILED: wait timed out for text: Agent Device Tester
hint: No readable snapshot capture completed before the wait timeout.
Retry, or use screenshot to inspect the current surface.
The hint points at the surface. The surface was fine.
What actually happened
From the request log (sessions/ios-e2e-smoke-nau/requests/fc627b1104c2bcc2.ndjson):
17:45:01.969 ios_runner_readiness_preflight findText
17:45:07.124 ios_runner_readiness_preflight snapshot durationMs=1029 [error]
17:45:07.124 ios_runner_session_invalidated
17:45:10.605 ios_runner_startup_ensure_booted
17:45:16.872 ios_runner_startup_cleanup_stale_bundles durationMs=6267
17:45:18.975 ios_runner_startup_ensure_xctestrun durationMs=2102
17:45:19.075 ios_runner_startup_launch_xcodebuild
17:45:20.259 retry attempt_failed (1/3)
17:45:20.261 retry exhausted (3/3)
17:45:20.262 snapshot_capture durationMs=14333 backend=xctest error="request canceled"
17:45:20.274 request_failed wait timed out for text
A preflight snapshot failed, the runner session was invalidated, and the runner restarted inside the wait. The restart alone spent ~12 s — 6.3 s of it in cleanup_stale_bundles — against a 10 s wait budget. The capture was then canceled, and the failure was reported as if nothing readable had appeared on screen.
Two separable problems
- The wait budget does not account for a restart it did not ask for. A 10 s wait cannot survive a ~12 s runner restart, so any invalidation inside a default-length wait is a guaranteed failure regardless of the app's state. Either the restart should not be charged to the caller's budget, or the wait should extend across it.
- The error names the wrong thing.
wait_capture_stalledand "no readable snapshot capture completed" send the reader to the app and the screen. The daemon log hasios_runner_session_invalidatedand a full restart sequence; that is what should surface. AGENTS.md already says a five-second-plus interaction is a daemon-log question naming exactly these phases — the error should carry that rather than making each reader rediscover it.
Fixing (2) alone would make this class self-diagnosing even if (1) stays as designed.
Frequency
Twice in one working session on unrelated PRs, both during scenario bootstrap: this one, and an Android wait timed out for text: Automation lab with the same wait_capture_stalled hint (run 32977635983). The Android instance was not traced, so I am not claiming the same mechanism — only the same reported symptom, which is part of the point of (2).
Generated by Claude Code
Activity
thymikee commentedon Aug 27, 2026
Triaged as a valid, AFK-ready bug. Keep the caller-supplied wait deadline hard; a runner restart must not silently grant an unbounded second budget. Fix the diagnostic boundary first: preserve a typed runner-invalidation/restart cause through capture normalization so the wait failure distinguishes restart exhaustion from a genuinely unreadable surface and retains diagnosticId/logPath. Add a planted regression where readiness invalidates inside a short wait, proving bounded cancellation and the typed restart hint. Treat the Android occurrence as unconfirmed sibling evidence until separately traced.