In the last post, I wrote about a specific issue: Snyk checks not running in GitHub merge queues, and how that breaks security validation at the point of integration.

It’s easy to look at that and think:

“That’s just a tooling gap.”

But it’s not.

It’s a symptom of something deeper.

The problem with “shift left”

We’ve spent years pushing quality earlier in the lifecycle.

  • run checks in PRs

  • catch issues before merge

  • give developers fast feedback

All good things.

But somewhere along the way, “shift left” quietly became:

“If we validated it early, we’ve validated it enough.”

And that’s where it breaks down.

Because systems behave differently in different circumstances:

  • in isolation (PR)

  • in combination (merge)

  • in environment (deploy)

  • under real conditions (runtime)

GitHub merge queues make this explicit. They require checks to run again on the combined state (merge_group) because the thing you are about to merge is not the same thing you validated in the PR.

The Snyk issue is just one example of that.

The real issue is this:

quality can regress between stages unless you enforce it where it actually matters

Which brings us to the real problem

We don’t have a detection problem.

We have a quality persistence problem.

A team identifies something undesirable:

  • flaky tests

  • recurring vulnerabilities

  • unreliable deployments

  • missing runbooks

  • weak alerting

  • manual rollback steps

People do the right thing. They investigate. They improve. They get the metric moving in the right direction.

For a while, everything looks better.

Then, slowly:

  • flaky tests creep back in

  • vulnerabilities reappear

  • pipelines degrade

  • incidents repeat

Not because teams don’t care - because nothing made the improvement stick.

Quality persistence is the idea that:

once you’ve improved something, the system helps prevent it from regressing

The key shift: from fixing → preserving

Most teams optimise for:

find → fix → move on

Quality persistence requires:

fix → encode → enforce → persist

What this looks like in practice

1. Turn improvements into constraints

  • “We reduced flaky tests”

  • “Build fails if flakiness exceeds X%”

2. Encode quality into pipelines

  • vulnerabilities → fail the build

  • test coverage → enforced threshold

  • deployment safety → gated

Quality becomes part of the delivery mechanism, not a side concern.

3. Close PIR loops properly

Most PIRs end with:

“We should improve X”

Quality persistence asks:

“How do we make it difficult (or impossible) for X to regress?”

⚙️ Examples

  • Flaky tests
    → detect + fail pipeline if reintroduced

  • Security vulnerabilities
    → block merge (including merge queue, not just PR)

  • Manual deployments
    → remove the manual path entirely

  • Incident learnings
    → convert into automated checks or signals

Keep Reading