Skip to content

fix(ios): pin simulator runtime to 27.2 and match the runtime id exactly - #592

Merged
patrickserrano merged 1 commit into
mainfrom
fix/runtime-pin-27-2
Oct 24, 2026
Merged

patrickserrano merged 1 commit into
mainfrom
fix/runtime-pin-27-2

Conversation

@patrickserrano

@patrickserrano patrickserrano commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

Summary

The runner host's iOS 27.0 simulator runtime is listed as Ready but unusable: simctl create on it fails with SimError 401, "runtime path not found". The 27.2 runtime creates fine. This moves the fleet pin (and the watch runtime that follows it) to 27.2, and fixes the presence check and fallback in Setup Simulator, which had a prefix trap now that Xcode 27.2 installs a device-specific runtime (…iOS-27-2-iPhone19-4).

Evidence (before the fix, origin/main, real simctl list runtimes on a host with Xcode 27.2)

  • Rendered: PINNED_RUNTIME="com.apple.CoreSimulator.SimRuntime.iOS-27-0"; watch runtime …watchOS-27-0.
  • Control: creating a device on the 27.0 runtime → SimError, code=401 … runtime path not found. On 27.2 it creates.
  • Presence check with the pin at iOS-27-2: the old grep -q "$PINNED_RUNTIME" passes, and iOS-27-2 is a substring of the …iOS-27-2-iPhone19-4 line, so a fixture list containing ONLY the device-specific runtime also passes (it should fall back).
  • Fallback: grep -oE '…SimRuntime\.iOS[0-9-]*' on the device-specific line extracts com.apple.CoreSimulator.SimRuntime.iOS-27-2-, which is not a runtime. sort -V | tail -1 ranks it above the real iOS-27-2, so on the real list a fallback selects it. A fixture with only the device-specific line "falls back" to the same non-existent id.

Change

  • DefaultRuntimePin 27.0 → 27.2.
  • Presence check matches the last field of each simctl line as a whole (awk '{print $NF}' | grep -qxF). Fallback considers only iOS-<major>-<minor> ids; || true keeps the "no runtimes installed" error reachable under pipefail.
  • Existing expectations moved 27.0 → 27.2 (ios_ci_products, sim_runtime, sim_runtime_override, watch_test_job, and TestSimulatorRuntimeRelaxOnThePinIsDead, whose "override on the pin" value is the pin). No assertion was loosened, skipped or widened. Fixture text that merely mentions 27.0 (simctl device listings, SDK stubs, measurement comments) is unchanged.
  • New internal/shipped/sim_runtime_exact_test.go runs the rendered step (bash -eo pipefail) against simctl-format fixtures: only the device-specific runtime plus an older plain one → warns and selects the older plain one, never the device-specific or truncated id; only the device-specific one → the no-runtime error; plain pin beside the device-specific one → passes with no fallback.

Tests

  • New test FAILS on origin/main's template (4 assertions: no fallback warning, wrong selection, device-specific id accepted, no error), passes after.
  • Mutations: restoring the substring grep -q → TestPinnedRuntimeIsMatchedExactlyNotAsAPrefix fails; restoring the old grep -oE fallback pattern → the same test fails; restored file passes.
  • go test ./... run once: the only failures are ones that also fail on a clean origin/main checkout in this environment (doctor package: fragment/typedoc/lint-config; TestNewProjectsAlwaysWork), plus a gh api alarm timeout in TestReleaseRefusesARedIOSPushRunWithoutDispatching under load that passes on rerun. The one failure caused by this change (TestSimulatorRuntimeRelaxOnThePinIsDead) is fixed above.
  • Public-names test passes against the denylist.

Proven on

Proven after merge (v1.79.5), 2026-10-24: a downstream project synced to v1.79.5 ran its iOS CI Test job on the runner host. Setup Simulator logged Using runtime: com.apple.CoreSimulator.SimRuntime.iOS-27-2 with no fallback, on a host that also lists the device-specific iOS-27-2-iPhone19-4 runtime, and the Test job passed. Before this pin, the same host's 27.0 runtime failed simctl create with SimError 401.

Not changed

The dated-override guard (internal/tokens/runtime.go) and the watch runtime resolver (internal/tokens/watch.go) use the same substring grep -q. No device-specific variant of those runtimes exists on the host today, so they are left alone.

The runner host's iOS 27.0 runtime is listed as ready but cannot create a
device (SimError 401, runtime path not found); 27.2 creates fine. Move the
fleet pin, and the watch runtime that follows it, to 27.2.

The Setup Simulator presence check was a substring grep, so a host with only
the device-specific runtime (pin plus a -<device> suffix) passed it, and the
fallback pattern extracted a truncated id that sorted above the real runtime.
Match the last field of each simctl line as a whole and only fall back to
plain iOS-<major>-<minor> ids.
@patrickserrano

Copy link
Copy Markdown
Owner Author

Agent CI round 1 of 2 · round · ef3177b · 2026-10-24T13:58:13Z

@patrickserrano

Copy link
Copy Markdown
Owner Author

Fresh-context verifier at ef3177b: PASS.

  1. Diff matches the ask: pin 27.2 (internal/config/config.go:1411), exact whole-field match plus plain-id-only fallback (profiles/ios/workflows/ci.yml ~1976), and the new test internal/shipped/sim_runtime_exact_test.go. No 27-0 runtime id is left outside testdata.
  2. No existing test weakened: every change to an old test is a 27.0 to 27.2 value swap, with no removed assertion and no skip.
  3. New tests ran: CI run 40100414063 ok .../internal/shipped (no -run filter, no Skip/Short/build tag), and a local -v run at the head shows RUN/PASS for both new tests.

@patrickserrano
patrickserrano merged commit 89a4ef7 into main Oct 24, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant