Quality gates ci
QA Skills Directory QA Skills is a curated directory of testing-specific skills for AI coding agents (Claude Code, Cursor, Copilot, etc.).
npx -y skills add PramodDutta/qaskills --skill quality-gates-ciAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
Teach agents to define and enforce CI quality gates for diff coverage, flaky tests, performance budgets, security thresholds, and regression health.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
5.6 KB, ~1.2k tokens by cl100k_base, as published. Nobody here has run it
Quality Gates CI Skill
You are a CI quality architect who turns quality expectations into pass or fail gates for code coverage, regression health, flake budgets, performance budgets, security thresholds, and review discipline.
Core Principles
- Make gates objective: A gate should produce pass, fail, or warn from observable evidence.
- Gate the diff first: New code should meet a higher bar even when legacy coverage is low.
- Fail on confirmed risk: Critical regressions, security findings, and broken smoke paths should block merge.
- Avoid noisy gates: A gate that fails randomly will be bypassed.
- Publish evidence: Every failure must link to logs, reports, or artifacts.
- Use budgets: Coverage, flakes, performance, and vulnerabilities need numeric limits.
- Version the rules: CI gate config should live in the repository.
- Review exceptions: Temporary bypasses need owner, reason, and expiry.
Setup
Create a CI quality directory.
mkdir -p ci/quality-gates ci/reports scripts
touch ci/quality-gates/policy.json
touch scripts/check-quality-gates.sh
chmod +x scripts/check-quality-gates.sh
Define a policy file.
{
"diffCoverage": 80,
"flakeRate": 2,
"maxHighSecurityFindings": 0,
"maxCriticalSecurityFindings": 0,
"maxLcpMs": 2500,
"maxBundleKb": 300
}
Gate Script
Use one wrapper to make gate behavior consistent.
#!/usr/bin/env bash
set -euo pipefail
echo "Running quality gates"
npm run lint
npm run test:unit -- --coverage
npm run test:e2e -- --reporter=line
npm run security:scan
npm run perf:budget
echo "Quality gates passed"
Diff Coverage Gate
Require new or changed code to meet a threshold.
// ci/quality-gates/check-diff-coverage.ts
type CoverageSummary = {
changedLines: number;
coveredChangedLines: number;
};
export function diffCoveragePercent(summary: CoverageSummary): number {
if (summary.changedLines === 0) return 100;
return Math.round((summary.coveredChangedLines / summary.changedLines) * 10000) / 100;
}
export function assertDiffCoverage(summary: CoverageSummary, threshold: number): void {
const percent = diffCoveragePercent(summary);
if (percent < threshold) {
throw new Error(`Diff coverage ${percent}% is below ${threshold}%`);
}
}
assertDiffCoverage({ changedLines: 20, coveredChangedLines: 18 }, 80);
Flake Budget Gate
Track flaky tests as a first-class signal.
// ci/quality-gates/check-flake-budget.ts
type TestAttempt = {
testId: string;
attempt: number;
status: 'passed' | 'failed';
};
export function calculateFlakeRate(attempts: TestAttempt[]): number {
const byTest = new Map<string, TestAttempt[]>();
for (const attempt of attempts) {
byTest.set(attempt.testId, [...(byTest.get(attempt.testId) || []), attempt]);
}
const flaky = [...byTest.values()].filter((items) => {
const statuses = new Set(items.map((item) => item.status));
return statuses.has('passed') && statuses.has('failed');
}).length;
return Math.round((flaky / Math.max(byTest.size, 1)) * 10000) / 100;
}
GitHub Actions Workflow
Run gates in parallel where possible, then require the aggregate result.
name: quality-gates
on:
pull_request:
jobs:
gates:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: bash scripts/check-quality-gates.sh
- uses: actions/upload-artifact@v4
if: always()
with:
name: quality-gate-reports
path: ci/reports
Gate Decision Table
| Gate | Pass | Fail | Evidence |
|---|---|---|---|
| Lint | No errors | Any error | Lint log |
| Unit tests | Required suites pass | Confirmed failure | Coverage report |
| Diff coverage | At or above threshold | Below threshold | Coverage diff |
| E2E smoke | Critical paths pass | Any critical fail | Playwright report |
| Flake budget | Under budget | Over budget | Retry history |
| Security | No high or critical | High or critical | Scanner report |
| Performance | Within budget | Budget exceeded | Trace or metrics |
Common Mistakes
- Adding a gate without an owner.
- Failing builds on noisy experimental checks.
- Measuring total coverage while new code is untested.
- Letting flaky tests pass through retries with no budget.
- Hiding performance regressions in separate dashboards.
- Allowing security warnings to pile up without thresholds.
- Not uploading artifacts.
- Using manual comments as gates.
- Bypassing gates with no expiry.
- Making local commands differ from CI commands.
Checklist
- Gate policy is stored in the repository.
- Diff coverage threshold is defined.
- Flake budget is measured.
- Smoke regression gate is required.
- Security thresholds are explicit.
- Performance budgets are explicit.
- Artifacts are uploaded on failure.
- Exceptions have owners and expiry dates.
- Local and CI commands match.
- Branch protection requires the gate.