Skip to content

Harden CI workflows for Node 24 and Xcode#78

Merged
ber4444 merged 7 commits into
mainfrom
codex/update-node24-actions
Jul 7, 2026
Merged

Harden CI workflows for Node 24 and Xcode#78
ber4444 merged 7 commits into
mainfrom
codex/update-node24-actions

Conversation

@ber4444

@ber4444 ber4444 commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Summary

Updates the CI workflows for current GitHub Actions runtimes and hardens the Android and Apple test jobs that were producing warnings or failures on PR #78. Also fixes an iOS Stockfish startup race that caused the Xcode Swift tests to return nil moves/scores on CI.

Why

GitHub Actions warns when Node 20-backed JavaScript actions are forced onto Node 24. Android tests also warned about a stale emulator-runner input and a report artifact path that does not match the KMP connected test layout. Apple jobs used macos-latest, which GitHub is migrating to macOS 26 beginning June 15, 2026.

The Xcode job also exposed an iOS Stockfish readiness race: the wrapper could read Engine.responseStream before ChessKitEngine had created it, exit the detached startup task, and leave getBestMove / evaluate waiting for readiness until they returned nil.

Changes

  • Bump checkout, setup-java, setup-node, setup-android, setup-gradle, cache, and upload-artifact actions used by CI and publish workflows.
  • Update the commented AVD cache example so it does not reintroduce actions/cache@v4.
  • Use Node 22 for the Android test workflow Node.js setup.
  • Bump reactivecircus/android-emulator-runner to v2.38.0 so the Android emulator action itself runs on Node 24.
  • Replace the Android emulator runner boot-timeout input with emulator-boot-timeout.
  • Upload the connected Android test report/results directories instead of the old debug-specific HTML path.
  • Pin Apple CI jobs to macos-15 to avoid the macos-latest macOS 26 migration warning.
  • Make the Xcode simulator destination explicit with OS=latest,arch=arm64 and disable parallel testing for the Swift test run.
  • Start the iOS Stockfish engine before reading its response stream, then wait until ChessKitEngine is running before sending app-level UCI options.

Validation

  • YAML parse check for .github/workflows/*.yml
  • git diff --check --cached
  • Targeted scan for old warning patterns: boot-timeout, macos-latest, androidTests/connected/debug/index.html, and the old emulator runner tag
  • Targeted Xcode simulator run for StockfishChessEngineTests/testBestMoveFromStartPositionIsUciMove and StockfishChessEngineTests/testEvaluateStartPositionIsRoughlyBalanced on an arm64 simulator
  • GitHub Actions run after the emulator runner bump: Android tests passed; Xcode progressed past the previous runner crash and exposed the Stockfish readiness race fixed in the follow-up commit

@ber4444 ber4444 changed the title Update GitHub Actions for Node 24 Update GitHub Actions for Node 24 and CI warnings Jul 7, 2026
@ber4444 ber4444 marked this pull request as ready for review July 7, 2026 12:24
@ber4444 ber4444 changed the title Update GitHub Actions for Node 24 and CI warnings Harden CI workflows for Node 24 and Xcode Jul 7, 2026
ber4444 added 3 commits July 7, 2026 06:04
…ailures)

The Xcode Swift test testBestMoveFromStartPositionIsUciMove intermittently failed
on CI with "Move was nil!" (~51s timeout). Root cause was a startup race: the
`isready`/`readyok` handshake could be dropped because ChessKitEngine's
responseStream is hot — a response emitted before `for await` begins iterating is
lost — and NNUE `setoption`s were sent before `uciok` (when the engine may silently
drop them), so `readyok` never arrived within the 30s timeout on a contended
3-core Debug CI runner.

Fix restructures the SharedStockfishCore init handshake into a strict sequence:
  1. start engine + get stream
  2. START iterating the stream BEFORE sending any command (so no response is missed)
  3. send `uci`, await `uciok` via a CheckedContinuation (async-native; blocking a
     DispatchSemaphore from async code is a Swift 6 language-mode error)
  4. send NNUE EvalFile/EvalFileSmall setoptions + Skill Level
  5. send `isready` (readyok awaited lazily by the first runSearch via readySemaphore)

Also bumps sharedReadyTimeout 30s → 90s: a cold start on contended CI can spend
30-40s loading NNUE before acknowledging readyok.

Verified locally: testBestMoveFromStartPositionIsUciMove now passes in ~2s
(was ~51s timeout); all 4 Swift tests pass; zero Swift warnings. The retry
logic in getBestMove/evaluate remains as a safety net.
The previous CheckedContinuation approach (commit c319fca) crashed the test
process on CI ~10s into testBestMoveFromStartPositionIsUciMove — xcodebuild
reported "Restarting after unexpected exit, crash, or test timeout". The crash
was from the continuation being abandoned (when the stream/engine tore down
before uciok arrived) — CheckedContinuation traps in that case.

Redesign: drive the ENTIRE uci→uciok→setoptions→isready→readyok handshake
inline from the single consumer `for await response in stream` loop. This:
  - eliminates cross-task signaling entirely (no continuation, no second Task)
  - is race-free by construction (the loop is single-threaded over the stream)
  - guarantees commands are sent in exact order and no response is missed
    (the original root cause: the consumer started iterating after isready was
    sent, so readyok was dropped)

Once the handshake completes (readyok received), the same loop routes runtime
responses (info/bestmove) to handleRuntime(). The readySemaphore remains for
runSearch's sync waitUntilReady() (called off the main thread, never from async).

Verified locally on a clean simulator: all 4 Swift tests pass; the first
(cold-start) test takes ~26s for NNUE load but completes with a valid move.
@ber4444 ber4444 merged commit 9a5a9c0 into main Jul 7, 2026
3 checks passed
@ber4444 ber4444 deleted the codex/update-node24-actions branch July 7, 2026 14:09
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