Your quality gate should only judge new code
A common quality gate looks like this: overall test coverage must be at least 80%, and there must be no more than N code smells in the project. It sounds rigorous. In practice it measures the codebase’s history, not the change in front of you, and it creates the wrong incentives.
- A team with an old, under-tested service can never pass, so the gate gets disabled or the threshold quietly lowered.
- A developer fixing a small bug in a legacy file inherits the blame for everything else in it.
- The easiest way to raise overall coverage is to add shallow tests to code that’s easy to test, not the code that’s risky.
Judge the change, not the codebase
SonarQube’s approach, which it calls Clean as You Code, is to apply the gate to new code only: lines added or changed in the current branch, or since a defined baseline. A typical gate:
- No new bugs or vulnerabilities.
- Every new security hotspot reviewed.
- Coverage on new code of at least 80%.
- Duplication on new code below 3%.
Old code is judged only when someone touches it, and then only the lines they touched. Every change leaves the code a little better than before, and coverage on the parts that actually change rises steadily. The overall number improves as a side effect instead of being the target.
Set the new-code baseline on purpose
“New code” needs a reference point. For pull requests, it’s the target branch. For the main branch, choose a period: the previous version, a number of days, or a reference branch. Pick one that matches how you release, and keep it stable, so the gate means the same thing every time.
Why this matters more in 2026
A growing share of new code is written with AI assistance. That code is often plausible, often correct, and sometimes subtly wrong in ways a quick human review misses. A gate focused on new code is exactly where that code gets checked: every generated function needs tests, every new hotspot gets a human decision, and nothing is waved through because the project’s overall numbers look fine.
Coverage isn’t the goal; tested behavior is
Coverage on new code is a useful floor, not a measure of quality. A test that runs a function and asserts nothing earns full coverage. Two habits keep the number honest:
- Review tests as carefully as the code. In a pull request, ask what behavior each test protects and what failure it would catch.
- Prefer a few meaningful tests on risky code (money, permissions, data deletion) over many shallow ones on simple code.
Make the gate fast and non-negotiable
A gate that takes 20 minutes gets bypassed. One that takes two minutes and gives a clear, specific reason when it fails becomes part of the workflow. Run it on every pull request, report the result inline, and don’t allow merges that fail it. A gate with exceptions is a suggestion.