diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 927e36e..8343ff4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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. diff --git a/packages/Bus/Tests/BusTests/BatcherTests.swift b/packages/Bus/Tests/BusTests/BatcherTests.swift index 32c9e2a..991078d 100644 --- a/packages/Bus/Tests/BusTests/BatcherTests.swift +++ b/packages/Bus/Tests/BusTests/BatcherTests.swift @@ -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