Skip to content

CI: make verify runs in three legs, and a mutant its named tests miss is an error, not a whole-suite run - #666

Open
don-petry wants to merge 6 commits into
mainfrom
claude/verify-headroom-e6eddd
Open

don-petry wants to merge 6 commits into
mainfrom
claude/verify-headroom-e6eddd

Conversation

@don-petry

@don-petry don-petry commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

On 2026-11-09 merge group pr-657-a81e6e58 was cut at the checks step's 26 minutes, and the queue ejected #657, a diff that only touched fixtures. In the same run mutants (7) finished at 26.2 of its 27. This PR gives both legs at least 40% headroom on merge-group runs. It skips and weakens nothing: every test, every seed and every mutant still runs in every merge group, and the required check is still verify. needs_passed is unchanged.

Protected edits (.github/workflows/verify.yml, tools/check_workflows.py): pre-approved by the Maintainer 2026-11-08, ruled by the Factory Builder 2026-11-09. Design: option (a) with three legs, plus the mutant fix and its guard. No decision record, following #180's precedent; no rule of AGENTS.md's table changes.

What was slow (17 runs to 2026-11-09)

Leg Limit Took Cause
checks, one job 26 14.1–23.4 min; cut at 26.2 the whole suite in one process: test_tools 49%, test_simulator 40%, test_hooks 8%; checks 41 s
slowest mutants leg 27 13.8–26.1 min two mutants whose named test passes on them, so the leg ran the whole suite after it, for 10–21 min

The two mutants, found from the gaps in the job logs, with their killers found by running the whole suite on each:

  • "P-58 keeps the first head's status" (outlier legs in 5 of the last 6 runs): its named test passes; ReachScript.test_a_head_ends_where_the_next_line_is_no_head fails on it, in 1 s.
  • "the impostor workflow posts from the Lens's own file": its named test passes; Simulation.test_the_seeds_serve_items_with_an_acceptance_contract_and_without fails on it, in 5 s.

The change

  1. make verify in three legs. checks becomes a matrix, CHECKS_SHARD/CHECKS_SHARDS from strategy.job-index/job-total, as the mutant shards are set. Every leg runs every check. Its tests are every third test method of the whole suite, so across the legs every test runs once, all 300 seeds included. With neither variable set, make verify still runs everything, as at a desk. An unreadable leg (one variable without the other, not a number, or out of range) stops the run before anything else.
    Held by test_the_legs_of_make_verify_run_every_test_once (the shares partition the suite for 1, 2, 3 and 5 legs; the front door) and check_workflows._legs / test_the_legs_of_make_verify_are_told_their_place_and_count_by_the_matrix: the index and count come from the matrix and are never written in; the job's shape is closed, as the shards' is. The example and the standard's copy are changed to match.
  2. The two mutants name their killers.
  3. Guard: the mutant run (guarded → attempt(..., alone=True)) now runs a mutant's named tests alone. If they pass on it, the mutant is an ERROR, named_test_does_not_kill: … passed on it; name the test that fails on it, never a run of the whole suite. tools/untested.py still calls attempt without alone, so its edits still run the whole suite after their tests. Held by test_a_mutant_its_named_tests_miss_is_an_error_and_never_runs_the_whole_suite.

Each new rule has its mutant: 7 for _legs, 5 for the legs in tools/verify.py, and 4 for the guard. Two existing targets moved with the line they mutate. A filtered run of the 21 new and moved mutants killed all of them.

tools/AGENTS.md lost a line of prose, so that the guard's row fits its 40 lines.

Runner-minutes per run

  • Before: 134–164 over 15 jobs, median 143 (the last ten runs).
  • After: 140 over 17 jobs on this PR's run at 35673e9 (run 42565323152). The slowest checks leg took 9.1 of 26 (65% headroom) and the slowest mutants leg 14.4 of 27 (47%). The first runs dealt the legs unevenly: tests took 309, 355 and 675 s at 5524e9d, because round-robin put the slow simulator tests on two legs. The slowest leg there was still 11.9 of 26 (54%).

Verification

  • make verify on an export of 35673e9: 1,719 tests, OK (8 expected failures), exit 0.
  • python3 -m tools.mutants: CI's twelve shards, all green at 35673e9. On the first run, the guard caught a third misnamed mutant. "exactly on the bar does not clear it" now names test_each_kind_is_held_to_its_own_bar_where_the_cases_are, which holds the bar exactly.

Reviews

  • At 5524e9d: Argon clean (10 of 10 parts), Muse clean, Claude security review clean. The Claude review raised two minors, both fixed in 74753ff:
    • The impostor mutant's new killer failed only at the mutant run's 40 seeds. The test it named before now asserts, after every step, that the Lens's own App never posts from the Lens's own file. It kills the mutant at 5, 40 and 300 seeds, and the mutant names it again. This edits tests/test_simulator.py, a protected path, and only strengthens it.
    • A named test that fails once and then passes was told as named_test_does_not_kill. It is SURVIVED again, as before the guard, with a mutant for the difference.
  • Later commits: b4b4c15 puts a test's injected env key into checks' own env:, since the legs gave it one. 35673e9 has the guard's catch above and a mutant target moved with the renamed loop.

After the merge, three consecutive merge-group runs will be reported, each with the slowest checks leg and the slowest mutants leg against their limits.

🤖 Generated with Claude Code

don-petry and others added 3 commits November 8, 2026 21:47
… kill them

"P-58 keeps the first head's status" and "the impostor workflow posts from the Lens's own file" each named a test
that passes with the mutant in place, so their legs ran the whole suite after it: 10 to 21 minutes of a 27-minute
step, the slowest leg of five of the last six merge-group runs. Each now names the one test the whole suite fails on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… by the matrix

On 2026-11-09 merge group pr-657-a81e6e58 was cut at the checks step's 26 minutes, and the ten runs before took 19 to
23.4. checks becomes a matrix of three legs, as the mutants are: each leg runs every check and every third test of the
whole suite, told CHECKS_SHARD and CHECKS_SHARDS by strategy.job-index and job-total, never by a number written in, so
across the legs every test runs once, the 300 seeds included. verify still needs checks, whose result is every leg's.

tools/check_workflows.py holds the legs' job as it holds the shards' (_legs); tools/verify.py refuses a leg it cannot
read before any check runs, and runs every test where neither is set, as at a desk. Each new rule has its mutant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ll, never a run of the whole suite

The mutant run holds each mutant to the tests it names, alone: when they pass on it, it is an ERROR that names them,
where before the whole suite ran after them, 10 to 21 minutes of a 27-minute leg, and hid the wrong name. An edit
tools/untested.py tries, through attempt without alone, still runs the whole suite after its tests. The verify
workflow's comment, its example and the standard's copy say so; the guard has its test and four mutants.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@don-petry
don-petry requested a review from a team as a code owner November 9, 2026 04:17
@chatgpt-codex-connector

Copy link
Copy Markdown
Codex Review Summary: ❌ Failed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ❌ Failed 2026-11-09T04:17:55.379125Z
We couldn’t complete this review. Comment @codex review to try again.
5524e9d PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Nov 9, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

don-petry and others added 3 commits November 8, 2026 22:32
…y named test stays SURVIVED

The Claude review of #666 found that the impostor mutant's new killer failed on it only at the mutant run's 40 seeds,
not at the 300 make verify runs. The test the mutant named before now pins what the mutant breaks: the Lens's own App
never posts from the Lens's own file, checked after every step, so it fails on the mutant at 5, 40 and 300 seeds; the
mutant names it again. And a named test that failed once and then passed was told as named_test_does_not_kill: it is
SURVIVED again, as before the guard, with a mutant for the difference.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he legs gave one

test_a_key_and_its_environment_are_named_by_their_one_file wrote an env: into the first job with contents: read, which
was checks; checks now has an env: of its own, so the key is put in it, not in a second.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ant follows its rename

On this pull request's run the guard told "exactly on the bar does not clear it" as named_test_does_not_kill: the gate
test it named passes on it, and test_each_kind_is_held_to_its_own_bar_where_the_cases_are, which holds the bar exactly,
fails on it. And "an unconfirmed failure is FLAKY with no second run" mutates the loop the review's fix renamed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Nov 9, 2026

Copy link
Copy Markdown

This branch has not been deployed

No deployments
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