fix(limrun): start the iOS runner under the hosts' Xcode 27

Merged
TH
1d ago
+62-37

Summary

Limrun hosts now run XCTest with Xcode 27. A runner built with Xcode 26 embeds XCTest 26, and its test host crashes at startup there. This PR:

  • builds the release runner with Xcode 27. release-ios-runner.yml picks the newest Xcode whose xcodebuild -version reports 27.x, and fails with a clear error if the image has none. Blacksmith macOS 26 images ship Xcode 27 beside the default 26.
  • adds TestingEnvironmentVariables DYLD_FRAMEWORK_PATH/DYLD_LIBRARY_PATH → __PLATFORMS__/iPhoneSimulator.platform/... to the Runner.xctestrun we write, so the host's Xcode resolves the runner's @rpath/XCTest.framework.
  • inverts the products and packaging checks: a runner that embeds XCTest.framework is refused (limrun_runner_products_invalid) instead of crashing after about 3 minutes. The lib_TestingInterop/_Testing_* copies are gone, because an Xcode 27.1 build embeds no Testing frameworks.
  • updates website/docs/docs/limrun.md.
  • also fixes a CI flake in lifecycle.test.ts: its 120 ms budget also had to cover real host setup. It now runs on virtual time. With a 150 ms setup, the base version fails with the same assertion as CI and the new one passes.

8 files. Fixes #4301.

Validation

Rebased head 0bdc0f4a66: pnpm check:affected --run --head 0bdc0f4a66 passed, exactCommit=true.

Live runs used the source CLI with an Xcode 27.1 (27A9275) runner packaged by scripts/package-ios-simulator-runner.sh and set through AGENT_DEVICE_LIMRUN_IOS_RUNNER_APP. Commands: open com.apple.Preferences, snapshot -i, click 'label="General"', snapshot -i.

Instanceopensnapshot -iclicksnapshot -i
default (iOS 26 default; iOS 26 Settings layout)ok 4 sok 11 s, 18 nodes (includes runner start)ok 1 sok, [navigation-bar] "General"
OSVersion: 27, attached via LIM_IOS_INSTANCE_*ok 3 sok 11 s, 19 nodes (iOS 27 sidebar)ok 2 sok, General pane

The same runs also passed earlier at 3ca49cb27a. Base evidence is in #4301: main refuses this runner, and the 0.21.36 runner crashes. Every instance was released.

Android smoke failed on earlier heads (Home pixels, keyboard dismissal, back→diff). The failure screenshot shows back did navigate, so this is a settle race in that suite, not this change. The release workflow is first exercised by the next release-ios-runner run.

🤖 Generated with Claude Code