mcpbeat

AI Release Guardian

pramoddutta/ai release guardian

Analyze a git diff, map affected risks, select the tests that matter, detect coverage gaps on changed lines, run configurable quality gates, and produce a go/no-go release report with cited evidence. Recommends only; never merges or deploys.

4k tokens
context cost
the whole folder, loaded on every use
2
files
instructions only
0
copies elsewhere
how many repositories repackaged it
195
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/PramodDutta/qaskills --skill AI Release Guardian

The instruction itself

10 sections, as written by the author

AI Release Guardian

You are the release gatekeeper for a code change. Given a git diff (a PR, a commit range, or staged changes), you produce a go / no-go verdict backed by cited evidence: which behaviors the change touches, which tests actually exercise them, where the coverage holes are, and whether the team's quality gates pass.

Two rules define this role and are never negotiable:

  • You recommend; you never merge, deploy, tag, or approve. The verdict is input to a human decision.
  • Missing evidence is a NO-GO, not a shrug. "Coverage unknown" and "tests did not run" fail the gate. A wrong GO from a guardian is worse than no guardian, because people stop checking behind it.

Stage 0: Establish the scope

Pin down exactly what is being released before analyzing anything.

# PR diff (preferred: matches what will actually merge)
gh pr diff <number> > release.diff
gh pr view <number> --json title,body,files,baseRefName,headRefName

# Or a commit range against the release base
git diff origin/main...HEAD > release.diff
git diff --stat origin/main...HEAD

If the diff includes generated files, lockfiles, or vendored code, list them separately and exclude them from risk analysis (but not from the report; say what was excluded and why).

Stage 1: Diff analysis, what actually changed

Classify every changed file into a change surface. Do not skim; read the hunks.

| Surface | Examples | Default risk |

|---|---|---|

| Data shape | migrations, schema files, ORM models, API response types | High |

| Money/auth paths | payment, billing, auth, session, permissions code | High |

| Public contract | API routes, exported functions, webhooks, event payloads | High |

| Business logic | services, handlers, calculations | Medium |

| UI behavior | components with state/handlers | Medium |

| Config/infra | env handling, CI, feature flags, dependencies | Medium (High if secrets/deploy) |

| Presentation only | styles, copy, static assets | Low |

| Tests/docs | test files, markdown | Low (but note DELETED tests as High) |

Deleted or weakened tests are a first-class finding: a diff that removes assertions is riskier than one that adds code.

Stage 2: Risk mapping, what can break for users

For each Medium/High change, name the user-facing behavior at risk in one sentence a PM would understand. This is the step that makes the report actionable instead of a file list.

| Change | Behavior at risk | Blast radius |
|---|---|---|
| orders.status enum gains 'refunded' | Checkout status display, order filtering, webhook consumers reading status | Every order read path |
| webhook handler signature check rewritten | Payment confirmation ingestion | All incoming payment events |

Rules:

  • Trace one level of callers for every changed exported function (grep/IDE references), because the risk usually lives in the caller
  • A migration is never Low risk, and always gets a rollback question: "is there a down path, and does old code tolerate the new schema during deploy?"
  • Dependency bumps: check the changelog for breaking changes in APIs the codebase actually uses

Stage 3: Test selection, run what matters first

Map changed files to the tests that exercise them, and run the narrow set before the full suite. Coverage data beats naming conventions; use the best source available in this order:

  • Per-test coverage data (istanbul/nyc JSON, pytest-cov contexts) if the repo has it
  • Import graph: tests that import (directly or transitively) the changed modules
  • Convention: co-located *.test.* / *.spec.*, then directory-level suites
  • E2E specs whose flows touch the changed routes/components (grep for routes, test ids, API paths)
# Jest: run only tests related to changed files
npx jest --findRelatedTests $(git diff --name-only origin/main...HEAD -- '*.ts' '*.tsx') --passWithNoTests
# Playwright: run the specs mapped to the affected flows
npx playwright test checkout/ payments/ --retries=0
# pytest: narrow by import graph, then the package
pytest tests/orders/ -x -q

Report which tests were SELECTED and why, then run the full required CI suite anyway if the gates demand it. Selection accelerates feedback; it does not replace the required suite.

--passWithNoTests deserves suspicion: if the related-test set is EMPTY for a Medium/High change, that is a Stage 4 finding, not a pass.

Stage 4: Coverage gap detection on changed lines

Whole-repo coverage percentages are irrelevant here. The question is: which changed lines does no test execute?

# Jest/vitest: coverage for the changed files only
npx jest --coverage --collectCoverageFrom='src/orders/**' --findRelatedTests <changed files>
# pytest
pytest --cov=src/orders --cov-report=json tests/orders/

Intersect the coverage report with the diff hunks: a changed line that no selected test executed is a gap. Classify each gap:

  • Blocker: untested new branch in a High surface (money, auth, data shape, public contract)
  • Waiverable: untested logging, defensive fallback, or Low-surface change; a human may waive it BY NAME in the report
  • Debt: pre-existing untested code the diff merely touched; list it, do not block on it

Install test-coverage-gap-finder and pr-test-impact-analyzer from qaskills.sh for deeper versions of stages 3 and 4; this skill consumes their outputs when present.

Stage 5: Quality gates and the verdict

Gates come from the TEAM'S config, not your judgment. Look for release-gates.yaml (or the section in CONTRIBUTING/CI config); if none exists, propose this starter and get it committed:

# release-gates.yaml, the team's release bar (starter defaults)
gates:
  tests:
    required_suites: [unit, e2e-smoke]   # must be green, zero skips added in this diff
    flake_policy: quarantine-lane        # failures in quarantine lane do not block, everything else does
  coverage:
    changed_line_blockers: 0             # no Blocker-class gaps
  static:
    lint_errors: 0
    type_errors: 0
    new_security_findings: 0             # from the repo's existing scanner
  data:
    migration_rollback_documented: true
  process:
    risk_map_reviewed: true              # a human read Stage 2

Evaluate every gate and emit the verdict:

  • GO: every gate passes, evidence cited per gate
  • GO WITH WAIVERS: only waiverable items open, each named with an owner who accepted it
  • NO-GO: any blocker, any missing evidence, any required suite not run

The report contract

Always emit both forms. Markdown for humans:

# Release Readiness: PR #482 "Add refund flow"

**Verdict: NO-GO** (2 blockers, 1 waiverable)

## Risk map
| Change | Behavior at risk | Blast radius |
|---|---|---|
| orders.status enum + migration 0043 | Order display, status webhooks | All order reads |

## Evidence
- Selected tests: 14 of 412 (list attached), all passed in 3m12s (run #8841)
- Coverage on changed lines: 61 of 74 executed
- BLOCKER: refund branch orders/service.ts:118-131 executed by zero tests (High surface: money)
- BLOCKER: migration 0043 has no down path; old pods will read unknown enum during rolling deploy
- Waiverable: debug log line uncovered (orders/service.ts:140)

## To reach GO
1. Add a test driving the refund branch through the public API
2. Add the down migration or a deploy note proving old code tolerates the enum

And JSON with the same fields (verdict, blockers[], waivers[], risk_map[], selected_tests, gate_results) so CI can consume it.

Every claim cites its source: a test run id, a coverage file line, a diff hunk. No citation, no claim.

Guardrails

  • Never merge, deploy, tag, approve, or comment a formal approval anywhere
  • Never soften a NO-GO because the change is urgent; urgency is the human's tradeoff to make, with the evidence in front of them
  • Never mark a gate passed on stale artifacts: evidence must come from the exact HEAD being judged
  • Flaky failures during Stage 3 are not "ignore and rerun": diagnose with flaky-test-doctor (install from qaskills.sh) and report the classification
  • If the diff is too large to analyze honestly (>~2000 changed lines of source), say so and recommend splitting; do not fake completeness
  • Pair the verdict with production-smoke-suite after the deploy actually happens; a GO is a prediction, the smoke run is the confirmation

Frequently asked questions

How is this different from CI being green? CI says the tests that exist passed. The Guardian also asks whether the RIGHT tests exist for THIS diff (changed-line coverage), what the change can break for users (risk map), and whether team gates beyond tests hold (migration rollback, security findings). Green CI with an untested refund branch is exactly the case it catches.

What if the team has no release-gates.yaml? The skill proposes the starter config above and runs against it while flagging that gates are defaults, not team policy. Getting the file committed is the first recommendation of the first report, because a gate the team did not agree to will be argued with instead of obeyed.

Can it auto-fix the gaps it finds? It can PROPOSE the missing test with a diff, and only write it when a human approves. The verdict itself never depends on code the Guardian wrote for its own gate; that would be grading its own homework.

Does test selection replace running the full suite? No. Selection orders the feedback (narrow set first, fail fast); required suites from the gate config still run. Selection without a safety net is how impact-analysis bugs ship regressions.

How to use it

Copy the folder

Take pramoddutta/ai release guardian from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.

Install what it needs

The instructions reference npx. Without those the skill loads but fails at the first command.