Manage Waivers
A waiver exempts a specific rule from gate enforcement for a given scope. Unlike tuning thresholds, waivers preserve your global policy while acknowledging specific, justified exceptions.
Scope Ladder
Each waiver has a scope. Most-specific match wins during evaluation:
- PR-scoped —
(org_id, repo_id, pr_number, rule)— applies only to that one PR - Repo-scoped —
(org_id, repo_id, rule)— applies across all PRs in that repo - Org-scoped —
(org_id, rule)— applies across all repos in the org
Missing fields = broader scope. Create an org waiver by leaving repo_id and pr_number null. Create a repo waiver by setting repo_id only.
Creating a Waiver
Example Waivers
PR-specific — emergency merge
POST /api/quality/gates/waivers
{
"rule": "new_critical_max",
"reason": "Hotfix for PROD-5512. Vulnerability in third-party SDK, upstream fix tracked in #7812. Rolling back to previous version via separate PR immediately after merge.",
"repo_id": 42,
"pr_number": 1087,
"expires_at": "2026-04-20T00:00:00Z"
}Repo-specific — known issue, scheduled remediation
{
"rule": "duplication_pct_max",
"reason": "Legacy monolith has 12% duplication. Refactor to shared utilities tracked in Q2 OKR. Gate disabled until 2026-07-01 scheduled review.",
"repo_id": 42,
"expires_at": "2026-07-01T00:00:00Z"
}Org-wide — temporarily lenient during rollout
{
"rule": "new_coverage_min",
"reason": "Org-wide testing push in progress. Coverage gates suspended until coverage baseline is established across all repos. Revisit 2026-06-01.",
"expires_at": "2026-06-01T00:00:00Z"
}How Waivers Affect Evaluation
When the gate runs, waived rules’ violations are stripped from the primary violations list and moved into a separate waived_violations field. The gate still passed if only waived rules are violating:
{
"status": "passed",
"violations": [],
"waived_violations": [
{ "rule": "duplication_pct_max", "threshold": 3, "actual": 4.2,
"severity": "high", "waived": true }
]
}The PR comment, Check Run, and dashboard widget all surface waived violations separately — with the reason — so reviewers know the exception is active and deliberate.
Viewing + Revoking
- List active:
GET /api/quality/gates/waivers— default hides expired + revoked - List all:
GET /api/quality/gates/waivers?include_expired=true&include_revoked=true - By repo:
GET /api/quality/gates/waivers?repo_id=42 - Revoke:
POST /api/quality/gates/waivers/{id}/revoke— soft-delete; stops honoring on next scan
In the UI: Settings → Policies → Quality Gates → Manage Waivers → toggle “Include expired/revoked” to see history. Trash icon on each row revokes.
Audit Trail
Every waiver stores:
created_by_user_id— who created itcreated_at— when createdrevoked_at— when revoked (null if active or expired)expires_at— scheduled expiry (null if permanent)reason— required text
No delete path. Revocation is soft. Records are preserved for audit.
Common Patterns
| Situation | Scope | Expiry |
|---|---|---|
| One-off emergency merge | PR | 24h |
| Known repo-level tech debt | Repo | Tied to remediation deadline |
| Awaiting upstream CVE fix | Repo or org | Tied to upstream release ETA |
| Vendor-mandated compensating control | Repo | Permanent (no expiry) + documented |
| Policy rollout easing | Org | Tied to full-enforcement date |
Related
- Set Up Quality Gates
- Policy as Code — for structural exemptions, prefer repo YAML over waivers
- Quality Gate API —
POST /quality/gates/waiversreference