skills/governing-quality-waivers/SKILL.md
Turns "we will skip this check for now" into a dated, attributed, expiring waiver with a stated reason and owner, inventories the silent skips already hiding in a repo - skipped tests, disabled lint rules, ts-expect-error, continue-on-error, lowered thresholds, coverage ignores - and reports expired waivers as findings. Use when a team wants to bypass a quality gate, when skip lists and quarantined tests accumulate without owners, when an audit asks why a check is off, or when a repo needs to know what it has quietly stopped enforcing.
npx skillsauth add jaktestowac/awesome-copilot-for-testers governing-quality-waiversInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this skill when something in the quality system is being switched off - or when you need to find out how much already has been.
Every repo accumulates skips. A test.skip from a sprint that ended, an eslint-disable-next-line nobody can explain, a continue-on-error: true added during an incident, a coverage threshold lowered to match reality. None were wrong at the time. All of them are now invisible, unowned, and permanent.
A waiver makes the same decision visible: same skip, but with a reason, an owner, and a date. That is the entire mechanism, and it is the difference between a considered trade-off and rot.
continue-on-error or a lowered threshold turns up in a diffBefore writing anything, establish what kind of skip this is:
| Kind | Example | Handling |
| --- | --- | --- |
| Not applicable | DAST on a library with no HTTP surface | not a waiver - remove the row from the contract with a reason |
| Deferred by maturity | mutation testing at crawl | not a waiver - it is next level's contract |
| Genuine waiver | contract testing postponed until the schema stabilises | waiver with reason, owner, expiry |
| Blocked work | integration tests need infrastructure nobody has provisioned | waiver plus a ticket for the blocker; the waiver expiry tracks the ticket |
| Refusal | a MUST practice someone does not want to do | not waivable - escalate as a contract or profile question |
Getting this classification right prevents the register from filling up with rows that were never waivers, which is what makes people stop reading it.
Use ./resources/waiver-register-template.md. Store the register where the contract lives - .qa/waivers.md, or the waivers: block of .qa/quality-contract.yaml.
- id: W-004
scope: coverage-rigor
paths: ['src/generated/**']
reason: >-
Generated OpenAPI clients. Tests would assert the generator's output, not our
behaviour. Regenerated on every schema change; the schema itself is contract-tested.
owner: '@maria'
created: 2026-08-21
expiry: 2026-12-01
review_trigger: 'if we hand-edit anything under src/generated/'
ticket: null
review_trigger is the field that earns its keep: an expiry catches time passing, a trigger catches the assumption breaking. A waiver justified by "this code is generated" should expire the moment someone edits it by hand.
| Situation | Expiry | | --- | --- | | This release only | the release date | | Waiting on a specific ticket | the ticket's target date, and name the ticket | | Waiting on a third party | 90 days, then re-justify | | Structural, no plan to change | do not waive - propose a contract change instead |
The last row matters. A structural exception dressed as a waiver expires, gets renewed unread, and pollutes the register. If the bar has genuinely moved, move the contract and say so out loud.
The high-value pass, especially on an inherited repo. Work through ./resources/silent-skip-inventory.md: skipped and quarantined tests, .only leaks, disabled lint rules, @ts-expect-error and any escapes, continue-on-error and || true in CI, coverage ignores and excludes, lowered thresholds, raised retries, --no-verify habits, allowlisted secret-scan and audit findings.
For each finding, one of three outcomes - and no fourth:
Report the count. "31 silent skips, 4 with any explanation" is the sentence that gets a team to act.
Findings, in order:
Enforcement worth wiring up: a CI step that fails when a waiver in the register has passed its expiry, and a review rule that a diff adding continue-on-error, .skip, or a lowered threshold must add a register entry in the same change. Both are cheap; the second is the one that stops accumulation at the source.
Review the register on a fixed cadence - release, sprint, or contract re-derivation - and ask three questions per entry:
The third question is the one that clears the register. Most expired waivers survive because renewal is easier than removal, and asking whether you would start it today breaks that.
./resources/waiver-register-template.md - the register format, worked entries, and the enforcement snippets for expiry checks./resources/silent-skip-inventory.md - every place a JS/TS repo hides a skip, with the search commands to find themderiving-a-quality-contract - where MUST/SHOULD/COULD is set, which decides what is waivable at allverifying-change-coverage - coverage exclusions are waivers and belong in the same registerrecording-change-intent - the sibling discipline: a waiver records why a check is off, an intent record records why a change was madeanalyzing-quality-metrics - waiver count and age are quality metrics worth trendingtech-debt-analysis - when silent skips are one symptom of broader debtassessing-release-readiness - expired waivers are release evidence, and belong in the go/no-go packThis skill is complete when:
testing
Tests the customization assets themselves - skills, prompts, custom agents, instructions - the way a product is tested: activation cases that check an asset fires when it should and stays quiet when it should not, output-contract cases, safety cases, collision cases between assets competing for the same trigger, a weighted rubric scored blind, and a baseline-versus-candidate gate before an edit ships. Use when a skill is edited and nobody knows whether behaviour changed, when two skills fight over the same request, when a description is being tuned for discoverability, when a collection has grown past manual spot-checking, or when the request mentions skill evals, prompt regression, or "does this skill actually work".
development
Shapes QA output for the person who has to act on it: result and blocker in the first two lines, one decision per report, findings ordered by what they cost, the long artifact in a file and the decisions in the message, and magnitude stated in units the reader can count. Use when a report is accurate but nobody acts on it, when a finding set is too long to read under time pressure, when the same findings must be retold for a developer, a release manager, and an on-call engineer, or when the request mentions "too long", "make this readable", "just tell me what to do", "so what", or "summarize this for stakeholders". Pairs with unslop-answers, which makes the same report honest.
testing
Verifies that the lines and branches a change actually touched are executed by tests, using LCOV or Cobertura diff coverage instead of whole-repo percentages, and escalates uncovered high-risk changes into a blocking finding. Use when a pull request needs a coverage gate that unrelated tests cannot satisfy, when total coverage looks healthy but the diff is untested, when wiring diff coverage into CI, or when someone claims a change is covered because the suite is green.
development
Cuts AI tells from test code: tests that pass without proving anything, tautological assertions, mock-only tests, hardcoded waits, coverage theater, vague names, swallowed errors, retries used as fixes. Use whenever test code is written, changed, or reviewed, including tests produced as a side effect of a feature task, and when the request mentions "review these tests", "are these tests any good", "this test always passes", "this suite is flaky", or "clean up these tests". Must always apply to test code.