ci: run the Rust gates on stacked PRs, not only PRs targeting main - #319
Merged
Conversation
`crap`, `test`, `mutants` and `miri` filtered `pull_request` to `branches: [main]`. Retargeting a PR onto its parent branch, the normal move when stacking, silently switched every one of them off: #318 showed only the Go bindings and wasm checks and looked green while the CRAP gate had a failing function nobody could see. `go.yml` had already dropped the filter for exactly this reason. The filter goes on all four. `mutants` already diffs against `github.base_ref`, which on a stacked PR is the parent branch, so its scope stays "this PR's changes" rather than growing to the whole stack. The `push: [main]` triggers are untouched. Claude-Session: https://claude.ai/code/session_01QvrvBVdcecdr4LfywiGnDd
Contributor
🧬 Mutation testing (cargo-mutants,
|
Contributor
✅ No CRAP threshold violations572 function(s) analyzed · threshold 30 |
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
The workflow trigger changes are straightforward and correct, with only a minor follow-up doc/comment consistency issue noted.
Pull request overview
Updates GitHub Actions triggers so Rust “gate” workflows run on stacked PRs (where the PR base is a feature branch), not only when the PR targets main, preventing false-green PRs when retargeting during stacking.
Changes:
- Removed the
pull_request.branches: [main]filter from Rust gate workflows so they run for any PR base branch. - Added short inline rationale comments explaining the stacked-PR motivation and prior failure mode.
- Left
push(stillmain-only) andworkflow_dispatchtriggers unchanged.
File summaries
| File | Description |
|---|---|
| .github/workflows/test.yml | Removes PR branch filter so the main Rust test/clippy/docs gate runs on stacked PRs; adds explanatory comment. |
| .github/workflows/crap.yml | Removes PR branch filter so the CRAP gate runs on stacked PRs; adds explanatory comment. |
| .github/workflows/mutants.yml | Removes PR branch filter so mutation testing gate runs on stacked PRs; adds explanatory comment. |
| .github/workflows/miri.yml | Removes PR branch filter so the Miri (unsafe/UB) gate runs on stacked PRs; adds explanatory comment. |
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+6
to
+8
| # No branch filter: a stacked PR (a feature branch as base) must run this | ||
| # gate too. With `branches: [main]` here, retargeting a PR onto its | ||
| # parent branch silently switched every Rust gate off; see go.yml. |
auxesis
approved these changes
Sep 6, 2026
coderdan
added a commit
that referenced
this pull request
Sep 7, 2026
…P and mutants First run of the Rust gates on this branch (it predates #319, so only the Go workflow had ever run) found one CRAP violation and three surviving mutants, all in `shuffle.rs`. `schedule` scored 56: complexity 7 from one match arm per size, and 0% coverage, because production only evaluates it inside `const` blocks and llvm-cov cannot see compile-time execution. The bounds test now calls it at runtime, and a `should_panic` test covers the unsupported length arm. Same production code, 100% covered, CRAP 7. `batcher_fill`'s inner guard `i + j + k < n` had a surviving `<=` mutant: every shipped size is a power of two, where a partial final merge block never occurs, so nothing exercised it. A zero-one-principle test now builds the schedule at runtime for every n from 2 to 16 and checks sorting and gate bounds; odd n reach the guard and the mutant dies with an out-of-bounds gate. The outer merge loop's bound has an equivalent mutant: one extra iteration whose every inner step the guard rejects, unobservable by construction. It is rewritten as `n > j + k` so its mutant name differs from the inner guard's, and that one name is excluded in .cargo/mutants.toml with the reasoning. The inner guard stays mutated. Packing `(random << 8) | index` had an equivalent `^` mutant since the low byte is zero after the shift. `+` produces the same word and has no equivalent mutant. Claude-Session: https://claude.ai/code/session_01QvrvBVdcecdr4LfywiGnDd
coderdan
added a commit
that referenced
this pull request
Sep 8, 2026
…P and mutants First run of the Rust gates on this branch (it predates #319, so only the Go workflow had ever run) found one CRAP violation and three surviving mutants, all in `shuffle.rs`. `schedule` scored 56: complexity 7 from one match arm per size, and 0% coverage, because production only evaluates it inside `const` blocks and llvm-cov cannot see compile-time execution. The bounds test now calls it at runtime, and a `should_panic` test covers the unsupported length arm. Same production code, 100% covered, CRAP 7. `batcher_fill`'s inner guard `i + j + k < n` had a surviving `<=` mutant: every shipped size is a power of two, where a partial final merge block never occurs, so nothing exercised it. A zero-one-principle test now builds the schedule at runtime for every n from 2 to 16 and checks sorting and gate bounds; odd n reach the guard and the mutant dies with an out-of-bounds gate. The outer merge loop's bound has an equivalent mutant: one extra iteration whose every inner step the guard rejects, unobservable by construction. It is rewritten as `n > j + k` so its mutant name differs from the inner guard's, and that one name is excluded in .cargo/mutants.toml with the reasoning. The inner guard stays mutated. Packing `(random << 8) | index` had an equivalent `^` mutant since the low byte is zero after the shift. `+` produces the same word and has no equivalent mutant. Claude-Session: https://claude.ai/code/session_01QvrvBVdcecdr4LfywiGnDd
coderdan
added a commit
that referenced
this pull request
Sep 9, 2026
…P and mutants First run of the Rust gates on this branch (it predates #319, so only the Go workflow had ever run) found one CRAP violation and three surviving mutants, all in `shuffle.rs`. `schedule` scored 56: complexity 7 from one match arm per size, and 0% coverage, because production only evaluates it inside `const` blocks and llvm-cov cannot see compile-time execution. The bounds test now calls it at runtime, and a `should_panic` test covers the unsupported length arm. Same production code, 100% covered, CRAP 7. `batcher_fill`'s inner guard `i + j + k < n` had a surviving `<=` mutant: every shipped size is a power of two, where a partial final merge block never occurs, so nothing exercised it. A zero-one-principle test now builds the schedule at runtime for every n from 2 to 16 and checks sorting and gate bounds; odd n reach the guard and the mutant dies with an out-of-bounds gate. The outer merge loop's bound has an equivalent mutant: one extra iteration whose every inner step the guard rejects, unobservable by construction. It is rewritten as `n > j + k` so its mutant name differs from the inner guard's, and that one name is excluded in .cargo/mutants.toml with the reasoning. The inner guard stays mutated. Packing `(random << 8) | index` had an equivalent `^` mutant since the low byte is zero after the shift. `+` produces the same word and has no equivalent mutant. Claude-Session: https://claude.ai/code/session_01QvrvBVdcecdr4LfywiGnDd
coderdan
added a commit
that referenced
this pull request
Sep 9, 2026
…P and mutants First run of the Rust gates on this branch (it predates #319, so only the Go workflow had ever run) found one CRAP violation and three surviving mutants, all in `shuffle.rs`. `schedule` scored 56: complexity 7 from one match arm per size, and 0% coverage, because production only evaluates it inside `const` blocks and llvm-cov cannot see compile-time execution. The bounds test now calls it at runtime, and a `should_panic` test covers the unsupported length arm. Same production code, 100% covered, CRAP 7. `batcher_fill`'s inner guard `i + j + k < n` had a surviving `<=` mutant: every shipped size is a power of two, where a partial final merge block never occurs, so nothing exercised it. A zero-one-principle test now builds the schedule at runtime for every n from 2 to 16 and checks sorting and gate bounds; odd n reach the guard and the mutant dies with an out-of-bounds gate. The outer merge loop's bound has an equivalent mutant: one extra iteration whose every inner step the guard rejects, unobservable by construction. It is rewritten as `n > j + k` so its mutant name differs from the inner guard's, and that one name is excluded in .cargo/mutants.toml with the reasoning. The inner guard stays mutated. Packing `(random << 8) | index` had an equivalent `^` mutant since the low byte is zero after the shift. `+` produces the same word and has no equivalent mutant. Claude-Session: https://claude.ai/code/session_01QvrvBVdcecdr4LfywiGnDd
coderdan
added a commit
that referenced
this pull request
Sep 9, 2026
…P and mutants First run of the Rust gates on this branch (it predates #319, so only the Go workflow had ever run) found one CRAP violation and three surviving mutants, all in `shuffle.rs`. `schedule` scored 56: complexity 7 from one match arm per size, and 0% coverage, because production only evaluates it inside `const` blocks and llvm-cov cannot see compile-time execution. The bounds test now calls it at runtime, and a `should_panic` test covers the unsupported length arm. Same production code, 100% covered, CRAP 7. `batcher_fill`'s inner guard `i + j + k < n` had a surviving `<=` mutant: every shipped size is a power of two, where a partial final merge block never occurs, so nothing exercised it. A zero-one-principle test now builds the schedule at runtime for every n from 2 to 16 and checks sorting and gate bounds; odd n reach the guard and the mutant dies with an out-of-bounds gate. The outer merge loop's bound has an equivalent mutant: one extra iteration whose every inner step the guard rejects, unobservable by construction. It is rewritten as `n > j + k` so its mutant name differs from the inner guard's, and that one name is excluded in .cargo/mutants.toml with the reasoning. The inner guard stays mutated. Packing `(random << 8) | index` had an equivalent `^` mutant since the low byte is zero after the shift. `+` produces the same word and has no equivalent mutant. Claude-Session: https://claude.ai/code/session_01QvrvBVdcecdr4LfywiGnDd
coderdan
added a commit
that referenced
this pull request
Sep 9, 2026
…P and mutants First run of the Rust gates on this branch (it predates #319, so only the Go workflow had ever run) found one CRAP violation and three surviving mutants, all in `shuffle.rs`. `schedule` scored 56: complexity 7 from one match arm per size, and 0% coverage, because production only evaluates it inside `const` blocks and llvm-cov cannot see compile-time execution. The bounds test now calls it at runtime, and a `should_panic` test covers the unsupported length arm. Same production code, 100% covered, CRAP 7. `batcher_fill`'s inner guard `i + j + k < n` had a surviving `<=` mutant: every shipped size is a power of two, where a partial final merge block never occurs, so nothing exercised it. A zero-one-principle test now builds the schedule at runtime for every n from 2 to 16 and checks sorting and gate bounds; odd n reach the guard and the mutant dies with an out-of-bounds gate. The outer merge loop's bound has an equivalent mutant: one extra iteration whose every inner step the guard rejects, unobservable by construction. It is rewritten as `n > j + k` so its mutant name differs from the inner guard's, and that one name is excluded in .cargo/mutants.toml with the reasoning. The inner guard stays mutated. Packing `(random << 8) | index` had an equivalent `^` mutant since the low byte is zero after the shift. `+` produces the same word and has no equivalent mutant. Claude-Session: https://claude.ai/code/session_01QvrvBVdcecdr4LfywiGnDd
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.
What
Drops the
branches: [main]filter underpull_requestincrap.yml,test.yml,mutants.ymlandmiri.yml, matching whatgo.ymlalready does.push: [main]andworkflow_dispatchtriggers are unchanged.Why
Retargeting #318 onto
non-empty-withto stack it on #314 turned every Rust gate off: only the Go bindings and wasm checks ran on the new commits, and the PR looked green while the CRAP gate had a failing function. The gates had to be triggered by hand withworkflow_dispatchto see it.mutants.ymldiffs againstgithub.base_ref, which on a stacked PR is the parent branch, so its scope stays this PR's changes rather than the whole stack. Cost is one extra run of each gate per stacked PR.https://claude.ai/code/session_01QvrvBVdcecdr4LfywiGnDd