Skip to content

Route Linux guard tests by owning group - #13585

Merged
teamleaderleo merged 12 commits into
mainfrom
ci/linux-guard-group-routing
Sep 22, 2026
Merged

teamleaderleo merged 12 commits into
mainfrom
ci/linux-guard-group-routing

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Sep 22, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • declare ownership for every workflow-guard-tests step and its directly executed inputs
  • add a per-diff linux_guard_test_groups route and expand only those matrix groups
  • keep unknown files and routing-policy edits fail-open to the full 11-group matrix
  • preserve the existing linux_guard_tests / Guard status required-check contract

Ownership / drift protection

scripts/ci/workflow_guard_groups.py is the declarative source for:

  • the ordered 11-group set
  • every group-conditioned guard-test step owner
  • directly executed guard inputs and known stable indirect inputs
  • broad Python-syntax and test-determinism scanners

tests/test_ci_linux_guard_routing.py compares that manifest back to ci-guards.yml, so moving a step between groups or adding a direct guard executable requires an ownership update in the same change.

Routing-policy files are also guarded in the caller before the PR-controlled detector runs; edits to the router, ownership manifest, reusable guard workflow, or routing contract tests emit the full group list.

Measurement: PR #13559

Measured from CI run 35683657111 (commit 39f90135), whose changed files are:

  • .github/workflows/ios-testflight.yml
  • ios/scripts/upload-testflight.sh
  • tests/test_ios_appstore_lane_identity.py

Current routing allocated all 11 workflow-guard-tests jobs. Their log spans sum to 315.021s = 5.25 runner-minutes.

The new ownership route selects:

  • preflight (workflow policy + Python syntax)
  • ci (repository reusable-workflow permission scan)
  • release-ios (TestFlight/App Store guards)
  • quality-determinism (test tree determinism scan)

Using the same run's per-group durations, that is 110.555s = 1.84 runner-minutes, saving 204.466s = 3.41 runner-minutes (64.9%) and 7 of 11 allocations (63.6%).

The guard-test wall span in that run was about 37.39s. The selected four span about 37.18s on the same timestamps because quality-determinism remains the critical parallel leg. This optimization removes unrelated runner work instead of shortening unrelated jobs.

Whole-run allocation

Across all successful allocated jobs in CI run 35683657111, log spans sum to about 600.375s = 10.01 runner-minutes across 22 jobs. Removing the seven unrelated guard-test legs yields a same-run counterfactual of 395.909s = 6.60 runner-minutes across 15 jobs: the same 3.41 runner-minute saving, or about 34.1% of total allocated runner time for this case.

The workflow itself ran from 03:34:28Z to 03:36:25Z (117s wall clock). The removed guard-test legs were off the overall critical path, so the modeled wall clock remains about 117s; the gain is runner capacity and cost, not a synthetic critical-path speedup.

Required-check behavior

The reusable workflow-guard-tests job still runs when linux_guard_tests == 'true', and Guard status still requires its aggregate result to be successful. Only the matrix vector changes.

This PR itself changes routing policy, so its own route intentionally fails open to all 11 groups; the narrow #13559 case is covered as a routing regression test.


Summary by cubic

Routes Linux workflow-guard-tests jobs to expand only the matrix groups that own the changed files instead of always running the full 11-group matrix, cutting CI time without changing the linux_guard_tests / Guard status required-check contract.

Routing and ownership

  • workflow_guard_groups.py declaratively maps every guard-test step and its directly executed inputs to an owning group.
  • The matrix now expands from the linux_guard_test_groups input rather than a hard-coded group list.
  • Unknown files and routing-policy edits fail open to all 11 groups so guard coverage is never silently reduced.

Drift protection

  • Tests compare the ownership manifest back to ci-guards.yml, so moving a step between groups or adding a direct guard executable requires an ownership update in the same change.
  • This PR edits routing policy, so its own route intentionally runs all groups.
  • A regression test pins the narrow route for a TestFlight change to preflight, ci, release-ios, and quality-determinism; that case saves 3.41 runner-minutes (64.9%) and 7 of 11 allocations.

Written for commit 6b96108. Summary will update on new commits.

Review in cubic

@coderabbitai

coderabbitai Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 39 seconds.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: ef6e7d78-9b4b-4bcb-9018-3a01ca250c25

📥 Commits

Reviewing files that changed from the base of the PR and between ef42fc4 and 6b96108.

📒 Files selected for processing (9)
  • .github/workflows/ci-guards.yml
  • .github/workflows/ci.yml
  • scripts/ci/detect_linux_guard_changes.py
  • scripts/ci/workflow_guard_groups.py
  • tests/test_ci_app_host_guard_structure.py
  • tests/test_ci_change_areas.py
  • tests/test_ci_linux_guard_routing.py
  • tests/test_ci_quality_guard_structure.py
  • tests/test_ci_release_guard_structure.py

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.

@github-actions

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@cursor

cursor Bot commented Sep 22, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@teamleaderleo
teamleaderleo enabled auto-merge (squash) September 22, 2026 04:21
@teamleaderleo
teamleaderleo merged commit 6cfa1b0 into main Sep 22, 2026
58 of 59 checks passed

Copy link
Copy Markdown
Collaborator Author

Post-merge integration regression to repair on current main:

#13535 added the Validate build graph health tooling preflight step, which directly runs tests/test_build_graph_health.py. The ownership manifest introduced here does not include that input, so test_guard_step_ownership_manifest_matches_workflow is now failing across unrelated PRs with:

AssertionError: 'tests/test_build_graph_health.py' not found ... ('Validate build graph health tooling', 'tests/test_build_graph_health.py')

Please land a small follow-up that assigns tests/test_build_graph_health.py (and its owning script if needed) to preflight in the declarative manifest and pins the integration with a regression. This is a main-branch CI contract drift, not something downstream PRs should work around.

teamleaderleo added a commit that referenced this pull request Sep 22, 2026
The Linux guard router kept a hand-written copy of every
workflow-guard-tests step (STEP_OWNERS) and every path those steps run
(PATH_OWNERS), and a test required the copy to equal the workflow. Two
PRs that each passed alone could land a copy that disagreed with the
workflow: #13535 added "Validate build graph health tooling" while
#13585 introduced the copy, and every PR failed guards until #13609.

Ownership now comes from the workflow. Each step's
`if: ${{ matrix.group == '<group>' }}` names its group and each path its
`run:` executes belongs to that group. The router reads ci-guards.yml
with a small line scanner, because the changes job runs on bare python3
without PyYAML; a test holds the scanner to yaml.safe_load field by
field. An unreadable workflow fails open to every group.

STEP_OWNERS is gone, and PATH_OWNERS keeps only the 24 indirect inputs
(imported scripts, the agent-chat working directory, the ghostty
submodule, skill files). Routing is unchanged for every path the old
tables knew. A step with an unknown group fails its own PR with the
exact file to edit.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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