Skip to content

ci(ios): pin iOS jobs to macos-15 to stabilize simulator boot#300

Open
mfazekas wants to merge 1 commit into
mainfrom
ci/pin-ios-runner-macos-15
Open

ci(ios): pin iOS jobs to macos-15 to stabilize simulator boot#300
mfazekas wants to merge 1 commit into
mainfrom
ci/pin-ios-runner-macos-15

Conversation

@mfazekas

Copy link
Copy Markdown
Collaborator

macos-latest is mid-migration to macOS 26, so the iOS jobs randomly land on macos-15-arm64 or macos-26-arm64. Only the macOS 15 image has a pre-created iPhone 16 Pro on an iOS >=26 runtime; on macos-26 the simulator-action boot step fails with "No devices found".

This is why an identical commit passes on one run and fails on another — e.g. the 0.4.12 release PR (#299) failed solely because it drew a macos-26 runner, while the same code on main passed on macos-15.

Pin build-ios and test-harness-ios to macos-15 for deterministic runs.

Follow-up (not in this PR): make the simulator selection image-agnostic (query an available iOS runtime / device dynamically) so the eventual macOS 15 retirement doesn't reintroduce this.

macos-latest is mid-migration to macOS 26. Jobs randomly land on
macos-15-arm64 or macos-26-arm64, and only the macOS 15 image has a
pre-created iPhone 16 Pro on an iOS >=26 runtime. When a job lands on
macos-26 the simulator-action boot step fails with 'No devices found',
which is why the same commit passes on one run and fails on another.

Pin build-ios and test-harness-ios to macos-15 for deterministic runs.
mfazekas added a commit that referenced this pull request Jul 1, 2026
…rs) (#303)

The `#230` test drove re-renders with `setInterval(50ms)` for 300ms and
asserted `renderCount >= 3` within a 2000ms `waitFor`. `waitFor`
resolves the instant renderCount hits 3 — i.e. it needs *exactly* 2
interval ticks, **zero margin**. When the JS thread is busy at mount
(RiveView + dataBind init) the ticks are starved and only 1 lands, so
renderCount stays at 2 and the test fails (the intermittent `expected 2
to be greater than or equal to 3`).

## Fix
Drive the re-renders deterministically via an exposed
`context.rerender()` (the pattern `issue297.hooks` already uses) instead
of racing a wall-clock `setInterval`. The callback-identity churn is
preserved; the timing dependence is gone.

## Reproduction kept in the test
The PR keeps the failure condition as a **permanent regression guard** —
a 500ms JS-thread block at mount that starves any re-render driver (what
RiveView init does on a slow runner). This is the concrete reproduction:
- **old `setInterval` approach + this block → 8/8 fail** (`renderCount`
stuck at 2)
- **new deterministic approach + this block → 8/8 pass**

So every CI run now verifies the fix against the reproduction, rather
than relying on the ~1% natural flake. (Locally I also confirmed the
natural flake at ~1%, and that `renderCount` lands at exactly 3 — zero
margin — on every passing run.)

## CI changes
This PR is **not** purely a JS test change — it also touches
`.github/workflows/ci.yml`:

- **Pin the iOS jobs (`build-ios`, `test-harness-ios`) to `macos-15`**
(Xcode `26.3`, simulator `iPhone 16 Pro` on iOS `>=26.0`).
`macos-latest` is mid-migration to macOS 26, whose simulator set has no
matching iPhone 16 Pro / iOS >=26 runtime, which breaks the harness boot
("No devices found"). This **overlaps with #300**, which pins the same
runners; if #300 lands first, this part should be rebased away.
- **Add a 300s per-attempt watchdog** to the `test-harness-ios` retry
loop. The harness can hang indefinitely if the app launches but never
connects to the bridge; without a cap a single stuck attempt eats the
whole 15-min step budget and the retry loop never advances. macOS has no
`timeout`, so a background watchdog kills the stuck attempt and
`nuke_harness` reaps the rest before the retry.
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