Skip to content

ci: aggregate required gates (stop branch-protection desync on renames/splits) - #6519

Merged
azooz2003-bit merged 4 commits into
mainfrom
feat-ci-aggregate-gates
Jun 20, 2026
Merged

azooz2003-bit merged 4 commits into
mainfrom
feat-ci-aggregate-gates

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Jun 20, 2026 •

Copy link
Copy Markdown
Collaborator

Why

Branch protection matches required status checks by literal name, and that list is hand-maintained. The recent CI burst kept changing names out from under it:

  • Speed up macOS CI with unit test sharding #6464 sharded the tests job → reported as app-host unit tests (N/4), so the required tests context went "expected" forever and blocked every PR built on top of it (until Route agent session web resource CI #6474 added a tests summary back).
  • iOS jobs live in a separate test-ios.yml; new suites (swift-package-tests, agent-session-web-resources) were added — none added to the required list, so they run but don't gate.

This is a recurring class of breakage: every rename / shard / workflow-split silently desyncs the required-checks name list.

What

Gate via aggregate summary jobs that reference suites by their job KEY through needs: (immune to display-name and shard changes), one per workflow:

  • ci.yml → tests-required-status (reported as tests, already required): now also needs: swift-package-tests + agent-session-web-resources. A real failure in either blocks merge; a path-filtered skip is allowed.
  • test-ios.yml → new ios-tests aggregate: needs: detect-ios-changes, package-conventions-lint, mobile-core-package, ios-simulator, same skip-tolerant logic.

Both mirror the existing ci-status / tests-required-status pattern.

Settings change required (after merge)

  • Add ios-tests to the main ruleset's required status checks. Do this after this PR merges, so the job exists first.
  • The tests change needs no settings change (same check name).

Policy note

ios-tests makes a real iOS suite failure block iOS-touching PRs (iOS jobs skip on non-iOS PRs via detect-ios-changes, and skip = pass here). If iOS sim flakiness should stay advisory, drop ios-simulator from the ios-tests needs: and keep only mobile-core-package + package-conventions-lint. Your call.

🤖 Generated with Claude Code


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Summary by cubic

Aggregate CI gates to keep branch protection stable when jobs are renamed or sharded. Expands the tests gate, adds a new ios-tests gate, and renames the unit-test matrix job key to app-host-unit-tests; updates CI guard tests and wiring to match.

  • Refactors

    • ci.yml: tests gate now needs app-host-unit-tests, swift-package-tests, and agent-session-web-resources; updated ci-status needs to reference the new keys.
    • test-ios.yml: adds ios-tests gate over detect-ios-changes, package-conventions-lint, mobile-core-package, and ios-simulator.
    • Rename: sharded unit-test job key tests → app-host-unit-tests; aggregate is keyed tests. Updated tests/test_ci_change_areas.py and tests/test_ci_self_hosted_guard.sh.
  • Migration

    • After merge, add ios-tests to the main ruleset’s required checks. tests needs no change.

Written for commit 9c882ec. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Chores
    • Strengthened CI merge gating by renaming the app-host unit test job and updating downstream workflow wiring and aggregation of required suite results.
    • Expanded CI required-status validation to include additional iOS and Swift/web-related suites, allowing only success or skipped.
    • Added an iOS aggregate gate that blocks merges unless change detection succeeds and all required iOS suites complete with success/skipped.
    • Updated CI validation tests and the self-hosted runner guard to match the revised job names and checks.

…protection

Branch protection requires status checks by literal name, but recent CI churn
(unit-test sharding renamed the `tests` job to `app-host unit tests (N/4)` in
#6464; jobs split across ci.yml and test-ios.yml; new suites added) kept moving
those names out from under the static required-checks list — stranding old names
("expected" forever, blocking every PR) and leaving new suites ungated.

Fix: gate via aggregate summary jobs that reference suites by their job KEY
(immune to display-name/shard changes), one per workflow.

- ci.yml `tests-required-status` (reported as `tests`, already required): now also
  needs `swift-package-tests` and `agent-session-web-resources`, so a failure in
  either blocks merge. Skipped (path-filtered) is still allowed.
- test-ios.yml: new `ios-tests` aggregate over `detect-ios-changes`,
  `package-conventions-lint`, `mobile-core-package`, `ios-simulator`, same
  skip-tolerant logic.

Settings follow-up (after merge): add `ios-tests` to the main ruleset's required
status checks. The `tests` change needs no settings change (same name). Optional
cleanup: the individual web/release contexts can stay or be folded into the
aggregates later.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 20, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jun 20, 2026 11:22pm
cmux-staging Building Building Preview, Comment Jun 20, 2026 11:22pm

@coderabbitai

coderabbitai Bot commented Jun 20, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Three CI workflow updates refactor test job naming and extend gate aggregation logic. In ci.yml, the app-host unit test job is renamed from tests to app-host-unit-tests, and its references are updated across downstream gates. The tests-required-status gate adds swift-package-tests and agent-session-web-resources to its validation requirements. In test-ios.yml, a new ios-tests aggregate gate job is introduced to enforce iOS suite outcomes.

Changes

CI Gate Aggregation Updates

Layer / File(s) Summary
Refactor app-host unit test job naming
.github/workflows/ci.yml
App-host unit test job is renamed from tests to app-host-unit-tests; references are updated in tests-required-status Python gate logic and ci-status job needs list.
Extend tests-required-status gate validation
.github/workflows/ci.yml
swift-package-tests and agent-session-web-resources are added to needs list and Python gating logic now enforces both report success or skipped, with output reporting of their results.
Add ios-tests aggregate gate job
.github/workflows/test-ios.yml
New ios-tests job always runs, validates detect-ios-changes succeeded, and enforces all other required iOS suite jobs report success or skipped.
Update CI test validation and guards
tests/test_ci_change_areas.py, tests/test_ci_self_hosted_guard.sh
Test assertions updated to reflect ci-status and tests job dependency changes, and shell script guards updated to validate app-host-unit-tests macOS runner compliance with clarified bare runner exceptions.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • manaflow-ai/cmux#5443: Modifies test-ios.yml to gate iOS CI using detect-ios-changes outputs and needs results, directly related to the new ios-tests aggregate gate added here.
  • manaflow-ai/cmux#6464: Introduces swift-package-tests and agent-session-web-resources jobs that this PR now registers as required suites in tests-required-status.
  • manaflow-ai/cmux#6490: Modifies the macOS app-host unit-test section of .github/workflows/ci.yml in the same job being renamed here.

Suggested reviewers

  • lawrencecchen

Poem

🐇 The gates grow strong, the jobs align,
App-host now wears its name so fine,
Swift packages and iOS blend,
Success or skipped—merge gates won't bend!
A rabbit's care in CI we see,
No broken builds shall pass, tee-hee! 🌿

🚥 Pre-merge checks | ✅ 21 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The pull request description covers the problem and solution clearly but is missing key template sections: no Testing section (how/what tested), no Demo Video, no Review Trigger block, and no Checklist. Add Testing section (test methodology and manual verification), Review Trigger block with bot mentions, and complete the Checklist with test and documentation status. A Demo Video section is less critical for CI workflow changes.
✅ Passed checks (21 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: introducing aggregate gate jobs to prevent branch protection desynchronization caused by CI job renames and splits.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed PR contains no production Swift changes—only GitHub Actions workflow configuration (.yml), Python test files (.py), and shell scripts (.sh). Check requires production Swift code to evaluate.
Cmux Swift Blocking Runtime ✅ Passed This PR contains only CI workflow configuration changes and test updates (.github/workflows/.yml, tests/.py, tests/*.sh). No production Swift files are modified, so blocking/timing-based synchron...
Cmux Expensive Synchronous Load ✅ Passed PR contains only CI workflow configuration (YAML) and test infrastructure changes; no production Swift code modifications are present, so the expensive synchronous load check does not apply.
Cmux Cache Substitution Correctness ✅ Passed Check is not applicable: PR contains only CI workflow YAML, Python tests, and shell scripts—no production Swift, TypeScript, or JavaScript code changes subject to cache substitution rules.
Cmux No Hacky Sleeps ✅ Passed All PR changes are to CI workflow YAML files (.github/workflows/) and test files (tests/), which are explicitly out of scope per runtime-no-hacky-sleeps.md. No production runtime code was modified.
Cmux Algorithmic Complexity ✅ Passed This PR modifies only GitHub Actions workflow YAML files, Python test files, and shell test scripts. Per the algorithmic complexity rule, these are not production code (which is Swift, TypeScript,...
Cmux Swift Concurrency ✅ Passed PR modifies only GitHub Actions workflow YAML, Python tests, and shell scripts—no cmux Swift source code changes, so the Swift concurrency check does not apply.
Cmux Swift @Concurrent ✅ Passed No Swift source code changes in this PR. Changes are limited to YAML workflow files and Python/shell test scripts. The @concurrent annotation rule is not applicable.
Cmux Swift File And Package Boundaries ✅ Passed PR contains no production Swift file changes—only YAML workflows, Python tests, and shell scripts. Check is not applicable.
Cmux Swiftpm Lockfiles ✅ Passed PR contains only CI workflow and test file changes—no SwiftPM Package.swift, Package.resolved, .gitignore, or Xcode project modifications. The check applies to such changes; this PR does not trigge...
Cmux Swift Logging ✅ Passed PR contains no Swift code changes; only YAML workflows and Python/Shell test files are modified. Custom check for Swift logging violations is not applicable.
Cmux User-Facing Error Privacy ✅ Passed PR modifies CI workflows and test files only (not user-facing product code). Error messages in workflow logs are developer-only diagnostics containing only generic status values and job names, no f...
Cmux Full Internationalization ✅ Passed PR contains only CI/workflow infrastructure and test fixture changes; no user-facing text added per full-internationalization.md allowed cases.
Cmux Swiftui State Layout ✅ Passed PR contains only GitHub Actions workflow and test file changes; no SwiftUI code modifications present, so the SwiftUI state layout check is not applicable.
Cmux Architecture Rethink ✅ Passed PR contains no Swift architecture changes—only CI workflow and test infrastructure updates. Custom check for Swift architectural violations is not applicable.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR contains no Swift files—only YAML workflows and Python/shell test updates. The check for Swift auxiliary window close-shortcuts is inapplicable to non-Swift changes.
Cmux Source Artifacts ✅ Passed All changed files are hand-written source code/configs (workflows, tests, scripts)—no generated artifacts, build output, caches, or temporary files enter source control.
Cmux No Test Or Debug Seam In Production Source ✅ Passed The PR modifies only CI/workflow configuration files (.github/workflows/ci.yml, .github/workflows/test-ios.yml) and test helper scripts (tests/test_ci_change_areas.py, tests/test_ci_self_hosted_gua...

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-ci-aggregate-gates

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Jun 20, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR addresses a recurring class of CI desync by introducing stable aggregate gate jobs whose needs: lists reference suite jobs by their YAML key rather than by display name, making the required-checks list immune to renames and shards.

  • ci.yml: Renames the sharded matrix job key tests → app-host-unit-tests and promotes tests-required-status → tests (keeping the same branch-protection check name); the tests gate now also blocks on swift-package-tests and agent-session-web-resources with correct skip-tolerant logic.
  • test-ios.yml: Adds a new ios-tests aggregate gate that requires detect-ios-changes to succeed and then allows success|skipped for package-conventions-lint, mobile-core-package, and ios-simulator — mirroring the tests pattern.
  • Test files: Updated test_ci_change_areas.py and test_ci_self_hosted_guard.sh to match the renamed job keys.

Confidence Score: 5/5

Safe to merge; the only post-merge action needed is manually adding ios-tests to the branch ruleset's required checks.

All changes are CI workflow mechanics — renaming job keys, wiring aggregate gates, and updating tests to match. The Python guard logic in both aggregate jobs correctly distinguishes success, skipped, and failure states, and the test file updates faithfully reflect every renamed key. No production code is touched.

No files require special attention; all four changed files are CI/test infrastructure with no production code impact.

Important Files Changed

Filename Overview
.github/workflows/ci.yml Renames sharded matrix job tests → app-host-unit-tests and the aggregate gate tests-required-status → tests; expands the tests gate to also block on swift-package-tests and agent-session-web-resources results, with correct skip-tolerant logic for both.
.github/workflows/test-ios.yml Adds new ios-tests aggregate gate mirroring the tests pattern; correctly requires detect-ios-changes to succeed and allows `success
tests/test_ci_change_areas.py Updates assertions in test_ci_status_job_accepts_skipped_routed_jobs and test_required_tests_status_waits_for_app_host_matrix to match the renamed job keys.
tests/test_ci_self_hosted_guard.sh Updates check_macos_runner call and inline comment to reference app-host-unit-tests instead of the old tests job key.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph ci.yml
        changes --> app-host-unit-tests
        changes --> swift-package-tests
        changes --> agent-session-web-resources
        app-host-unit-tests --> tests["tests (aggregate gate)"]
        swift-package-tests --> tests
        agent-session-web-resources --> tests
        changes --> tests
        tests --> ci-status
        app-host-unit-tests --> ci-status
        swift-package-tests --> ci-status
        agent-session-web-resources --> ci-status
    end

    subgraph test-ios.yml
        detect-ios-changes --> ios-tests["ios-tests (aggregate gate)"]
        package-conventions-lint --> ios-tests
        mobile-core-package --> ios-tests
        ios-simulator --> ios-tests
    end

    tests -->|"required check: 'tests'"| BP[Branch Protection]
    ios-tests -->|"required check: 'ios-tests' (add after merge)"| BP
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    subgraph ci.yml
        changes --> app-host-unit-tests
        changes --> swift-package-tests
        changes --> agent-session-web-resources
        app-host-unit-tests --> tests["tests (aggregate gate)"]
        swift-package-tests --> tests
        agent-session-web-resources --> tests
        changes --> tests
        tests --> ci-status
        app-host-unit-tests --> ci-status
        swift-package-tests --> ci-status
        agent-session-web-resources --> ci-status
    end

    subgraph test-ios.yml
        detect-ios-changes --> ios-tests["ios-tests (aggregate gate)"]
        package-conventions-lint --> ios-tests
        mobile-core-package --> ios-tests
        ios-simulator --> ios-tests
    end

    tests -->|"required check: 'tests'"| BP[Branch Protection]
    ios-tests -->|"required check: 'ios-tests' (add after merge)"| BP
Loading

Reviews (4): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile

Comment on lines +368 to +415
ios-tests:
name: ios-tests
# Aggregate gate for this workflow's iOS suites. Add this check to the branch
# protection required list (it is the iOS sibling of ci.yml's "tests" gate).
# References each suite by job KEY via needs:, so renaming or sharding a job
# never desyncs the required-checks list. Add new iOS jobs to needs: here.
needs:
- detect-ios-changes
- package-conventions-lint
- mobile-core-package
- ios-simulator
if: ${{ always() }}
runs-on: ${{ vars.LINUX_RUNNER || 'warp-ubuntu-latest-x64-4x' }}
timeout-minutes: 5
steps:
- name: Check iOS test routing
env:
IOS_NEEDS: ${{ toJSON(needs) }}
run: |
python3 - <<'PY'
import json
import os
import sys

needs = json.loads(os.environ["IOS_NEEDS"])

# The routing job must succeed for its should_run/should_lint outputs to
# be trustworthy; the suites below run or skip based on those outputs.
if needs["detect-ios-changes"]["result"] != "success":
print(f"detect-ios-changes: {needs['detect-ios-changes']['result']}", file=sys.stderr)
sys.exit(1)

# A suite that opted out via the routing filter reports "skipped", which
# is fine; a suite that actually ran and failed must block the merge.
allowed = {"success", "skipped"}
bad = {
name: data["result"]
for name, data in sorted(needs.items())
if name != "detect-ios-changes" and data["result"] not in allowed
}
if bad:
for name, result in bad.items():
print(f"{name} did not pass: {result}", file=sys.stderr)
sys.exit(1)

for name, data in sorted(needs.items()):
print(f"{name}={data['result']}")
PY

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 ios-tests required-check will block PRs that never trigger test-ios.yml

test-ios.yml has a paths: trigger filter. For a PR that touches only web/**, a server-side Go file, or any other path outside the listed patterns, the entire workflow never runs — meaning ios-tests produces no check status at all. GitHub reports the check as "Expected" (not "skipped"), and a required check that is absent blocks the merge.

The PR description says "skip = pass here," but that only describes jobs that opt out inside a running workflow (e.g., ios-simulator skipping because should_run=false). It does not cover the case where the workflow itself never triggers. If ios-tests is added to the ruleset's required list under the default "must be present and passing" mode, every web-only, Go-only, or other non-iOS-path PR will be permanently blocked.

The safe configuration options are: (a) switch the GitHub Ruleset entry to "required if triggered" / allow-if-skipped mode, or (b) remove the paths: filter from the on: pull_request: trigger so the workflow always runs and internal job conditions handle the skip logic (the same model ci.yml uses).

Removes the confusing name/key crossover left by #6464+#6474: a job KEYED
`tests` that reported as "app-host unit tests", plus a gate keyed
`tests-required-status` that reported as `tests`. Now the names line up:

- `app-host-unit-tests` (key) -> reports "app-host unit tests (N/4)" — the suite
- `tests` (key) -> reports "tests" — the required aggregate gate

No settings change: the gate still reports under the required name `tests`. The
two `needs:` references to the old matrix key (the gate and ci-status) and the
gate's needs["..."] lookup are updated accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
azooz2003-bit and others added 2 commits June 20, 2026 15:59
The job-key rename moved the macOS app-host matrix to `app-host-unit-tests` and
gave the key `tests` to the required aggregate gate. Update the guards that
asserted on the old keys:

- test_ci_self_hosted_guard.sh: assert the paid-macOS-runner requirement against
  `app-host-unit-tests` (the matrix), not `tests` (now a linux gate).
- test_ci_change_areas.py: ci-status routed-jobs list and the gate-block test now
  reference `app-host-unit-tests` (matrix) and `tests` (gate).

All workflow-guard-tests steps pass locally (self-hosted guard, change-areas,
sharding validator).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@azooz2003-bit
azooz2003-bit merged commit 2770d50 into main Jun 20, 2026
35 checks passed
@azooz2003-bit
azooz2003-bit deleted the feat-ci-aggregate-gates branch June 20, 2026 23:29

This branch was successfully deployed

1 active deployment
Preview – cmux — 9c882ec6 Deployed Jun 20, 2026 by vercel[bot]
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