fix(ios): pay for one toolchain in the snapshot bridge identity read (#2712) - #2765
Conversation
The identity read probed `xcodebuild -version` and then `xcrun --sdk iphonesimulator --show-sdk-version` — two Xcode-owned binaries, each a tool the host can stall on before it answers. On CI the `xcrun` probe lost twice at the shared 30 s ceiling and took the whole iOS smoke job down over a cache-key field (60.9 s of a 120 s budget, job 106068926059). The Simulator SDK ships inside the selected `Xcode.app`, so the version and build `xcodebuild -version` already reports pin it: the field left the cache key and the exec left the identity read. The `xcrun clang` the build runs pays that wait once, under the build's own ceiling, where a stall of that length fits instead of exhausting the budget. A probe or compile that cannot answer now says so at the seam that waited: `timeout` with `toolchain-probe-stalled` or `native-build-stalled`, the command, the budget each attempt was armed with, and the exec layer's kill kept as the cause. Before, a job got a bare `xcrun timed out after 30000ms` stack that reads exactly like a device failure. Cache entries written before this hash to a different key, so they rebuild once instead of being misread; no schema bump is needed to prove that. Closes #2712
Size Report
Startup median (7 runs, lower is better):
|
|
Reviewed at 6f458ca: the code looks good. Dropping the Simulator SDK version from the cache key is sound, because the selected Xcode version and build already pin that SDK, and old manifests cannot match the new key. The retry, deadline and cancellation behavior is unchanged, and a cancel cannot turn into One small note, not blocking: the compile-stall test builds the timeout error by hand instead of through I did not see the output of the reported host run. A cold Two Smoke Tests jobs are still running. The iOS one runs the snapshot bridge preparation step that this PR changes, so it should finish green before merge. |
Both stall fixtures built the timeout error by hand, so a probe could keep classifying a kill `exec.ts` no longer reports as one. They now run a command the exec layer really kills and carry whatever error it raises; the probe assertions still read the shape through `isCommandTimeoutError` rather than a message. Review note on #2765.
|
Thanks — fixed at
Host run output added to the Validation section. Noted that a cold stall cannot be summoned: the attribution's proof is the next cold host, and it should now read Smoke Tests: all green on |
|
CI on |
|
4b1cc67 looks good. The delta since 6f458ca is test-only: the fixture now takes its timeout error from the real exec.ts kill path instead of a synthetic one, so the snapshot bridge identity timeout test exercises the same failure the runner produces. No production code changed, and I found nothing left to fix. CI is green on all 18 checks, including the smoke-test job that runs |
|
Summary
verify-installed-snapshot-bridgedied onxcrun --sdk iphonesimulator --show-sdk-version, twice at the 30 s probe ceiling, and a cache-key field took the iOS smoke job down.Triage disagreed with the reported cause. That script ran
11:15:44.964 → 11:16:45.862(60.9 s) against a 120 s deadline, and the identity read runs before the cache lock, soremainingMscannot reach 0 and the retry cannot have been skipped. The only reading that fits is two 30 s attempts onxcrun: the retry fired and stalled too — #2422's retry only recovers a stall that finished while the killed exec was going away.The fix is at
SnapshotSourceToolchainIdentity. The Simulator SDK ships inside the selectedXcode.app, so the version and buildxcodebuild -versionreports already pin it: the field left the key and the exec left the identity read.xcrun clangin the build pays that wait once, under the build's own ceiling, where it fits instead of exhausting the budget. A stall now reportstoolchain-probe-stalled/native-build-stalledwith the command, each attempt's budget and the exec kill as cause, instead of an unattributedxcrun timed out after 30000msthat reads like a device failure. 6 files.Cache keys change, so existing entries rebuild once; old manifests hash differently and cannot be misread, so no schema bump. Untouched: the sibling runner prober's policy, and the generation circuit a preparation stall still opens.
Validation
4b1cc67ff:pnpm check:affected --run(all runnable gates, 1712 tests),check:fallow,check:layering,check:bundle-owner-files, build, lint, typecheck clean. Six tests fail with the two source files reverted to the merge-base.Host run the review asked for (macOS 27.0, Xcode 27.0): prepared from source, exit 0 in 1.9 s, second run reused the entry.
A cold stall cannot be reproduced on demand; the attribution's real proof is the next cold CI host.
ios.ymlfilters on this directory, so this PR runs the job it fixes.