Repository navigation
fix(apple): recover runner snapshot bridge after a wedge or restart - #4256
Conversation
Size Report
Startup median (7 runs, lower is better):
|
There was a problem hiding this comment.
All reported issues were addressed across 10 files
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
Apex SentinelVerdict: Since the last review: 0 new · 0 still open · 2 no longer raised No findings. 2 findings below Reviewed with this repository's own Sentinel configuration ( Reply under an inline comment with Earlier reviewsReview of
|
| Where | Finding |
|---|---|
packages/platform-apple/src/snapshot-route.ts:208 |
🆕 sessionDisabled disables the bridge route forever when no probe names a session |
packages/platform-apple/src/snapshot-route.ts:208 |
🆕 Only a channel that passes sessionChanged can ever clear sessionDisabled, so a local-route wedge is permanent |
3 findings below minor not shown (user_settings.min_severity).
Reviewed with this repository's own Sentinel configuration (0a1d37cb5359).
Review of e25fef03 · 06.11.2026 07:46 UTC
Apex Sentinel
Verdict: request_changes
Since the last review: 2 new · 0 still open · 1 no longer raised
2 finding(s): 1 major, 1 minor.
Required fixes
- A bridge-reader-wedged refusal on the describe path never retires the runner session
🟠 Major (1)
| Where | Finding |
|---|---|
packages/platform-apple/src/runner-snapshot-bridge.test.ts:514 |
🆕 A bridge-reader-wedged refusal on the describe path never retires the runner session |
🟡 Minor (1)
| Where | Finding |
|---|---|
packages/platform-apple/src/snapshot-route.ts:202 |
🆕 circuitForProbe silently drops wedge evidence when the probe names a third runner session |
Reviewed with this repository's own Sentinel configuration (90c959518e46).
Review of 4e78ccc1 · 06.11.2026 05:21 UTC
Apex Sentinel
Verdict: approve
1 finding(s): 1 minor.
🟡 Minor (1)
| Where | Finding |
|---|---|
packages/platform-apple/src/snapshot-route.ts:248 |
Post-wedge captures warn with the app-generation sentence, not the runner-session one |
1 finding below minor not shown (user_settings.min_severity).
Reviewed with this repository's own Sentinel configuration (b42c7c265f07).
There was a problem hiding this comment.
Apex Sentinel: 1 new finding on 4e78ccc. The verdict and the full list are in the summary comment.
|
The change reads sound at 4e78ccc, but the new runner recovery path has no live or native run, so I can't confirm it works. All 17 checks pass at this commit, but hosted CI does not run the native wedge path or a remote runner restart. Before merge, please add the evidence below and fix the two open warning and write-guard threads. The central transition runs nowhere: a held read goes abandoned, then Could the circuit be one object per runner session instead? The route core would hold Not blocking, take or leave: a runner-session disablement should belong to the session it was seen under, so runner-runtime.ts#L78 should clear it when the probe reads a different id, even if no id was recorded at the wedge (I could not confirm the remote path reaches this state); the permanent retirement at snapshot-route.ts#L245 could be confirmed in the ADR or bounded so one capture per interval retries the bridge; On the open inline threads: the warning-scope thread (#4256 (comment)) and the unguarded presentation-failure write (#4256 (comment)) still apply. Five lower-priority threads still apply too. The launch-observation thread (#4256 (comment)) does not apply: that probe exists only in the local AX route, whose reader never emits One open question: do you know how often a slow but finite read on a remote Simulator crosses the 5 s bound? |
|
Native evidence for The exact-head affected gate passed ( |
|
Live Limrun iOS run at e25fef0 ( No real trigger retires a remote generation on demand, so the run used two local, uncommitted changes to the built JS, which were removed afterwards with
The app generation did not change, so the new runner session alone reopened the bridge. Before this PR, the generation stayed retired. Two side observations:
|
There was a problem hiding this comment.
Apex Sentinel: 2 new findings on e25fef0. The verdict and the full list are in the summary comment.
Both branches repeated the same guard prefix. Read the probed session id once, compare it with the starting and current circuits, and document that a capture writes through the circuit object itself, never a copy.
There was a problem hiding this comment.
Apex Sentinel: 2 new findings on 6dcfd3f. The verdict and the full list are in the summary comment.
…cuit names it Only a probe that names a different runner session replaces a circuit, so a runner-session refusal on a circuit with no session id disabled the bridge for good. Such a refusal now speaks for its capture only.
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
…o retire A runner-session refusal on a circuit with no session id now reports a capture-scoped bridge-read-busy disposition, so its warning no longer claims a runner-session retirement that did not happen.
|
This PR is ready at b9a16c4. The findings from the earlier review (#4256 (comment)) are fixed. CI shows 17 checks, none failing, and there are no conflicts. Nothing else needs to happen before merge. Your live Limrun run was at e25fef0; the change since then is behavior-equivalent on that route, so it still covers it. A real Not blocking, take or leave: (1) |
- SystemSurfaceForegroundProbe always returns { foreground, sessionId? }, so the
snapshot route drops its three narrowings.
- Test fakes without a runner session answer 'unknown', as the real probe does.
- The native wedge test holds a read after the admitted one and checks it at a
time far past the old abandon stamp, so it fails if the stamp is not cleared.
- The lease handler uses errorMessage() for the teardown diagnostic.
Follow-up to #4256 and #4257.
…4272) * fix(apple): keep runner bridge test hooks out of the shipped package #4256 put RunnerSnapshotBridgeReadForTest and RunnerSnapshotBridgeDrainForTest under an #if AGENT_DEVICE_RUNNER_UNIT_TESTS block in the shipped RunnerSnapshotBridge.m. The packager strips that block only from Swift, so the macro survived packaging and check-package failed the Release Build job. Move the hooks to UnitTests/RunnerSnapshotBridgeTesting.m, which the package omits, and reach the read and the reader queue through a private UnitTests/RunnerSnapshotBridge+Internal.h. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(apple): mark the runner bridge read's nil-able result nullable Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Summary
Retire a runner's snapshot bridge when an abandoned reader remains blocked for five seconds. Each runner session owns its circuit and target cache, so a replacement retries the bridge and late failures cannot retire the replacement's generations. Session-scoped refusals retain their scope in warnings and diagnostics. Fixes #4241.
15 files changed across the runner bridge, routing, tests, refusal fixture, and ADR.
Validation
Base:
b42c7c265f0765045b1ce5c53dd426512e11108d. Head:e25fef03950b54543ca29a71fbfaede8f4586cd4.4e78ccc; the updated focused suites pass at this head (84 tests).pnpm check:affected --run --head e25fef03950b54543ca29a71fbfaede8f4586cd4passed:run-pvhLTv,exactCommit=true,checkoutChanged=false. Coverage and native/device lanes remain GitHub-owned or skipped; provider integration was deduplicated against related tests.Live evidence: on Limrun iOS at e25fef0, a real
bridge-read-abandonedrefusal (triggered by a 1 ms budget) retired the generation. After the runner was replaced throughstopIosRunnerSession, the route logged the session change and servedsimulator-ax-bridgefor the same app generation with no warning. The PR comment has the details. No data shows finite remote reads crossing 5 s: no Limrun run has returned an abandoned, deadline, or wedged refusal without fault injection.