Skip to content

ci(mutants): run the lane once a night on main, never on a push - #24

Open
systemfsoftware-maker wants to merge 5 commits into
mainfrom
ci/mutants-nightly
Open

systemfsoftware-maker wants to merge 5 commits into
mainfrom
ci/mutants-nightly

Conversation

@systemfsoftware-maker

@systemfsoftware-maker systemfsoftware-maker commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

The Mutants lane stops running on every push to main. It now runs once a night on main at 03:17 UTC (cron: "17 3 * * *") and on workflow_dispatch. A red night opens a fix task. This follows ci-wall-clock/mutation-runs-nightly-on-main, which #23 enrolled. Plan: docs/plans/2026-10-13-2100-ci-mutants-nightly-plan.md.

What changes

  • Triggers. schedule and workflow_dispatch only. The push trigger is gone. The rule never on a pull request from R21 of the standalone plan still holds. The run name is Mutants <sha>, plus for <night> on a re-test.
  • Dispatch inputs. sha (a commit main reaches, 40 hex digits; empty means main's tip), packages (a JSON array of package names; empty means every package) and night (the run id a re-test is for; a re-test resumes nothing). The old mode and base inputs are gone.
  • Main-only guard. A guard job refuses any ref that is not the default branch (mutants-off-main), a malformed or unreachable sha (mutants-sha-invalid, mutants-sha-off-main) and a malformed night (mutants-night-invalid) before anything installs. Every other job needs it.
  • No main-side cancellation. Each run is its own concurrency group (mutants-${{ github.run_id }}, cancel-in-progress: false). The old setup keyed groups by commit and ref, so with GitHub's default queue: single a third run in a group cancelled the one still pending, and two dispatches on main could replace each other.
  • Jobs aim at 10 minutes. The plan predicts each shard's load from the newest measured run's per-file mutant times and per-shard overhead, then picks the fewest round-robin shards whose heaviest load fits 600 s. Every job keeps the 60-minute backstop and writes its wall time to the step summary. A job over 600 s is marked in the night's job table.
  • Shards restore main's Nix store bundle and take their tools from the new packages.x86_64-linux.gritlint-mutants-tools, not from a dev shell.
  • Night scope. A night tests the diff from the last green night. It tests everything when there is no green night, when that night's commit is not an ancestor, or when the range changed one of the lane's inputs: mutants.yml, .cargo/mutants.toml, either script, flake.lock, flake.nix or rust-toolchain.toml.
  • Night record and fix task. No triage workflow exists yet, so the report job writes the record artifact mutants-night-<run id> itself. On a red night it updates the open fix task that already names a survivor or failure, files a new task for anything no task names (listing every merge in the range as a candidate, with the opener mentioned and a reproduce command), and ends red. A green night writes one line. The decisions live in scripts/tools/mutants-plan.sh and the new scripts/tools/mutants-night.sh. checks.<system>.gritlint-mutants-plan runs both decision tables.

Proof before merge

# Check Result
V1 Decision tables checks.x86_64-linux.gritlint-mutants-plan builds locally. On CI run 38473088412 the x86_64 job built it: 72 ok lines, all passed twice.
V2 actionlint and shellcheck actionlint .github/workflows/mutants.yml exit 0. shellcheck -S warning scripts/tools/mutants-*.sh exit 0.
V3 Tools without a dev shell (list-only) cargo mutants --workspace --list through gritlint-mutants-tools lists 627 mutants, byte-identical to the dev shell's list. --shard k/3 --sharding round-robin gives list[k::3] line for line. cargo test --workspace --no-run --offline builds with only that package on PATH.
V4 Sizing over real artifacts Planned over the 627-mutant list: run 38447766912's timings (overhead 471 s, mean 19.1 s) give 93 shards, heaviest 599 s, 900 job-min. Run 38130956835's (203 s, 9.5 s) give 16 shards, heaviest 595 s, 157 job-min. With no artifacts left, the model gives 105 shards, heaviest 585 s, 1023 job-min.
V5 PR CI Green at 5f88dbeac. The head shows no Mutants run. Times below.
Rehearsal Night decisions over run 38447766912's real outcome files verdict gives red with caught 105, unviable 50, missed 10, timeout 21, complete. route with no open task files the 10 survivors. The rendered task routes back to itself on the next night.

No mutant was built or run locally. cargo mutants ran only with --list.

CI job times (jobs API, run 38473088412 and Changeset Check 38473088832)

Job Wall time
Nix · x86_64-linux 3m59s
Nix · aarch64-linux 1m42s
A change under crates, apps or packs adds an intent 8s
Tarball and binaries match across systems 6s
changeset · shared tooling / a publishable-package change needs an intent 1m59s

Proof after merge

# Check Owner and trigger
V6 The first schedule run after merge, the night of the merge day at 03:17 UTC: title, guard success, plan summary, every shard's wall time, the mutants-night-<id> artifact, then the task or the green line Cited by run id in a comment on this PR the morning after merge.
V7 A workflow_dispatch on main runs, and one on a branch is refused by guard with mutants-off-main The operator dispatches both. This session's token cannot: POST …/actions/workflows/mutants.yml/dispatches returns HTTP 403 Resource not accessible by personal access token.

The first night tests everything (no green night yet). Its predicted price is in the workflow's cost header: 93 shards and 900 job-min from run 38447766912's timings, and 25 shards and 236 job-min if the store restore brings the overhead down to about 160 s.

Review receipt

Full-path ce-code-review, run 20261013-204731-a3bd48a6, base 3919672c8 (main, #23), reviewed head af068a080. Eight reviewers ran: correctness, project-standards, testing, maintainability, learnings, reliability, security, and the cross-model adversarial peer. Every reviewer returned and none timed out. Turns served, from each reviewer's session transcript:

Reviewer Model served Turns Wall time
correctness deepseek/deepseek-v4.1-flash 36 10m30s
project-standards deepseek/deepseek-v4.1-flash 22 2m18s
testing deepseek/deepseek-v4.1-flash 20 1m09s
maintainability deepseek/deepseek-v4.1-flash 20 1m33s
learnings deepseek/deepseek-v4.1-flash 33 5m29s
reliability deepseek/deepseek-v4.1-flash 26 2m58s
security deepseek/deepseek-v4.1-flash 32 3m51s
adversarial peer (cross-model) deepseek/deepseek-v4.1-flash 19 7m06s
adversarial delta pass over the fixes deepseek/deepseek-v4.1-flash 7m24s
validator (P1) deepseek/deepseek-v4.1-flash 1m51s
body check of this description deepseek/deepseek-v4.1-flash 3m46s

No Grok or xai model served any turn. The body check filed two P3s (which head the Item column's line numbers refer to, and a shortened job name); both are fixed here. The peer ran as an omp subagent, not through CE's peer runner, so CE records independence_verified: false, and its findings took no promotion bonus.

Verdict. The review found five primary findings at af068a080: one P1, three P2, one P3. The validator confirmed the P1. CE's report leaf wrote "Ready to merge", but an open P1 caps the verdict at "Ready with fixes" under CE's own rule, so the verdict at af068a080 is Ready with fixes. All five are fixed: #1 to #5 in 74de64575. The delta pass checked all eight findings the reviewers filed and found each one fixed at 74de64575. Its three P3 regressions are fixed in 5f88dbeac. 1be5a6a41 adds a verdict-to-route test.

Every finding, risk and gap, ruled

Each item is fixed by a named commit, rejected with its evidence, or given an owner and a trigger. Line numbers in the Item column are the reviewers', at the reviewed head af068a080. Line numbers in the Ruling column are at the final head 5f88dbeac.

# Reviewer Kind Item Ruling
1 correctness finding Night jobs listing read unpaginated; table and sizing lose jobs Fixed in 74de64575: both jobs reads paginate (mutants.yml:208-209, :417-418). Live check over run 38447766912 at per_page=10: all 23 jobs came back.
2 correctness residual risk A night-tagged re-test dispatch, the plan's triage hook, writes no record and cannot end red: record, route, upload-record and verdict are g… Rejected. A re-test dispatch belongs to the triage the rule names; this lane has none yet (plan Scope Boundaries). Its survivors still show in the shard and outcome step summaries, and a dispatch's own run is red when a shard fails.
3 correctness residual risk Both the resume and the timing steps list a run's artifacts with per_page=100 (mutants.yml:158, 176) while a night may upload more than 99 shard art… Fixed in 74de64575: both artifacts reads paginate (mutants.yml:180-181, :199-200).
4 correctness residual risk route reads the open tasks with per_page=100 (mutants.yml:428) while tasks are filed on every red night and the lane never closes them; past 100 o… Fixed in 74de64575: the open-issues read paginates (mutants.yml:466-467).
5 correctness residual risk The refusal the plan tests assert for a malformed artifacts response (mutants-plan.test.sh, artifacts: an API error body is a failure) is bypassed a… Fixed in 74de64575: $PLAN artifacts writes its own file and fails the step on a bad body. Only the grep for shard names may continue (mutants.yml:201-202).
6 correctness testing gap No test covers the artifact and argument handoff between the plan, shard and report jobs: plan/args, plan/mutants.diff, the `mutants-plan-<a… Rejected as a new test. Running the workflow's gh glue needs a test harness over the GitHub API, which is a new CI gate; this repo admits a gate only with operator sign-off (GATE1). The glue is proved by the first scheduled night and the two dispatches after merge (plan V6, V7), which the post-merge comment cites by run id.
7 correctness testing gap No test covers verdict or route for a night whose shards uploaded artifacts from two run attempts at once, the shape a re-run attempt produces (`p… Rejected. merge unions every directory it is given and does not read names (mutants-plan.sh merge, covered by the merge cases in mutants-plan.test.sh), so two attempts' shard directories merge like any two shards.
8 project-standards finding gh api effect lives inside the pure decision script Fixed in 74de64575: last_green is gone from mutants-night.sh. The plan job makes the gh calls and calls the pure nights and green-record (mutants.yml:152-167).
9 project-standards residual risk CONST-T12 boundary: the full-run trigger list (scripts/tools/mutants-plan.sh:5-11, FULL_RUN_TRIGGERS) decides a full night from file paths, so renamin… Rejected. A rename of a trigger file edits mutants-plan.sh (it holds the list), and that script is itself a trigger, so the rename night runs everything.
10 project-standards residual risk The workflow's own gh-call steps (plan's resume and timings fetch, report's record/route/report) have no test; only the decision scripts and actionlin… Rejected as a new test. Running the workflow's gh glue needs a test harness over the GitHub API, which is a new CI gate; this repo admits a gate only with operator sign-off (GATE1). The glue is proved by the first scheduled night and the two dispatches after merge (plan V6, V7), which the post-merge comment cites by run id.
11 project-standards testing gap No test covers the workflow glue that invokes the scripts (resume, timings fetch, record/route/report steps); a regression in the YAML -- wrong artifa… Rejected as a new test. Running the workflow's gh glue needs a test harness over the GitHub API, which is a new CI gate; this repo admits a gate only with operator sign-off (GATE1). The glue is proved by the first scheduled night and the two dispatches after merge (plan V6, V7), which the post-merge comment cites by run id.
12 project-standards testing gap last-green (scripts/tools/mutants-night.sh:161-179) has no decision table; its gh pagination and artifact download are exercised by no test. Fixed in 74de64575 by removal: last-green no longer exists; nights and green-record have decision tables.
13 testing finding task-body emits route's machine-parsed marker with no test Fixed in 74de64575: a test files a task-body output, finds it with tasks and routes the next night to it (mutants-night.test.sh:126-133).
14 testing residual risk mutants.yml's inline steps are covered only by actionlint (clean, verified), not by executing against fixtures: the timings step's selection of the ne… Rejected as a new test. Running the workflow's gh glue needs a test harness over the GitHub API, which is a new CI gate; this repo admits a gate only with operator sign-off (GATE1). The glue is proved by the first scheduled night and the two dispatches after merge (plan V6, V7), which the post-merge comment cites by run id.
15 testing residual risk The verdict→route record schema (keys items/planned/missed) is asserted on each side with independently hand-built fixtures; no test feeds a verdict… Fixed in 1be5a6a41: one case feeds verdict's record into route (mutants-night.test.sh:135-141).
16 testing testing gap mutants-night.sh's task-body, comment-body, mentions, reproduce, green-line and last-green subcommands have no test coverage at all; only nights, gree… Partly fixed in 74de64575 (task-body's machine-read part is now tested). Rejected for comment-body, mentions, reproduce and green-line: their output is prose for people, and a test of wording is banned here.
17 testing testing gap The workflow's timing-source selection (newest completed main run that actually carries mutants.out-- artifacts, and choosing the high… Rejected as a new test. Running the workflow's gh glue needs a test harness over the GitHub API, which is a new CI gate; this repo admits a gate only with operator sign-off (GATE1). The glue is proved by the first scheduled night and the two dispatches after merge (plan V6, V7), which the post-merge comment cites by run id.
18 testing testing gap No end-to-end case composes verdict output with route input, so the record.json contract shared between the two subcommands is unverified. Fixed in 1be5a6a41 (same case as 15).
19 maintainability finding Task marker literal duplicated across workflow and script Fixed in 74de64575: the marker lives only in mutants-night.sh:5, and the workflow calls $NIGHT tasks (mutants.yml:468).
20 maintainability residual risk mutants.yml:414 -- for commit in $(git log --first-parent --format=%H "${green:+$green..}$TARGET") degenerates to git log --first-parent $TARGET w… Fixed in 74de64575: with no green night, the record walks at most 20 commits (mutants.yml:448-452). Since 5f88dbeac, the task also says that older merges are not named.
21 maintainability residual risk The four Job report steps (guard, plan, shard, report) repeat identical if: always() + STEPS/printf steps.json + $PLAN job-report boilerplat… Rejected. GitHub Actions has no step reuse without a composite action, which would add a fourth file for four short steps; a missing code degrades to unclassified, never to a silent pass.
22 maintainability testing gap No decision-table test covers the timings step's newest-attempt selection (.github/workflows/mutants.yml:177-182): `grep -E ' mutants.out-[0-9]+-[0-9… Rejected as a new test. Running the workflow's gh glue needs a test harness over the GitHub API, which is a new CI gate; this repo admits a gate only with operator sign-off (GATE1). The glue is proved by the first scheduled night and the two dispatches after merge (plan V6, V7), which the post-merge comment cites by run id.
23 maintainability testing gap The report job's merge-range construction (.github/workflows/mutants.yml:414) and the route step's task-number accumulation (mutants.yml:432-445) are … Rejected as a new test. Running the workflow's gh glue needs a test harness over the GitHub API, which is a new CI gate; this repo admits a gate only with operator sign-off (GATE1). The glue is proved by the first scheduled night and the two dispatches after merge (plan V6, V7), which the post-merge comment cites by run id.
24 learnings residual risk Cost-header fallback: the header prices the first night at 93 shards / 900 job-min from run 38447766912's per-file timings, but the shipped no-artifac… Fixed in 74de64575: the cost header now prices the fallback at 105 shards and 1023 job-min (mutants.yml:10-11). That is what mutants-plan.sh shards printed for the 627-mutant list.
25 learnings residual risk The cargo-mutants round-robin index rule (list[k::n]) the shard-load prediction depends on is pinned only by the doc's manual list-only probe (docs/so… Follow-up owner: whoever bumps cargo-mutants in flake.lock. Trigger: that bump; the solution doc's Verification section names the list-only probe to re-run, and a flake.lock change also forces a full night. An executable check would be a new gate (GATE1).
26 learnings residual risk FULL_RUN_TRIGGERS (mutants-plan.sh:5-11) lists .cargo/mutants.toml, the workflow, both scripts and flake.lock, but not flake.nix, which composes gritl… Fixed in 74de64575 (flake.nix and rust-toolchain.toml added) and tested in 5f88dbeac (mutants-plan.test.sh:90-91).
27 learnings residual risk Steps without an id (the shard job's 'Outcomes' and 'Upload mutants.out', and every job's trailing 'Job report') are absent from the steps context, so… Fixed in 74de64575: the shard's outcome and upload steps have ids and reason codes (mutants.yml:345, :348).
28 learnings residual risk The workflow's job graph, permissions, per-job timeouts and summary lines are verified only by actionlint (V2) plus the scripts' decision tests; nothi… Rejected as a new gate (GATE1). A step without a code reports unclassified and still names the step.
29 learnings testing gap No test exercises the workflow's job graph: that every job carries timeout-minutes: 60, that the report job's Job-report table covers each step id in … Rejected as a new gate (GATE1). Every job's timeout-minutes: 60 is read in review; actionlint is clean.
30 learnings testing gap No test covers the timings model-vs-measured boundary beyond fixtures: the branch deriving per-shard overhead from the jobs API (shard wall time minus… Rejected. The fallback is tested: mutants-plan.test.sh:144-146 (timings: nothing measured falls back to the labelled model).
31 learnings testing gap No test asserts the header's daily-cost figures against what the shipped plan prints for the two documented night shapes, so the header numbers can dr… Rejected. The header is a comment; a test of comment text is banned here.
32 reliability finding Artifact/job listings capped at 100 with no pagination Fixed in 74de64575 (same as 1 and 3).
33 reliability residual risk Best-effort history reads are fatal: the plan's resume (mutants.yml:150-168) and timings (173-188) steps run under set -euo pipefail, so one tra… Rejected. A failed history read ends the plan red with its step and code named (mutants-plan-history), which the failures rule wants; falling back silently would turn one API error into a full night of about 900 job-min.
34 reliability residual risk Night-record artifact name ignores the attempt: mutants-night-${{ github.run_id }} (mutants.yml:410) while resume_runs explicitly handles `attempt… Fixed in 74de64575: the record upload sets overwrite: true (mutants.yml:495). The pinned action's README says that without it, a name collision fails the upload.
35 reliability residual risk When there is no green night (the expected state until F1 lands), the record step walks every first-parent commit of main and issues one `gh api .../c… Fixed in 74de64575 (same as 20).
36 reliability testing gap The workflow wiring has no automated test -- the guard's GITHUB_REF/DEFAULT values, the report job's toJSON(needs) -> failures mapping, and the … Rejected as a new test. Running the workflow's gh glue needs a test harness over the GitHub API, which is a new CI gate; this repo admits a gate only with operator sign-off (GATE1). The glue is proved by the first scheduled night and the two dispatches after merge (plan V6, V7), which the post-merge comment cites by run id.
37 reliability testing gap timings has no case where a succeeded shard is present in the jobs API but its outcomes.json is missing (a partially uploaded run); that path sile… Rejected. A shard that succeeded without outcomes.json would lower the overhead estimate; the next run's jobs table marks any job over 600 s as over the target, so the miss is loud and the next night's timings correct it.
38 security residual risk Store paths are imported with signature verification off, so the mutants jobs trust the Actions cache rather than Nix for the toolchain they execute. … Rejected. The mutants jobs import the bundle the same way ci.yml does on main (nix copy --no-check-sigs: ci.yml:71, mutants.yml:133, :314). Since #17, only the default branch exports and saves that key (ci.yml:96, :107).
39 security residual risk The guard's ref and sha checks are the only validation of the dispatch inputs, and one half of them is self-referential. `scripts/tools/mutants-plan.s… Rejected. The guard stops a dispatch on the wrong ref before anything installs, which is what the rule asks; a user with write access can edit any workflow, so no in-workflow check can stop them.
40 security residual risk A merged pull request's title is rendered raw into markdown in the issue the night files. scripts/tools/mutants-night.sh:135 builds ` ($merges[… Rejected. The titles come from pull requests already merged to main by users with write access, and GitHub renders issue bodies without scripts.
41 security testing gap Nothing in the repository fails if a future edit interpolates a dispatch input straight into a run: script instead of routing it through an environm… Rejected as a new gate (GATE1). Every dispatch input reaches bash through env: (mutants.yml:60-61, :96-97), and review checks that.
42 security testing gap The gate that keeps the other jobs behind the guard is unverified outside reading the YAML. shard (.github/workflows/mutants.yml:255: ` if: nee… Rejected. GitHub skips a job that needs: guard when the guard fails, unless the job's if: calls always(). Only report calls it, and its if: also requires needs.guard.result == 'success' (mutants.yml:373).
43 adversarial-deepseek finding Cascade: a re-run of a night collides on the record artifact name, so the verdict is skipped and a green night is filed as a failed run Fixed in 74de64575 (same as 34); the validator confirmed it at af068a0.
44 adversarial-deepseek finding Cascade: one transient gh API failure in the merges loop drops the red night's task, record and verdict together Fixed in 74de64575: a failed pulls lookup yields [], and that commit is left unattributed (mutants.yml:454).
45 adversarial-deepseek finding First red night @-mentions every contributor in the repository's history Fixed in 74de64575 (same as 20).
46 adversarial-deepseek residual risk jobs-per_page cap vs shard ceiling: mutants.yml:183 (.../runs/$run/jobs?per_page=100) and mutants.yml:391 (`.../attempts/$GITHUB_RUN_ATTEMPT/jobs?pe… Fixed in 74de64575 (same as 1).
47 adversarial-deepseek residual risk The lane's first-night behavior is asserted but never exercised: the plan's V6/V7 are post-merge observer checks, and nothing in the tree records a re… Rejected. cargo-mutants 27.1.0 --list --json over this tree, through the new tools package, gives 627 objects, each with package: "gritlint_core", the shape packages reads.
48 adversarial-deepseek residual risk record's merges loop and last-green together make up the report job's API budget: one call per first-parent commit plus up to 50 x 2 calls in last… Fixed in 74de64575: the candidate walk is at most 20 commits. The green lookup lists only nights that ended success, and a red night's report fails its run, so the first unexpired record it reads is normally green.
49 adversarial-deepseek testing gap No case in the review's verification contract covers a re-run (attempt > 1) of a schedule night end to end, which is the path where the record artifac… Follow-up owner: the operator. Trigger: the first schedule night that is re-run; its run id goes in the post-merge comment. The PAT here cannot re-run or dispatch (HTTP 403, below).
50 adversarial-deepseek testing gap No fixture drives the no-green-night path through record/route (empty green => unbounded git log and a task with no named range); the tests cove… Rejected as a new test. Running the workflow's gh glue needs a test harness over the GitHub API, which is a new CI gate; this repo admits a gate only with operator sign-off (GATE1). The glue is proved by the first scheduled night and the two dispatches after merge (plan V6, V7), which the post-merge comment cites by run id.
51 adversarial-deepseek testing gap No case covers a schedule run whose record or route step fails (transient gh api error) to pin the intended behavior: unrouted red run vs. best-… Rejected as a new test. Running the workflow's gh glue needs a test harness over the GitHub API, which is a new CI gate; this repo admits a gate only with operator sign-off (GATE1). The glue is proved by the first scheduled night and the two dispatches after merge (plan V6, V7), which the post-merge comment cites by run id.
D1 adversarial-deepseek (delta) regression A failed plan job silently drops the green base the report job used to fetch for itself, so a red-night record can say 'no green night yet' while a gr Fixed in 5f88dbeac: the plan publishes green and green-night as step outputs as soon as it finds them, and the report job builds a base record from them when the plan artifact is missing.
D2 adversarial-deepseek (delta) regression The no-green candidate bound can drop the culprit merge from the task, which the lane's own R8 says must name every merge in the range Fixed in 5f88dbeac: the task says only the newest 20 are named, and plan R8 states the bound.
D3 adversarial-deepseek (delta) regression The two added full-run triggers are outside the plan's R5 and outside the decision-table test loop Fixed in 5f88dbeac: the decision table covers both, and plan R5 lists them.

Constitution treatment (16 laws, CONSTITUTION.md at de684e25, evidence at af068a080)

Law Verdict First evidence
CONST-D1 comply scripts/tools/mutants-plan.sh:37
CONST-D2 comply scripts/tools/mutants-plan.sh:35
CONST-D4 comply scripts/tools/mutants-night.sh:74
CONST-B1 violate scripts/tools/mutants-night.sh:164
CONST-B4 comply flake.nix:75
CONST-N1 comply flake.nix:142
CONST-N3 comply flake.nix:145
CONST-S1 comply .github/workflows/mutants.yml:17
CONST-S2 comply docs/plans/2026-10-13-2100-ci-mutants-nightly-plan.md:17
CONST-S4 comply docs/solutions/tooling-decisions/cargo-mutants-resume-and-shard-semantics.md:49
CONST-T8 comply flake.nix:145
CONST-T10 comply scripts/tools/mutants-plan.test.sh:155
CONST-T3 comply scripts/tools/mutants-night.test.sh:107
CONST-T12 comply scripts/tools/mutants-plan.sh:90
CONST-W1 comply docs/plans/2026-10-13-2100-ci-mutants-nightly-plan.md:45
CONST-E7 comply flake.nix:146

Compound Pack rules (all 56 loaded rules, packs at de684e25, evidence at af068a080)

11 apply and comply; 45 do not apply.

Pack Rule Applies Verdict First evidence
ci-wall-clock failures-name-the-gate-and-location.md yes comply scripts/tools/mutants-plan.sh:235
ci-wall-clock flake-outputs-build-once-on-main.md yes comply .github/workflows/mutants.yml:124
ci-wall-clock gates-share-one-job.md no not-applicable .github/workflows/mutants.yml:17
ci-wall-clock heavy-lanes-state-their-daily-minutes.md yes comply .github/workflows/mutants.yml:1
ci-wall-clock heavy-suites-judge-every-main-commit.md yes comply .github/workflows/mutants.yml:35
ci-wall-clock light-checks-run-the-pinned-tool.md no not-applicable .github/workflows/mutants.yml:19
ci-wall-clock local-gate-equals-pr-gate.md no not-applicable flake.nix:145
ci-wall-clock mutation-runs-nightly-on-main.md yes comply scripts/tools/mutants-plan.sh:33
ci-wall-clock no-dev-shell-on-verdict-lanes.md yes comply flake.nix:77
ci-wall-clock no-lane-grades-the-repos-own-docs.md no not-applicable .github/workflows/mutants.yml:174
ci-wall-clock one-stuck-job-backstop.md yes comply .github/workflows/mutants.yml:51
ci-wall-clock pr-gate-runs-only-what-the-diff-affects.md no not-applicable .github/workflows/mutants.yml:255
ci-wall-clock red-main-reverts-its-culprit-same-day.md no not-applicable .github/workflows/mutants.yml:347
ci-wall-clock release-promotes-the-staging-proven-build.md no not-applicable .github/workflows/mutants.yml:43
ci-wall-clock setup-under-a-minute.md no not-applicable .github/workflows/mutants.yml:16
mutation-discipline kill-survivors-with-contract-properties.md no not-applicable scripts/tools/mutants-night.sh:58
mutation-discipline suppress-by-shape-in-an-ignorer.md no not-applicable scripts/tools/mutants-plan.test.sh:175
mutation-discipline unkillable-survivors-are-dead-code.md no not-applicable scripts/tools/mutants-night.sh:71
boundary-testing expected-values-never-come-from-the-subjects-output.md yes comply scripts/tools/mutants-night.test.sh:79
boundary-testing fake-and-real-store-laws.md no not-applicable scripts/tools/mutants-plan.sh:1
boundary-testing no-mocks-on-internal-glue.md yes comply scripts/tools/mutants-plan.sh:154
boundary-testing pin-dependency-semantics.md yes comply scripts/tools/mutants-plan.sh:154
boundary-testing port-fakes-pass-the-port-contract.md no not-applicable scripts/tools/mutants-plan.sh:1
boundary-testing real-system-oracles.md yes comply .github/workflows/mutants.yml:174
boundary-testing staged-protocol-evidence.md no not-applicable scripts/tools/mutants-night.sh:1
cell-architecture callable-vs-resource-syntax.md no not-applicable flake.nix:75
cell-architecture decode-never-cast.md no not-applicable scripts/tools/mutants-plan.sh:1
cell-architecture four-channel-contracts.md no not-applicable scripts/tools/mutants-night.sh:1
cell-architecture handle-state-privacy.md no not-applicable .github/workflows/mutants.yml:42
cell-architecture pipeable-dual-parity.md no not-applicable flake.nix:75
cell-architecture pipeline-composition.md no not-applicable scripts/tools/mutants-plan.sh:1
cell-architecture pure-decision-workflows.md no not-applicable scripts/tools/mutants-night.sh:1
cell-architecture resource-vs-handle-duality.md no not-applicable .github/workflows/mutants.yml:42
cell-architecture sandwich-phase-order.md no not-applicable flake.nix:75
cell-architecture scoped-lifecycle-boundaries.md no not-applicable scripts/tools/mutants-plan.sh:1
cell-architecture service-and-layer-boundaries.md no not-applicable scripts/tools/mutants-night.sh:1
cell-architecture single-namespace-barrel.md no not-applicable .github/workflows/mutants.yml:42
cell-architecture staged-lawful-builders.md no not-applicable flake.nix:75
cell-architecture store-serializable-unit-of-work.md no not-applicable scripts/tools/mutants-plan.sh:1
cell-architecture store-unit-of-work-handle.md no not-applicable scripts/tools/mutants-night.sh:1
package-topology condition-branch-agreement.md no not-applicable flake.nix:142
package-topology declared-entry-points.md no not-applicable flake.nix:75
package-topology enumerated-entry-modules.md no not-applicable flake.nix:146
package-topology import-time-inertness.md no not-applicable flake.nix:142
package-topology one-access-path.md no not-applicable flake.nix:75
package-topology public-signature-types.md no not-applicable flake.nix:146
package-topology surface-changes-are-versioned.md no not-applicable flake.nix:142
schema-laws arbitrary-filter-floors.md no not-applicable scripts/tools/mutants-plan.sh:1
schema-laws cross-field-invariants-as-struct-checks.md no not-applicable scripts/tools/mutants-night.sh:1
schema-laws data-only-schema-classes.md no not-applicable scripts/tools/mutants-night.test.sh:79
schema-laws invariants-as-refinements.md no not-applicable scripts/tools/mutants-plan.sh:1
schema-laws recursive-schema-suspend.md no not-applicable scripts/tools/mutants-night.sh:1
schema-laws refusal-properties-cover-unobservable-boundaries.md no not-applicable scripts/tools/mutants-night.test.sh:79
schema-laws rich-type-over-foreign-encoded.md no not-applicable scripts/tools/mutants-plan.sh:1
schema-laws tagged-unions-over-state-by-presence.md no not-applicable scripts/tools/mutants-night.sh:1
schema-laws tests-own-no-schemas.md no not-applicable scripts/tools/mutants-night.test.sh:79

ce-compound

Nothing new written: the documentation was skipped. The durable learning, that the plan must size from the same filtered listing the shards split, round-robin by index, and that a reproduce must not resume, is in this PR's update to docs/solutions/tooling-decisions/cargo-mutants-resume-and-shard-semantics.md. The other lessons from this session are either in the plan's KTDs or not yet observed, such as how a re-run behaves on a real night, so writing them up now would document claims nobody has checked.

Privacy

A case-insensitive grep for private project and person names, email addresses and local filesystem paths finds nothing in the diff origin/main..5f88dbeac. In the commit messages it finds only the author line, the identity this repository already commits under. The same grep over this body finds nothing.

The Mutants lane must stop running on every push to main (ci-wall-clock/mutation-runs-nightly-on-main, enrolled in #23). The plan covers the schedule and dispatch inputs, the main-only guard, per-run concurrency, shards sized from measured timings, and the night record and fix task the lane writes itself while no triage exists.
Mutants now runs on a 03:17 UTC schedule and on workflow_dispatch, as
ci-wall-clock/mutation-runs-nightly-on-main requires, and no longer on
every push to main.

- A guard job refuses any ref but the default branch, a sha main does
  not reach and a malformed night id before anything installs, and
  every other job needs it.
- Each run is its own concurrency group, so a dispatch and the night's
  run never replace each other.
- Dispatch takes sha, packages and night; the run is titled
  "Mutants <sha>" plus " for <night>".
- The plan sizes shards from the newest measured run's per-file mutant
  times and per-shard overhead, so each job aims at 10 minutes.
- Shards restore main's Nix store bundle and take their tools from the
  new gritlint-mutants-tools package instead of the dev shell.
- A night tests the diff from the last green night, or everything.
- The report job writes the night's record artifact, files or updates
  the fix task on a red night, and ends red; a green night writes one
  line.
- Every job writes its wall time and, on failure, a reason code and a
  reproduce command.
…flow, bound a red night's candidates

From the full-path review of the nightly lane:

- The night record upload overwrites its own name, so a re-run's report
  writes the record instead of failing on a name the first attempt took.
- The jobs, artifacts and open-issue reads follow every page, so a night
  past 100 shards still sizes, reports and routes from all of them.
- The green-night lookup moves from mutants-night.sh into the plan job,
  which hands the green record to the report job in the plan artifact;
  the scripts again hold only decisions over files.
- With no green night, a red night names the 20 newest first-parent
  commits as candidates instead of main's whole history, and one failed
  pulls lookup leaves that commit unattributed instead of failing the
  record.
- A malformed artifacts body fails the plan instead of being read as a
  run with no shard artifacts.
- mutants-night.sh tasks selects the open fix tasks; a test files a task
  body and routes the next night to it.
- flake.nix and rust-toolchain.toml join the full-run triggers, since the
  lane's tools are built from them.
- The shard's outcome and upload steps carry ids and reason codes.
verdict writes the record route reads; one case now feeds the first into the second, so a renamed record key fails the gritlint-mutants-plan check.
…candidate bound

From the cross-model pass over the review fixes:

- The plan job publishes the green night's sha and id as outputs as
  soon as it finds them, so a report whose plan failed later still
  names the range from that night instead of "no green night yet".
- With no green night, the fix task says that only the newest 20
  first-parent commits are named and older merges are not; plan R8
  says the same.
- The decision table runs the full-night case for flake.nix and
  rust-toolchain.toml, and plan R5 lists them as lane inputs.
@systemfsoftware-maker systemfsoftware-maker changed the title ci/mutants nightly ci(mutants): run the lane once a night on main, never on a push Oct 13, 2026
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