Compare commits

...
Author SHA1 Message Date
james.maesandClaude Opus 4.7 eb90bedaf4 fix(ci): pin Xcode 26.x, drop phantom VoiceLog, harden Batcher timing
CI run 25799596445 failed on 6 SPM packages + the App target. Root cause
was a toolchain skew between local dev (Swift 6.3.2 / Xcode 26) and CI
(Swift 6.0 / Xcode 16):

- mlx-audio-swift v0.1.2 ships swift-tools-version:6.2 which Swift 6.0
  cannot parse, breaking Voice + Harness + the App target with
  "Dependencies could not be resolved because 'mlx-audio-swift' contains
  incompatible tools version (6.2.0)".
- MCP swift-sdk 0.12.0 uses the new `withThrowingTaskGroup` overload
  (no `of:` parameter) that only exists in Swift 6.2+.
- AgentCore tests use `@MainActor` XCTestCase with `await super.setUp()`,
  a pattern Swift 6.0 rejects but Swift 6.1+ accepts.

The macos-15 runner already ships Xcode 26.3 / 26.2 / 26.1 / 26.0
alongside 16.x, so the fix is to switch the Xcode select. Fallback to
Xcode_26.app preserves robustness against patch-level shuffles.

Also:
- Drop `VoiceLog` from the SPM matrix. No `packages/VoiceLog` directory
  exists; the job failed with `chdir error: No such file or directory`.
  Voice-log work is parked under v1.1.
- Bump BatcherTests `waitForDrain` from 80ms to 250ms. The batcher
  window is 33ms; 80ms was tight enough that macos-15 dropped
  test_tokenDeltaConcat with sendCount=0 because the scheduled drain
  hadn't completed its actor + main-actor hop before the test resumed.
  250ms (~7.5× the window) survives CI jitter; verified locally — all
  five Batcher tests pass in 1.27s.

Refs: CI run 25799596445.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 08:14:13 -05:00
2 changed files with 32 additions and 13 deletions

No files matched your search

+17 -7
View File
@@ -122,6 +122,9 @@ jobs:
strategy:
fail-fast: false
matrix:
# VoiceLog removed: no `packages/VoiceLog` directory exists in the
# repo. The matrix entry was a phantom that failed with `chdir error:
# No such file or directory`. Voice-log work tracked under v1.1.
package:
- AgentCore
- Bus
@@ -136,20 +139,25 @@ jobs:
- Shell
- Vision
- Voice
- VoiceLog
steps:
- uses: actions/checkout@v4
# Project targets macOS 26 Tahoe + Swift 6.2/6.3. Xcode 16 (Swift 6.0)
# cannot parse `mlx-audio-swift` v0.1.2's `swift-tools-version:6.2`,
# lacks the `withThrowingTaskGroup` overload used by MCP `swift-sdk`
# 0.12.0, and rejects `@MainActor` XCTestCase `super.setUp()` patterns
# that Swift 6.1+ accepts. Pin to the newest Xcode 26.x on macos-15.
# See actions/runner-images macos-15 readme for installed Xcode list.
- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_16.app/Contents/Developer || sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
run: sudo xcode-select -s /Applications/Xcode_26.3.app/Contents/Developer || sudo xcode-select -s /Applications/Xcode_26.app/Contents/Developer
- name: Show Swift toolchain
run: |
swift --version
xcodebuild -version
# Download the production webview bundle so Bus + downstream packages
# (AgentCore / Harness / MCP / Voice / VoiceLog) can mount a real
# WKWebView with a working JS bridge. Without this, BusTests fail
# with `Error: bus not mounted` because index.html + the JS bundle
# are missing from App/Resources/webview/.
# (AgentCore / Harness / MCP / Voice) can mount a real WKWebView with
# a working JS bridge. Without this, BusTests fail with `Error: bus
# not mounted` because index.html + the JS bundle are missing from
# App/Resources/webview/.
- name: Download webview resources
uses: actions/download-artifact@v4
with:
@@ -173,8 +181,10 @@ jobs:
needs: [boundary-gates, webview]
steps:
- uses: actions/checkout@v4
# Same Xcode 26.x pin as swift-packages — Xcode 16 cannot resolve
# mlx-audio-swift's swift-tools-version:6.2 manifest.
- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_16.app/Contents/Developer || sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
run: sudo xcode-select -s /Applications/Xcode_26.3.app/Contents/Developer || sudo xcode-select -s /Applications/Xcode_26.app/Contents/Developer
- name: Install xcodegen
run: brew install xcodegen
# Reuse the webview build from the upstream job rather than rebuilding.
+15 -6
View File
@@ -3,7 +3,13 @@ import XCTest
/// Exercises `OutboundBatcher` behaviour against a recording fake sink. All
/// timing assertions are designed to survive CI jitter — the batcher's nominal
/// window is 33ms; tests wait ≥60ms (≈2x) before asserting.
/// window is 33ms; tests wait 250ms (≈7.5x) before asserting. The earlier
/// 80ms wait was tight enough that macOS-15 GitHub Actions runners (cold
/// build + cold WKWebView mount sharing the box) intermittently dropped
/// `test_tokenDeltaConcat` with sendCount=0 — the 33ms `Task.sleep` had not
/// yet hopped back through the batcher actor + main actor by the time the
/// test resumed. 250ms gives the scheduled drain ample time without making
/// the suite noticeably slower (the four affected tests cost ~1s total).
///
/// The fake is `@MainActor`-isolated because `BusOutbound` does not cross
/// actor boundaries by default under Swift 6 strict concurrency, and the
@@ -21,13 +27,16 @@ final class BatcherTests: XCTestCase {
}
}
// A small drain-wait helper. The batcher window is 33ms; wait 80ms to let
// the scheduled drain fire and propagate the main-actor hop.
// `@MainActor` because each test is main-actor-isolated and Swift 6 strict
// concurrency disallows sending `self` across a nonisolated boundary.
// A small drain-wait helper. The batcher window is 33ms; wait 250ms to
// let the scheduled drain fire and propagate the main-actor hop. The
// earlier 80ms wait was flaky on macos-15 CI runners (cold builds racing
// a cold WKWebView mount on the same box) — see commit message + doc
// comment above. `@MainActor` because each test is main-actor-isolated
// and Swift 6 strict concurrency disallows sending `self` across a
// nonisolated boundary.
@MainActor
private func waitForDrain() async {
try? await Task.sleep(for: .milliseconds(80))
try? await Task.sleep(for: .milliseconds(250))
}
// MARK: - Tests