Repository navigation
Add a ci job for the main ruleset to require, and raise four timeouts - #1565
Merged
Merged
Conversation
ci job that one branch-protection check can requireci job that one branch-protection check can require, and raise the engine-free cap
ci job that one branch-protection check can require, and raise the engine-free capci job the main ruleset can require, have lint check it, and raise four job timeouts
MaxGhenis
force-pushed
the
ci-aggregate-check
branch
from
November 10, 2026 05:33
573283f to
f9e8ce0
Compare
ci job the main ruleset can require, have lint check it, and raise four job timeoutsci job for the main ruleset to require, and raise four timeouts
MaxGhenis
force-pushed
the
ci-aggregate-check
branch
from
November 10, 2026 06:31
f9e8ce0 to
1efead5
Compare
`ci` gives the main ruleset one check that covers the country jobs. It needs every other job, runs with `if: always()`, and fails unless each job passed, or skipped because select-countries succeeded and reported `false` for its country. A skipped matrix job reports under its unexpanded name, so a ruleset cannot require engine-us or engine-uk by name. The plan names the jobs the selection may leave out: those whose test groups all need the same country's engine. `require-results` takes its jobs from the plan and reads nothing from the workflow. A new `verify-workflow` command, which the lint job runs, parses the workflow with PyYAML. Its loader refuses two keys that PyYAML reads as one, a merge key, and U+0085, U+2028 or U+2029. The command then refuses: - a job outside the plan, a plan job the workflow lacks, and a job whose `if` differs from the plan's; - a job the selection may leave out that doesn't need select-countries, and a job that needs one the selection may leave out without it; - a `ci` job that lacks `if: always()`, omits a job from `needs`, or does anything but check out the repository and run `require-results`; - a select-countries job that doesn't publish its plan step's outputs; - `continue-on-error` on any job or step, a step `if` other than `always()`, `success()` or `!cancelled()`, and a job-level `name`; - a workflow `defaults` other than `run: shell: bash`, a job-level `defaults` and a step `shell`. The workflow now sets `defaults: run: shell: bash`. GitHub runs an explicit `shell: bash` as `bash -eo pipefail`, and a step with no shell as `bash -e`, where a pipe hides the exit status of the command that feeds it. The ruleset also names both engine-free legs, and engine-free runs the plan's tests, so a change that breaks `ci` fails a check the ruleset reads without `ci`. `verify` refuses a plan whose tests engine-free would not run. The tests run the tool as a script, the way the workflow does, so a dead entry point fails them. select-countries now selects both countries for a pull request whose file listing reaches GitHub's 3,000-file limit. Raise four timeouts to at least 1.5 times each job's slowest successful leg on 2026-11-09: engine-free to 165 minutes (109), engine-us to 110 (73), engine-uk to 90 (45) and integration-uk to 20 (8). Co-Authored-By: Claude <noreply@anthropic.com>
MaxGhenis
force-pushed
the
ci-aggregate-check
branch
from
November 10, 2026 06:52
1efead5 to
2782c2c
Compare
MaxGhenis
marked this pull request as ready for review
November 10, 2026 08:41
Contributor
Author
|
I merged this at 2782c2c. All 12 checks passed on that head, including |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Main has no required checks today, so a PR can merge with no CI run on its head. For example, a stacked PR that retargets to main gets no run, because GitHub starts none for a base change. I decided to require passing CI on a PR's head before it merges into main. This PR adds a
cijob that gives themainruleset one check covering the country jobs. It also raises four job timeouts, since a job that times out will block a merge once the ruleset requires CI.What changes
.github/workflows/test.ymlgains acijob. It needs every other job, runs withif: always(), and passes GitHub'sneedscontext topython3 tools/ci_test_plan.py require-results.require-resultsfails unless each job in the test plan reportedsuccess, orskippedbecauseselect-countriessucceeded and reportedfalsefor the job's country. The plan names the jobs the selection may leave out:engine-us,engine-ukandintegration-uk, whose test groups all need the same country's engine.tools/ci_test_plan.py verify-workflow, after it syncs the workspace. The command parses the workflow with PyYAML and refuses:<<), and U+0085, U+2028 or U+2029, which YAML 1.1 reads as line breaks and YAML 1.2 doesn't;ifdiffers from the one the plan gives it;select-countries, and a job that needs one the selection may leave out, unless both follow the same country's selection;cijob that lacksif: always(), omits a job fromneeds, or does anything but check out the repository and runrequire-resultson itsneedscontext;select-countriesjob that doesn't publish the outputs itsplanstep writes;continue-on-erroron any job or step, a stepifother thanalways(),success()or!cancelled(), and a job-levelname;defaultsother thanrun: shell: bash, a job-leveldefaultsand a stepshell.defaults: run: shell: bash. GitHub runs an explicitshell: bashasbash -eo pipefail, and a step with no shell asbash -e, where a pipe hides the exit status of the command that feeds it.tools/ci_test_plan.py verify, which lint already runs, now refuses a plan whose own testsengine-freewould not run.select-countriesnow selects both countries for a PR whose file listing reaches GitHub's 3,000-file limit, since the listing stops there.docs/agent-guide.mddescribesciandverify-workflow, and says that retargeting a stacked PR to main starts no run.Why
ci, and what checks itA ruleset can't require
engine-usorengine-ukby name. A matrix job that runs reports asengine-uk (3.13)andengine-uk (3.14), and one that skips reports asengine-uk, so a US-only PR never produces the two names a ruleset would wait for.cireports one result for all the jobs, so a ruleset that requirescicovers the country jobs.GitHub counts a skipped required check as passing ("A job that is skipped will report its status as 'Success'", per its docs on job conditions), so
ciruns withif: always(). An edit that letsciskip would leave it passing, and so would an edit that makesrequire-resultspass a failed job. The plan's tests catch both. They run inengine-free, and the ruleset keeps naming bothengine-freelegs, so their failure blocks the merge without passing throughci. The tests also run the tool as a script, the waycidoes, so a dead entry point fails them.History
María added a
ci-okjob for the same reason on 2026-08-25 (404e457). It accepted a lane's skip only when classification succeeded. #1048 removed it on 2026-09-29 when it unified test orchestration, and #888 added and removed one again on its branch. Neither PR says why it removed the job. This PR keeps María's rule, declares the job in the test plan's registry of infrastructure jobs, and puts the logic intools/ci_test_plan.py, where pytest covers it.Invariants
cireports one error for each job that neither passed nor skipped because the selection succeeded and reportedfalsefor it. Two property tests and an exhaustive test of 38,880 combinations on a five-job plan check that against an independent statement of the rule.ci(a property test).verify-workflowpasses a workflow only when it breaks none of the rules listed above. One property test checks the rules on jobs and steps against an independent statement of them, and another checks that a workflow keeps passing through changes no rule reads.Limits
verify-workflowreads the workflow as PyYAML does. GitHub's own parser could read a file differently.cichecks each job's result, and a job decides its own result. A test step that swallows a failure, for example with|| true, still passes, and so does a runner script that exits 0 after a failed test.engine-freelegs, so a change to that job's matrix needs a ruleset change with it. A test pins the names.Rollout
A ruleset on main (id 26905965) logs what it would block and blocks nothing yet. Once active it requires six checks that run on every PR:
lint,wheels,select-countries,installed-emitterand bothengine-freelegs. I'll addcito that list after this lands and open PRs have run with the job. GitHub runs a PR's workflow on its merge with main, so an open PR gainscion its next push, or when someone closes and reopens it. Re-running a run from before this lands reuses that run's commit and adds noci, while re-running failed jobs in a later run re-runscitoo. A PR that adds a job must add it to the plan and toci'sneeds, orlintfails.Tests
test_ci_test_plan.pyandtest_ci_integration_job.py: 225 tests pass locally.tools/ci_test_plan.pyat a time, 81 variants in all, and a test failed for each.ruff checkandruff format --checkpass on the touched files.python3 tools/ci_test_plan.py verifyprintsverification=ok, andverify-workflowprintsworkflow=ok.axiom: n/a: CI infrastructure
🤖 Generated with Claude Code