From 47581adbd5de9a2126d62e5944db5a158f594060 Mon Sep 17 00:00:00 2001 From: lawrencecchen <54008264+lawrencecchen@users.noreply.github.com> Date: Wed, 8 Jul 2026 01:53:48 -0700 Subject: [PATCH 1/2] ci: stop skipped linux jobs from transitively skipping staged macOS jobs Since https://github.com/manaflow-ai/cmux/pull/7583 staged macOS CI behind linux-preflight, every PR that does not touch web/go/agent-session paths fails CI: the routed linux jobs skip, GitHub's implicit success() gate evaluates the transitive needs chain, and app-host-unit-tests, swift-package-tests, tests-build-and-lag, and release-build all report skipped even though linux-preflight itself succeeded. The tests gate then fails with 'app-host unit tests were required but did not pass: skipped'. Replace the implicit gate with an explicit direct-needs condition: !cancelled() plus result == 'success' for each direct need, keeping the macos route filter. #7583's own PR run missed this because workflow file changes set every path filter true, so no routed job skipped there; the same applies to this PR's run, so the skip path is provable only on a macOS-only PR after merge. --- .github/workflows/ci.yml | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3335fee17806..b7b6b762386b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -388,7 +388,12 @@ jobs: needs: - changes - linux-preflight - if: ${{ needs.changes.outputs.macos == 'true' }} + # !cancelled() disables the implicit success() gate, which GitHub evaluates + # over the transitive needs chain: linux-preflight runs behind routed linux + # jobs that legitimately skip (web/go/agent-session paths), and that + # transitive skip otherwise marks every macOS job skipped even when + # linux-preflight itself succeeds. Require the direct needs explicitly. + if: ${{ !cancelled() && needs.changes.result == 'success' && needs.linux-preflight.result == 'success' && needs.changes.outputs.macos == 'true' }} name: app-host unit tests (${{ matrix.shard }}/4) # App-host XCTest needs a runner that can broker testmanagerd control # sessions. Validated head-to-head that warp-macos-15-arm64-6x runs the @@ -772,7 +777,12 @@ jobs: needs: - changes - linux-preflight - if: ${{ needs.changes.outputs.macos == 'true' }} + # !cancelled() disables the implicit success() gate, which GitHub evaluates + # over the transitive needs chain: linux-preflight runs behind routed linux + # jobs that legitimately skip (web/go/agent-session paths), and that + # transitive skip otherwise marks every macOS job skipped even when + # linux-preflight itself succeeds. Require the direct needs explicitly. + if: ${{ !cancelled() && needs.changes.result == 'success' && needs.linux-preflight.result == 'success' && needs.changes.outputs.macos == 'true' }} runs-on: ${{ vars.MACOS_RUNNER_15 || 'warp-macos-15-arm64-6x' }} timeout-minutes: 40 env: @@ -1076,7 +1086,12 @@ jobs: needs: - changes - linux-preflight - if: ${{ needs.changes.outputs.macos == 'true' }} + # !cancelled() disables the implicit success() gate, which GitHub evaluates + # over the transitive needs chain: linux-preflight runs behind routed linux + # jobs that legitimately skip (web/go/agent-session paths), and that + # transitive skip otherwise marks every macOS job skipped even when + # linux-preflight itself succeeds. Require the direct needs explicitly. + if: ${{ !cancelled() && needs.changes.result == 'success' && needs.linux-preflight.result == 'success' && needs.changes.outputs.macos == 'true' }} # Build the full cmux scheme once, then run the required display/runtime # regressions from the same DerivedData instead of queuing a second display # runner for UI-only checks. @@ -1412,7 +1427,10 @@ jobs: - changes - linux-preflight - swift-package-tests - if: ${{ needs.changes.outputs.macos == 'true' }} + # See app-host-unit-tests: explicit direct-needs gate instead of the + # implicit success() so skipped routed linux jobs upstream of + # linux-preflight do not skip this job transitively. + if: ${{ !cancelled() && needs.changes.result == 'success' && needs.linux-preflight.result == 'success' && needs.swift-package-tests.result == 'success' && needs.changes.outputs.macos == 'true' }} # Compile the same unsigned universal Release app that nightly builds before # signing, notarization, and publishing. This catches DEBUG/Release boundary # mistakes before they reach main. From 2a58d9f5ec5876029758db8beb3f29dc2576bfca Mon Sep 17 00:00:00 2001 From: lawrencecchen <54008264+lawrencecchen@users.noreply.github.com> Date: Wed, 8 Jul 2026 01:58:40 -0700 Subject: [PATCH 2/2] tests: macOS staging guard requires explicit direct-needs gate test_macos_jobs_wait_for_linux_preflight asserted the exact bare macos route literal, which is the condition that reintroduces the transitive skip. Assert the !cancelled() + direct-needs form instead, and reject the bare literal. --- tests/test_ci_change_areas.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/test_ci_change_areas.py b/tests/test_ci_change_areas.py index b11e518bc847..e88c97f5f460 100644 --- a/tests/test_ci_change_areas.py +++ b/tests/test_ci_change_areas.py @@ -491,6 +491,11 @@ def test_required_tests_status_waits_for_app_host_matrix() -> None: def test_macos_jobs_wait_for_linux_preflight() -> None: + # The staged macOS jobs must gate on their direct needs explicitly. + # A bare `if: needs.changes.outputs.macos == 'true'` keeps the implicit + # success() gate, which GitHub evaluates over the transitive needs chain: + # routed linux jobs that legitimately skip (web/go/agent-session paths) + # then mark every macOS job skipped even though linux-preflight succeeded. for job_name in [ "app-host-unit-tests", "swift-package-tests", @@ -500,7 +505,16 @@ def test_macos_jobs_wait_for_linux_preflight() -> None: block = workflow_job_block(job_name) assert " - changes" in block assert " - linux-preflight" in block - assert "if: ${{ needs.changes.outputs.macos == 'true' }}" in block + assert "if: ${{ needs.changes.outputs.macos == 'true' }}" not in block + expected_needs = ["changes", "linux-preflight"] + if job_name == "release-build": + expected_needs.append("swift-package-tests") + expected_if = ( + "if: ${{ !cancelled() && " + + " && ".join(f"needs.{need}.result == 'success'" for need in expected_needs) + + " && needs.changes.outputs.macos == 'true' }}" + ) + assert expected_if in block, f"{job_name} must gate on direct needs explicitly" def test_linux_preflight_blocks_macos_on_cheap_layer_failure() -> None: