Skip to content

feat: a coverage grid, so "is there an end to this" has a number (3.6.0) - #12

Merged
tmoody1973 merged 1 commit into
mainfrom
feat/v3.6.0-coverage-grid
Aug 22, 2026
Merged

feat: a coverage grid, so "is there an end to this" has a number (3.6.0)#12
tmoody1973 merged 1 commit into
mainfrom
feat/v3.6.0-coverage-grid

Conversation

@tmoody1973

Copy link
Copy Markdown
Owner

Three review rounds in a row each found new defects. The question was asked plainly: is there an end to this? There was no way to answer, because nobody could say how much had been checked.

Now there is a number: 83 of 83.

The hole

All 68 tests asked one question: does this check fire?

None asked: does it stay quiet when it should?

That is the exact hole auth-2 fell through. Wrong about half the time it spoke, for three releases, with a green suite the whole way.

The grid

Every check must have a fixture that makes it fire and a fixture that makes it stay quiet. Checks a profile can skip must also have a fixture that skips them.

$ python3 skills/prod-readiness-coach/scripts/coverage_grid.py --quiet
83 of 83 cells filled (100%). 0 check(s) with a gap.

The grid is computed by running the audit over the fixtures, not maintained by hand, so it cannot drift from the code. Add a check with no fixture and the build fails naming that check:

AssertionError: no fixture makes these fire: ['ms-2', 'res-5']

CI fails below 100 percent.

Borrowed from KICS, which refuses a query shipped without both a vulnerable and a safe fixture, and Checkov, which requires both a PASSED and a FAILED case.

Two false negatives it found in its first hour

Both missed by three rounds of human review. Both surfaced mechanically, by the grid demanding a passing fixture.

1. @sentry/nextjs did not count as error tracking.

_installed('sentry')   # False  against {'@sentry/nextjs'}
_installed('@sentry')  # False

The matcher knew sentry and @sentry but not the scope prefix. A Next.js app with Sentry correctly wired up was told at CRITICAL that it had no error tracking at all. That is the most common error-tracker and framework pairing this tool audits. @vercel/otel, @sentry/node and every other scoped package were equally invisible.

@types/pino still correctly does not count as a logger. The existing suite caught that regression when I first fixed this, which is the net working.

2. A plain migrations/ folder was never read for destructive SQL.

The irreversible-migration check knew Prisma, Drizzle, Alembic and Rails. A DROP TABLE in the folder that dbmate, golang-migrate, node-pg-migrate, sqlx and Supabase all use went unreported.

Five invariants, each with a test

Each closes a whole class of defect, so it cannot come back one instance at a time.

# Invariant Where
1 Never report about a file that is not there Go fixture
2 Never claim a control exists from a text match without saying the evidence is weak Invariants
3 Never grade what it did not scan RefusesToGradeNothing (3.5.2)
4 Never ship text its own linter rejects validate-toolkit.sh (3.5.2)
5 Every check has a firing case and a quiet case CoverageGrid

Two more properties now hold across every fixture: a failing check always carries a recommendation, and no finding text uses an em or en dash.

The stop rule

The engine is done when the grid is full, the invariants have tests, and CI is green. After that a review hunts for a new class of defect, not a new instance of an old one, and a review that finds nothing counts as a pass. Only a bug report from a real user reopens the engine.

Full reasoning in docs/decisions/009, including the honest downside: fixtures are their own maintenance surface, and a fixture that misrepresents a real repo will make a check look covered when it is not. The count says a behavior is exercised. It does not say the behavior is right.

Test plan

  • 114 tests pass (was 92). Grid tests written failing first.
  • coverage_grid.py --fail-under 100 exits 0, and is now a CI step
  • ./scripts/validate-toolkit.sh green
  • --fail-on critical on this repo, exit 0
  • Version bumped in plugin.json and marketplace.json (x2), CHANGELOG entry, README states the number
  • CI green on this PR

All 68 tests asked whether a check fires. None asked whether it stays
quiet. That is the hole auth-2 fell through: wrong about half the time
it spoke, for three releases, green suite the whole way.

- Coverage grid: every check needs a firing fixture and a quiet fixture;
  skippable checks need an n/a fixture. 83 cells, 83 filled. Computed by
  running the audit over the fixtures, so it cannot drift. CI fails
  below 100 percent. scripts/coverage_grid.py prints it.
- Two false negatives it found in its first hour, both missed by three
  rounds of human review:
  * @sentry/nextjs did not count as error tracking. The matcher knew
    "sentry" and "@sentry" but not the scope prefix, so a Next.js app
    with Sentry wired up correctly was told at CRITICAL it had none.
    @vercel/otel and every scoped package likewise. @types/* still
    correctly excluded.
  * A plain migrations/ folder was never read for destructive SQL. Only
    Prisma, Drizzle, Alembic and Rails were known.
- Five invariants, each with a test, so a class of defect cannot return
  one instance at a time. Plus: every failing check carries a
  recommendation, and no finding text uses an em or en dash.
- The stop rule, in docs/decisions/009.

114 tests.
@tmoody1973
tmoody1973 merged commit 14d49a6 into main Aug 22, 2026
2 of 3 checks passed
@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@tmoody1973, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 31 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3560a563-e879-4be9-a41c-62a0ee921fad

📥 Commits

Reviewing files that changed from the base of the PR and between 42c7ee7 and a4f292a.

📒 Files selected for processing (10)
  • .claude-plugin/marketplace.json
  • .claude-plugin/plugin.json
  • .github/workflows/validate.yml
  • CHANGELOG.md
  • README.md
  • docs/decisions/009-coverage-grid-and-stop-rule.md
  • skills/prod-readiness-coach/scripts/audit/checks_runtime.py
  • skills/prod-readiness-coach/scripts/coverage_grid.py
  • skills/prod-readiness-coach/tests/fixtures.py
  • skills/prod-readiness-coach/tests/test_coverage_grid.py

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

Comment @coderabbitai help to get the list of available commands.

@tmoody1973
tmoody1973 deleted the feat/v3.6.0-coverage-grid branch August 22, 2026 23:42
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