fix(ci): judge a panic ratchet red by its per-lint rows, not the packages it names
Summary
scripts/ci/base_red_excuse.py never excused a Rust panic ratchet red on clippy (changed cmux-tui packages) (step Rust panic ratchet on changed cmux-tui packages). It compared the ratchet's ::error line, which names the packages the run checked. A base run can be a whole-workspace dispatch ("the panic ratchet is red for the whole cmux-tui workspace"), but a PR run names only its changed packages. So the line never matched, even when every failure row was the same on both runs.
Concrete case: cmux#26849 at f81fd0a3e4386ddc13eea076dc9a5315abb4c798, run 41176610742, fails on exactly two rows:
acpmux: clippy::indexing_slicing 692 > baseline 686cmux-tui: clippy::indexing_slicing 836 > baseline 831
Base run 41176544319 (at 734e99a7e6) fails on those same two rows plus cmux-rd-link: clippy::indexing_slicing 7 > new crate (must be 0). The classifier still said not excused: errors not on feat-cmux-next run 41176544319.
The ratchet red is now judged by the rows in its rust-panic-ratchet: RED block:
- Each head row
CRATE: clippy::LINT N > WHEREmust be on the base with the same crate, the same lint and the sameWHERE(baseline Mornew crate (must be 0)), and the base's count must be at least the head's. The base may have extra rows. - Hit-location lines (
crates/x/src/y.rs:L:C) are not compared. Any other RED line (for example an allow with no reason) must be on the base word for word. - A ratchet red with no row is never excused. The ratchet prints no row when its clippy run did not finish.
- Other error lines in the same job (a clippy compile error, say) are still compared as before. So are failed steps. The crash and cut-short rules are unchanged.
This also closes a gap that loosened the check: when the head and base had the same scope line, the old code excused the head even when its count was higher than the base's (see the ..._with_the_same_scope_too test). That case now blocks.
No open PR fixes this classifier. #28958 lowers the base counts. It does not change the classifier.
Testing
Command: python3 -m unittest tests.test_base_red_excuse.PanicRatchet
- At the test commit (fd5ad6bc3e6, fix not applied):
FAILED (failures=7, errors=2)of 10 tests. - At the head:
Ran 10 tests ... OK. The whole filepython3 -m unittest tests.test_base_red_excusepasses: 106 tests, OK.
Observed / Not run
- Observed: the new tests red and then green, as above. I read the real job logs of run 41176610742 (job 124465364731) and base run 41176544319 (job 124465669565) and ran the new parser on them.
ratchet_redread 2 head rows and 3 base rows, andratchet_unmatchedreturned no unmatched lines. - Not run: the end-to-end
base_red_excuse.py --run 41176610742against GitHub. The shared REST quota ran out (HTTP 403) when I tried it. I will re-check after the reset and report the result in a PR comment.
Changelog
none
risk:normal: CI tooling only. It loosens the base-red excuse for one kind of check and tightens it in the same-scope case.
Agent session: agent session
🤖 Generated with Claude Code
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Fixes the base-red excuse for Rust panic ratchet failures so ratchet reds are judged by their per-lint rows instead of the scope line that names the checked packages.
A base run may cover the whole cmux-tui workspace while a PR run covers only its changed packages, so the scope line never matched and valid excuses were refused. Now each head row (CRATE: clippy::LINT N > WHERE) must appear on the base with the same crate, lint, and WHERE and a count at least the head's; other RED lines match word for word, and a red with no rows is never excused.
Behavior changes
- Tightens the check: a head count above the base's now blocks even when both runs share the same scope.
- Other error lines in the same job and failed steps are still compared as before.