Skip to content

fix(tensilelite): stop coverage ratchet update from lowering floors - #10596

Merged
tony-davis merged 4 commits into
developfrom
users/tony-davis/coverage-ratchet-no-silent-lowering
Aug 26, 2026
Merged

tony-davis merged 4 commits into
developfrom
users/tony-davis/coverage-ratchet-no-silent-lowering

Conversation

@tony-davis

@tony-davis tony-davis commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

ISSUE ID : #10591
JIRA ID : AIHPBLAS-3878

Motivation

coverage_ratchet.py update is not a ratchet. write_baseline() rewrites every entry from whatever coverage.json is on disk, with no comparison against the floors already committed, so an update run made to move one file also resets every other file to that run's numbers. Some of those move down. The gate's own failure message tells you to run exactly that command, which makes the tool's remediation path the fastest way to weaken the tool.

That contradicts what the ratchet is documented to do in three places: tox.ini says the floors "are never lowered to go green", and the module docstring and the characterization README both describe a one-way mechanism. This makes the code match the contract.

It came up while clearing the stale SubtileGREmit.py floor in #10591, where the documented fix would have silently lowered unrelated floors as a side effect. It matters more the moment TensileLite coverage becomes a required check, because being blocked is what makes someone reach for the remediation command at speed. Today the lane is advisory, so this is a fix rather than a scramble.

Technical Details

update can now only strengthen the baseline. New ratchet_floors() takes the committed floors plus the current report and returns the new floors and any it refused to move. A floor rises to the current number, a file with no floor yet is pinned at its current number, and a floor that would fall is held. Percentages are rounded to the two decimals the baseline is written at before being compared, so a difference the file cannot represent is not treated as a fall.

Lowering stays possible, but it has to be named. --allow-lower PATH (repeatable) lowers exactly the files listed and nothing else. Without it, cmd_update writes nothing, exits 1, and prints the offending files with their floor, current value and delta.

The remediation text can no longer be pasted into a blanket reset. REMEDIATION was a constant suggesting a bare update --current coverage.json; it is now remediation(paths), emitting one --allow-lower line per offending file. Both check and update print it, so the command a developer copies out of a red CI log can only touch the files that actually regressed. An --allow-lower naming a path that is not in the report warns instead of passing silently, since a typo there would otherwise look like the drop had been reviewed.

Docs move with the tool. The README's "Raising the floors" steps described the old blanket behavior and now describe the refusal and the named-file opt-in.

No CI job invokes update; coverage-gate runs check only, and the Math CI tensilelite-unit-codecov job runs coverage-unit without the gate. So no automation changes behavior.

One related gap is deliberately left alone: update still drops the floor for a file absent from the report, so running it against a partial report would delete those floors. Same family, but it needs its own opt-out and would grow this diff past one logical change.

Test Plan

  • Unit tests for the new semantics in test_coverage_ratchet.py: a floor rises to current, a floor is held when current is lower, a new file is pinned, a named file is lowered, sub-precision dips are not falls, refusals sort biggest-drop-first, and the remediation text names every offender and never emits a bare update.
  • The regression test for the defect itself is test_lowering_one_file_does_not_lower_another: with one file named in --allow-lower and a second also measuring low, the second file's floor must not move.
  • End-to-end through cmd_update and main: a refusal writes nothing and returns 1, --allow-lower lowers only the named file, repeated flags parse, and an unknown path warns.
  • Before/after reproduction against the unpatched tool from develop.
  • No other test level applies. This is CI test infrastructure: no product code, no kernel generation, no device or architecture impact, so the CPU-only coverage lane is the appropriate and sufficient coverage and no multi-arch sweep is warranted.

Test Result

Reproduction against the pre-change tool, identical inputs both times. Starting floors {named.py: 90.0, bystander.py: 88.0}, coverage on disk named.py=70.0, bystander.py=60.0, lowering named.py on purpose:

BEFORE (develop):  rc=0  bystander.py floor: 88.0 -> 60.0
AFTER  (this PR):  rc=1  bystander.py floor: 88.0 -> 88.0

After the change the run refuses, writes nothing, and prints the command that lowers only bystander.py.

Unit suite, 36 tests (24 pre-existing, 12 new), all passing:

python -m pytest Tensile/Tests/unit/characterization/tools/test_coverage_ratchet.py -q
36 passed

Run locally on Windows with --noconftest, because the suite's conftest imports rocisa, which this machine cannot build. CI runs the file normally in the -m unit lane, so that caveat is local only.

Note on this PR's CI: TensileLite coverage / Linux will stay red until the sibling baseline PR #10595 lands, because develop's SubtileGREmit.py floor is still stale. That failure is pre-existing, is the subject of #10591, and is unrelated to this diff. The unit tests above run in the same lane and are the signal to read here.

Submission Checklist

Risk level

Low (2). Test infrastructure only, with a blast radius of one CI lane and one manual maintenance command. The change makes that command stricter, so the failure mode is a refusal that names its own fix rather than a silently weakened gate. The one behavior change a user will notice is that an update which used to succeed and quietly lower floors now exits 1 and asks which file you meant.

write_baseline() rewrote every entry from the current coverage.json with
no comparison against the committed floors, so an update run made to move
one file also reset all the others to that run's numbers, lowering some.
The gate's own failure message suggested exactly that command, which made
the tool's remediation path the fastest way to weaken the tool. tox.ini,
the module docstring and the characterization README all already claimed
floors are never lowered to go green.

update now only strengthens the baseline: a floor rises to the current
number, a new file is pinned, and a floor that would fall is held.
Lowering one requires naming it with --allow-lower, and the remediation
text emits one such flag per offending file so a red CI log cannot be
pasted into a blanket reset.

ISSUE ID : #10591

Co-authored-by: Cursor <cursoragent@cursor.com>
@therock-pr-bot

therock-pr-bot Bot commented Aug 10, 2026 •

Copy link
Copy Markdown

✅ All Checks Passed — Ready for Review

Check Status Details
📝 PR Description ✅ Pass —
⛔ Forbidden Files ✅ Pass —
🧪 Unit Test ✅ Pass —
🔎 pre-commit ✅ Pass —
🚫 Draft PR 🔜 To Be Enabled —
🚩 Feature Flag 🔜 To Be Enabled —
📊 Code Coverage 🔜 To Be Enabled —
🤖 therock-pr-bot ✅ Pass —

🎉 All checks passed! This PR is ready for review.

📖 Need help? See the Policy FAQ for details on every check and how to fix failures.

🙋 Wish to Override Policy?

@therock-pr-bot

Copy link
Copy Markdown

🎉 All checks passed! This PR is ready for review.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes TensileLite’s per-file coverage “ratchet” so that coverage_ratchet.py update can no longer silently lower unrelated per-file floors when run to adjust a single file. It makes update strictly one-way by default (raise/pin only), and requires an explicit per-file opt-in (--allow-lower PATH, repeatable) to lower any floor, with updated remediation output and documentation to match.

Changes:

  • Implement ratchet_floors() to compute updated floors while refusing unintended decreases unless explicitly allowed via --allow-lower.
  • Replace the constant remediation string with a remediation(paths) helper that prints a copy/paste command listing only the regressed files.
  • Add unit tests covering the new update semantics and update the characterization README instructions.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
projects/hipblaslt/tensilelite/Tensile/Tests/unit/characterization/tools/coverage_ratchet.py Implements “update never lowers floors unless named” behavior, adds --allow-lower, and updates remediation output.
projects/hipblaslt/tensilelite/Tensile/Tests/unit/characterization/tools/test_coverage_ratchet.py Adds unit tests validating refusal behavior, per-file lowering opt-in, and remediation text output.
projects/hipblaslt/tensilelite/Tensile/Tests/unit/characterization/README.md Updates documentation to reflect refusal-by-default and explicit --allow-lower workflow.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@codecov

codecov Bot commented Aug 11, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #10596      +/-   ##
===========================================
- Coverage    69.36%   68.98%   -0.39%     
===========================================
  Files         2778     2767      -11     
  Lines       458114   455972    -2142     
  Branches     67566    67227     -339     
===========================================
- Hits        317756   314509    -3247     
- Misses      117218   118543    +1325     
+ Partials     23140    22920     -220     
Flag Coverage Δ *Carryforward flag
TensileLite-CPP 38.05% <ø> (ø)
TensileLite-Unit 76.57% <ø> (ø)
hipBLAS 90.62% <ø> (-<0.01%) ⬇️ Carriedforward from 4f3a750
hipBLASLt 34.89% <ø> (ø)
hipCUB 82.68% <ø> (ø) Carriedforward from 4f3a750
hipDNN 86.53% <ø> (-0.25%) ⬇️ Carriedforward from 4f3a750
hipFFT 45.76% <ø> (+2.16%) ⬆️ Carriedforward from 4f3a750
hipRAND 76.12% <ø> (ø) Carriedforward from 4f3a750
hipSOLVER 69.03% <ø> (ø) Carriedforward from 4f3a750
hipSPARSE 86.99% <ø> (ø) Carriedforward from 4f3a750
rocBLAS 48.23% <ø> (-0.03%) ⬇️ Carriedforward from 4f3a750
rocFFT 48.12% <ø> (+0.49%) ⬆️ Carriedforward from 4f3a750
rocRAND 57.02% <ø> (-0.03%) ⬇️ Carriedforward from 4f3a750
rocSOLVER 76.92% <ø> (-0.20%) ⬇️ Carriedforward from 4f3a750
rocSPARSE 72.55% <ø> (-2.07%) ⬇️ Carriedforward from 4f3a750
rocThrust 91.60% <ø> (ø) Carriedforward from 4f3a750

*This pull request uses carry forward flags. Click here to find out more.
see 213 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@newling

newling commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

If I understand correctly, this PR's main change is to make it a requirement for anyone running the ratchet script to explicitly list all files whose new floors will go down, and not up? That seems sensible. Indeed, without the asymmetry introduced here it is not a ratchet (a distinctly asymmetrical tool!).

I do have one concern, although it is not introduced in this PR. I see 2 orthogonal things being mixed up in this tooling:

  1. Ratchet coverage gains: opportunistically raise all floors.
  2. Accept an intentional regression: lower one specific floor as part of a PR.

With the current flow, a developer who wants to accept an intentional regression (2) is forced to ratchet up the other floors (1). I think the ratcheting up and the accepting a lowering of floor are separate concerns. I might be missing something though.

I will get an agent review here shortly, but overall this PR looks good to me!

@newling

newling commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Agent review: https://github.com/newling/agent-public-reviews/blob/main/rocm-libraries/review_pr10596.md
It looks like there are 2 actionable items there, please take a look.

@newling
newling self-requested a review August 11, 2026 17:20
tony-davis added a commit that referenced this pull request Aug 12, 2026
…10595)

ISSUE ID : #10591

## Motivation

`TensileLite coverage / Linux` has failed on every tensilelite PR since
#9410 landed, on a file none of those PRs touch. The baseline holds
`Tensile/Components/Subtile/SubtileGREmit.py` at 73.39%, develop
measures it at 70.83%, and the 2.56 pp gap is past the 1 pp tolerance.
Issue #10591 has the full trace, including the four unrelated PRs
showing a byte-identical failure.

This is not something a re-run can clear: the drift is on develop, and a
re-run replays the same merge SHA. The lane is advisory rather than
required, so nothing is blocked by it, but it is red on every affected
PR and that is worth clearing rather than teaching people to scroll
past.

Please read this as what it is: approving a 2.56 pp coverage reduction
on `SubtileGREmit.py`. Whether that drop should instead be bought back
with tests is a component call rather than a CI one, and @WorldofKerry
has a follow-up planned in #10591. When those tests land the floor
ratchets back up on its own, which is the mechanism working as intended.

## Technical Details

One entry changed, `SubtileGREmit.py` 73.39 -> 70.83. Nothing else in
the baseline moves.

The number is develop's own measurement, taken from the `TensileLite
coverage` job on #9410's merge commit:
https://github.com/ROCm/rocm-libraries/actions/runs/31121977279/job/92714351091.
It came from the CI log rather than a local run because the lane needs
Linux plus a built `rocisa`. This PR's own coverage run is the check on
it: if 70.83 is wrong, the gate says so.

The entry was edited directly rather than by running
`coverage_ratchet.py update`, which is what the gate's failure message
currently suggests. That command rewrites every entry from whatever
`coverage.json` is on disk, so it would also reset unrelated files to
that run's numbers and quietly lower some of them. #10596 fixes the tool
so `update` can no longer do that; this PR deliberately touches only the
one number so the diff is the whole review.

## Test Plan

- The `TensileLite coverage / Linux` lane on this PR. It re-measures
`SubtileGREmit.py` from source and compares against this baseline, so a
green run is the direct check that 70.83 is the right number.
- No other test level applies. This changes one datum in a CI baseline
file: no product code, no kernel generation, no device or architecture
impact, so the CPU-only coverage lane is both the appropriate and the
only relevant coverage.

## Test Result

Pending the PR's own coverage run.

## Submission Checklist

- [ ] Look over the contributing guidelines at
https://github.com/ROCm/ROCm/blob/develop/CONTRIBUTING.md#pull-requests.

## Risk level

None to low (1). A single number in a CI baseline file. It cannot affect
built artifacts or runtime behavior; the only thing it changes is where
one file's coverage gate sits. The risk it does carry is the one named
above: it accepts a real coverage reduction rather than covering it with
tests, which is why the drop is called out explicitly rather than buried
in a diff.

Co-authored-by: Cursor <cursoragent@cursor.com>
@tony-davis
tony-davis requested a review from davidd-amd August 19, 2026 00:42
tony-davis and others added 3 commits August 18, 2026 19:42
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…aths

Address the two actionable items from the agent review on this PR:
ratchet_floors() now takes the same tolerance check uses, so an
in-tolerance dip is held silently instead of forcing a second
--allow-lower the printed remediation command never named. remediation()
now shell-quotes each path and uses --allow-lower=<value>, so a path
with a space, a leading hyphen, or shell metacharacters can't corrupt
or hijack the copy-pasted command.

Co-authored-by: Cursor <cursoragent@cursor.com>
@tony-davis

Copy link
Copy Markdown
Contributor Author

Thanks for the review, both the design note and the agent review's two actionable items are solid catches.

Pushed a fix for both:

  1. ratchet_floors() now takes the same tolerance that check uses. Previously update refused any representable drop, even one check itself would classify as noise and therefore never named in the remediation command. Now an in-tolerance dip is held at the existing floor silently, so the command check prints is actually sufficient to run as-is.
  2. remediation() now shell-quotes each path and prints --allow-lower=<value> instead of --allow-lower <value>, so a path with a space, a leading hyphen, or shell metacharacters (e.g. $(...)) can't split into extra arguments, get misread as another flag, or execute if copy-pasted.

Added unit tests for both (in-tolerance dip held without a refusal, a real regression still refused, an end-to-end check→update round trip, and quoting cases for space/hyphen/metacharacter paths). All 43 tests pass.

On your separate design point about ratcheting-up vs. accepting-an-intentional-regression being different concerns: agreed that's real, but I'd like to treat it as its own follow-up rather than grow this PR further, similar to the floor-deletion-on-partial-report gap already called out in the description.

@newling

newling commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

real, but I'd like to treat it as its own follow-up rather than grow this PR further

makes sense to me

@newling newling left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but I suggest letting @davidd-amd have a look at this too as he's most familiar with it

@tony-davis
tony-davis merged commit 69977d1 into develop Aug 26, 2026
176 of 191 checks passed
@tony-davis
tony-davis deleted the users/tony-davis/coverage-ratchet-no-silent-lowering branch August 26, 2026 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants