Teams should separate new code from legacy code and enforce quality gates only on what is added or changed. That approach keeps the focus on work developers are already touching, reduces regression risk, and prevents endless refactoring campaigns. Over time, the codebase improves incrementally because each sprint adds less debt instead of more. The practical goal is clean delivery, not heroic cleanup.
Why quality gates should move with the code, not fight the whole legacy base
The practical problem is not whether the old code is perfect, it is how to keep new work from inheriting old defects. When a codebase already carries technical debt, broad “fix everything” standards usually stall delivery and create uneven enforcement. A change-scoped approach keeps quality expectations tied to the code that is actually being written or modified.
That distinction matters because teams can control the risk introduced by current changes, but they usually cannot absorb a full rewrite without slowing the product. Quality gates on touched code create a stable bar for each commit or pull request, while the legacy code remains a separate remediation backlog.
What “separate new from legacy” means in day-to-day engineering
Separation can be physical, logical, or process-based. Common patterns include new modules, clear ownership boundaries, stricter linting or test thresholds for changed files, and explicit exceptions for inherited hotspots. The goal is not to excuse bad code, but to stop the next release from making the debt worse.
This also changes how teams read test and review results. A failure in untouched legacy code should be treated as technical debt inventory, while a failure in new or modified code should block merge. That split helps reviewers focus on regression risk, code churn, and whether the current change meets the team’s standard.
Incremental enforcement works best when teams can tell what is genuinely new. Diff-based checks, path-based ownership, and baseline comparisons all support that model. Without that separation, quality policies become arbitrary, because developers cannot tell whether they are accountable for old weaknesses or for the current change set.
How to keep the quality bar real without turning it into a rewrite programme
Teams should treat quality gates as a control on forward motion, not as a repair plan for the entire repository. The most effective rule is simple: if code is added or altered, it must meet the current bar; if code is inherited and untouched, it belongs to a tracked remediation queue. That keeps the system improving without demanding a wholesale cleanup before any progress can happen.
Over time, that discipline changes the debt curve. Each sprint can reduce the proportion of code that fails current standards, even if the legacy tail remains. The result is a codebase that becomes safer and easier to maintain through normal delivery, rather than through disruptive “big bang” refactors.
One useful sign of maturity is that teams can raise standards for new code without repeatedly breaking delivery. If the gate only exists on paper, or if exceptions quietly accumulate, the policy is not really protecting quality. The practical test is whether recent changes are consistently better than the baseline they inherited.
Risk and Threat Considerations
When teams apply one standard to both new and legacy code, they can create either paralysis or blind spots. If the bar is too strict for inherited code, delivery slows and engineers bypass the process; if it is too loose everywhere, new defects and insecure patterns enter the codebase unchecked.
Failure mechanism: the organization conflates remediation of historical debt with validation of current changes, so the review process stops distinguishing inherited risk from newly introduced risk. That often produces exception fatigue, inconsistent enforcement, and hidden regression exposure in the exact files that matter most.
Impact: teams lose the ability to trust their quality gate as a release control, and the codebase slowly accumulates more defects even while appearing to have standards in place. In regulated or high-change systems, that can also make audit evidence and release accountability harder to defend.
Practitioner Guidance
What to prioritise: make the first-line rule binary, touched code must meet the current standard, untouched legacy code must be tracked separately. That keeps review conversations focused on what the change introduces, not on reopening the entire history of the repository.
What to verify: your pipeline should be able to identify changed files reliably and apply different thresholds or tests to them. If the toolchain cannot separate touched from untouched code, the policy will drift into subjective review and will be hard to enforce consistently.
Common mistake: treating every legacy defect as an immediate blocker. That usually converts quality management into a permanent refactoring programme and leaves teams unable to ship. The better discipline is to block new debt, then burn down old debt deliberately.
Practitioner takeaway: the right standard is not “fix all debt now,” it is “do not add avoidable debt to code you are already changing.” That is what makes quality sustainable in a legacy environment.
Related resources from NHI Mgmt Group
- How should engineering teams reduce the long-term cost of poor code quality before it becomes technical debt?
- How should security teams make NHI best practices usable across the business?
- How should security teams implement sink-side validation for user-controlled IDs in legacy application code?
- How should security teams reduce risk when legacy RBAC leaves large amounts of unused permission in place?
Deepen Your Knowledge
Reviewed and updated by the NHIMG editorial team on September 26, 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org