ci: run the ios leg on macos-26, pinned to a device and a runtime

macos-26 carries no iPhone 16 Pro at all, and on macos-15 that name spanned
iOS 18.5 through 26.2, so the leg could boot a two-major-old runtime. the
pair is now iPhone 17 Pro on iOS 26.2, resolved to a udid before boot, and
an image that drops it fails naming what it does carry.

iPhone 17 Pro is what examples/folio/justfile already defaulted to.
This commit is contained in:
pj committed 2026-08-16 22:14:56 +05:30
1 parent 644e036578
commit 9a292aefd8
4 files changed
+52 -6

No files matched your search

+1 -1
View File
@@ -110,7 +110,7 @@ expect_argv "--seed" argv-ios
expect_argv "7" argv-ios expect_argv "7" argv-ios
expect_argv "240" argv-ios expect_argv "240" argv-ios
expect_argv "20m" argv-ios expect_argv "20m" argv-ios
expect_argv "iPhone 16 Pro" argv-ios expect_argv "iPhone 17 Pro" argv-ios
run argv-android android 2 <<TRACE run argv-android android 2 <<TRACE
$on_txn $on_txn
+1 -1
View File
@@ -102,7 +102,7 @@ case "$platform" in
# away from the `simctl uninstall` + `install` path that races FrontBoard # away from the `simctl uninstall` + `install` path that races FrontBoard
# ("app.folio is unknown to FrontBoard"), which needs an app path to reach. # ("app.folio is unknown to FrontBoard"), which needs an app path to reach.
folio_args+=(--platform ios folio_args+=(--platform ios
--ios-device "${IOS_DEVICE:-iPhone 16 Pro}") --ios-device "${IOS_DEVICE:-iPhone 17 Pro}")
;; ;;
web) web)
dist="examples/folio/app/webApp/build/dist/wasmJs/developmentExecutable" dist="examples/folio/app/webApp/build/dist/wasmJs/developmentExecutable"
+42 -4
View File
@@ -236,13 +236,14 @@ jobs:
folio-ios: folio-ios:
name: Folio (ios) name: Folio (ios)
runs-on: macos-15 runs-on: macos-26
timeout-minutes: 90 timeout-minutes: 90
env: env:
SEED: "7" SEED: "7"
MAX_STEPS: "240" MAX_STEPS: "240"
DURATION: 20m DURATION: 20m
IOS_DEVICE: iPhone 16 Pro IOS_DEVICE: iPhone 17 Pro
IOS_RUNTIME: iOS 26.2
steps: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v7
@@ -265,10 +266,47 @@ jobs:
- name: Build sanderling - name: Build sanderling
run: make sanderling-ios run: make sanderling-ios
# simctl resolves a device by name alone, and one image carries the same
# phone under several runtimes: iPhone 17 Pro exists here on iOS 26.2,
# 26.4 and 26.5. Booting by name is therefore booting on whichever one
# simctl happens to list first, and a seed only means something against a
# fixed runtime. So the pair is resolved to a UDID here and every step
# after this is handed that. An image that stops carrying the pair fails
# here naming what it does carry, rather than as a `bootstatus` error to
# read backwards from.
- name: Boot a simulator - name: Boot a simulator
run: | run: |
xcrun simctl boot "$IOS_DEVICE" || true udid="$(python3 <<'PY'
xcrun simctl bootstatus "$IOS_DEVICE" -b import json, os, subprocess, sys
want_device = os.environ["IOS_DEVICE"]
want_runtime = os.environ["IOS_RUNTIME"]
devices = json.loads(subprocess.run(
["xcrun", "simctl", "list", "devices", "available", "--json"],
capture_output=True, text=True, check=True).stdout)["devices"]
def name_of(runtime):
family, _, version = runtime.rsplit(".", 1)[-1].partition("-")
return "%s %s" % (family, version.replace("-", "."))
for runtime, entries in devices.items():
if name_of(runtime) != want_runtime:
continue
for entry in entries:
if entry["name"] == want_device:
print(entry["udid"])
sys.exit(0)
carried = sorted({"%s on %s" % (e["name"], name_of(r))
for r, es in devices.items() for e in es})
sys.exit("no %r on %r in this image. it carries:\n %s"
% (want_device, want_runtime, "\n ".join(carried) or "no simulators at all"))
PY
)"
echo "booting $IOS_DEVICE on $IOS_RUNTIME ($udid)"
xcrun simctl boot "$udid"
xcrun simctl bootstatus "$udid" -b
echo "IOS_DEVICE=$udid" >> "$GITHUB_ENV"
- name: Build and install folio - name: Build and install folio
working-directory: examples/folio working-directory: examples/folio
+8
View File
@@ -170,6 +170,14 @@ reinstall-and-launch cycles on iOS 26.1, 10 of them reinstalling on top of a
live app, so any fix for it has to be developed on a host that can still show it live app, so any fix for it has to be developed on a host that can still show it
failing. failing.
The leg names a device and a runtime, `iPhone 17 Pro` on `iOS 26.2`, and boots
by the UDID that pair resolves to. Both halves matter: one runner image carries
the same phone under several runtimes, so booting by name alone is booting on
whichever one `simctl` lists first, and a seed that is only calibrated against a
runtime it did not run on says nothing. A runner image that stops carrying the
pair fails the boot step naming what it does carry, which is the cue to pick a
new pair and recalibrate rather than a `bootstatus` error to read backwards.
Only one sanderling run may drive a given simulator at a time. The driver takes Only one sanderling run may drive a given simulator at a time. The driver takes
an advisory lock on the target's UDID and a second run is refused with the lock an advisory lock on the target's UDID and a second run is refused with the lock
path in the message, because two runs interleaving app lifecycle leave the first path in the message, because two runs interleaving app lifecycle leave the first