The most valuable code we wrote this year isn't in the product. It exists to stop us shipping the same bug twice.
A bug gets found, the cause gets understood, the fix goes out, and everyone moves on feeling like the matter is closed. It usually isn't. The instance is closed. The class is still open, and the class is the part that costs money.
The bug you have already found is the cheapest bug you will ever have. Someone noticed it, you know its shape, you know which line was wrong. The expensive one is the same mistake made again in a different file eighteen months later by someone who never heard about the first one — including, increasingly, by an AI assistant that has no memory of it at all.
So the rule we work to is that an incident is not finished when the fix ships. It is finished when something mechanical exists that would have caught it, and that thing runs whether or not anyone remembers it.
Why “we'll be careful next time” doesn't work
Not because people are careless. Because care doesn't survive the conditions it has to survive in.
- The person who understood the bug is the least likely person to make it again. The value of what they learned sits with the one individual who no longer needs it.
- The fix is local; the mistake is general. You corrected one date calculation, one query missing a filter, one place where a value was hardcoded. Nothing you did stopped the next one appearing three directories over.
- Review catches what the reviewer thought to look for. A reviewer scanning a diff for logic errors will read straight past the category of mistake nobody has told them to watch for.
- Scar tissue doesn't transfer. New people, contractors, and AI coding tools all arrive without it. Anything that depends on having lived through the incident is a defence that decays as the team changes.
The common thread is that all four failures are about attention, and attention is the one resource you cannot add to. A check doesn't get tired, doesn't onboard, and doesn't have a busy week.
What separates a real guard from theatre
Most teams already agree with everything above and still end up with a pile of checks nobody trusts. The difference comes down to four properties, and the fourth is the one almost everyone skips.
- It is deterministic. It either passes or fails on the same input every time. A check that asks a model whether the code looks right is a useful reviewer and a terrible gate — you cannot build a rule on something that answers differently on Tuesday.
- It names the class, not the instance. If the bug was one page rendering a stale value, the check that matters is the one that scans every page for that pattern. A test that asserts the one fixed page is now correct only proves you fixed it, which you already knew.
- It fails at a gate, not into a log. The check has to sit somewhere that stops the thing it is guarding against — the commit, the build, the deploy. A warning printed into output that nobody reads is a slower way of not having a check.
- It has been proved to fail. This is the step that gets skipped. Before you trust a new check, break the code on purpose and confirm it goes red — then fix it and confirm it goes green. Both directions. An untested check is a piece of code whose only observed behaviour is passing, and code that only ever passes includes code that can never fail.
A check you have never once watched fail is not a safety net. It is a green tick you have chosen to believe.
That last point sounds pedantic until the first time you deliberately reintroduce a bug and the guard sails straight past it — a typo in a file path, a pattern that never matched anything, a script that exits zero when it crashes. We have caught all three in our own checks. Every one of them would otherwise have sat there for a year radiating false confidence, which is worse than no check at all, because an absent defence at least leaves you appropriately nervous.
Where it runs matters more than what it checks
Two placements do most of the work, and they fail in different ways.
Checks at the gate — before a commit lands, or in the build — are the strong form. They cannot be forgotten, because the thing you want to do doesn't happen until they pass. The discipline here is that the check has to inspect what is actually being shipped, not what happens to be sitting in your working directory. Those are not always the same thing, and a guard that reads the wrong one is a guard that verifies a file nobody is deploying.
Checks on a clock — the nightly sweep, the scheduled audit — cover the things you cannot know at build time, like whether the data in production still satisfies a rule your code assumes. They have one specific and nasty failure mode: silence is ambiguous. A scheduled job with nothing to report and a scheduled job that stopped running six weeks ago produce exactly the same amount of email. If a check runs on a clock, something has to watch the clock, and a missed run has to be as loud as a failure.
This is the same reasoning that led us to not run a test environment. Our confidence doesn't come from a staging copy that drifts away from reality — it comes from a growing set of checks that run against the real thing and fail loudly. Fewer rehearsals, more alarms.
The costs, honestly
This is not free and it is not always right. A flaky check is genuinely worse than nothing: the first time it fails for a reason that turns out not to be real, people investigate; the third time, they learn to re-run it; after that every failure it reports is invisible, including the true one. Our rule is blunt — a check that cries wolf twice gets fixed or deleted that week. There is no third strike, because the damage isn't the wasted hour, it is the habit of dismissal it teaches.
The other trap is the baseline. You write a check, run it for the first time, and it flags four hundred existing violations. The overwhelming temptation is to record those as accepted and only enforce the rule on new code. Sometimes that is the only practical path. But understand what you have built: a check that is permanently disabled for the exact places most likely to be wrong, with a list that no one will ever revisit. If you take that road, put a number on it and make the number visible, so the debt has to shrink rather than quietly become the furniture.
And the real limit: none of this catches novelty. Guards protect you from mistakes of a kind you have already made. They do nothing about building the wrong feature, misreading what a customer needed, or a failure mode you have never seen. That is precisely the argument for having them. Every class of mistake you automate away is attention returned to the problems that actually require a person.
The small version
You do not need a platform team or a testing strategy to start. The next time you fix something that went wrong in production, spend ten more minutes on two questions: what would have caught this before it shipped, and where does that thing have to live to run without me. Then write it, break the code to watch it fail, and put it in the pipeline.
One check per incident is a rate nobody notices and nothing else keeps up with. A year of that is a codebase where the mistakes you have already paid for can't be made again for free — which is a better definition of maturing software than almost anything you can see from the outside.
Software for service businesses — built by an operator.
Job management, books, and AI agents that actually know your business.