Home Lessons LearnedWe Find Them Faster Than We Fix Them

We Find Them Faster Than We Fix Them

by Marc

I gave an agent one rule: close as many of my tickets as you honestly can, where “done” has to survive someone checking it. Two days later I had closed four tickets and opened nineteen.

Ten of those nineteen were bugs. Not new work, not scope creep. Defects already running in production, found while checking whether something else was finished.

That is the whole post. Verification is cheap now, so we do it properly, and doing it properly turns up more than we can repair.

What checking actually costs you

The old economics of a ticket were simple. Someone writes the code, someone glances at the diff, it merges, the ticket closes. Nobody opens the warehouse and asks whether the number on the dashboard actually moved, because that is an afternoon and the ticket is already green.

An agent will just go and look. Every time. So “is this done” stops being a judgement call and becomes a query, and the query returns things you did not ask about.

Tickets closed 4
Tickets opened 19
Of which bugs 10

The defects are old

This is the part that changed how I think about it. I dated eleven of them properly, by finding the commit that introduced the broken string rather than trusting what the ticket said.

Ages at discovery, in days: 8, 81, 131, 260, 272, 323, 399, 1034, 1112, 1294, 1826

Median 323 days. Four older than two years. One in eleven was a recent regression.

So the backlog is not filling with things we just broke. It is filling with a stock that was always there, being read by people, producing wrong numbers the whole time. A conversion rate reported at five times its real value. An executive average order value shown as falling when it was rising. A revenue figure overstated by 3.6 million pounds on a customer-facing table.

Why depth makes it worse

The defects that survive are the quiet ones. Anything that throws an error gets found within hours by whoever is on call. Anything that returns a plausible wrong number has nothing arguing for its existence, so it sits.

In a shallow system you run out of those quickly. In a warehouse with a dozen layers between a source table and a dashboard tile, every layer is another place for a plausible wrong number to live, and nothing downstream can tell that what it received is wrong.

Everything found on those two days had that shape. A deploy command that silently replaced an entire environment, after which the next run reported success because an unconfigured job has nothing to do. A validation threshold that skipped its own check when the value was not a number. An alert that reported nothing had been published regardless of what had been published. A test that passes at a zero percent match rate, because a failed lookup is null and the test skips nulls.

Every one of those had been green for months.

It is not closing that finds them

Worth being precise about the mechanism, because I had it wrong at first. I assumed you find things while closing a ticket.

Seven of the nine discoveries came from tickets that did not close. Several stayed open precisely because the check found something. The generator is going to look at the running system in order to decide whether something is done. What happens to the ticket afterwards is a side effect.

Does it converge?

I think it does, and faster than the stock alone would suggest, because two separate things are shrinking at once.

The old defects are finite. There is some number of them sitting in the warehouse right now and every one we find is one fewer. That part drains on its own, and the discovery rate should fall as it does.

The flow of new ones is shrinking too, which is the part I initially got wrong by treating it as a constant. The code going in now is not the code that produced a 323-day-old defect. Every fix in those two days shipped with tests, and each test was proved to bite by breaking the behaviour and watching it fail. One repository went from 473 checks to 799 in a day. Defects written under that regime mostly do not survive to be written.

And the third lever is the one that matters most, because it attacks the thing that let the stock form at all. Every example above is something that could not be determined being quietly treated as something that was. A deploy that wiped a configuration and reported success. A threshold that skipped its own check. A test that passes at a zero percent match rate. Each of those now fails its run and says why.

That does not just find bugs faster. It shortens how long a new one can stay hidden, from months to a single run. A defect that fails loudly on the day it ships never joins the stock, and never gets to be 323 days old.

So the end state is not a system where nothing ever breaks. It is one where nothing breaks quietly.

You may also like

Leave a Comment