Picture a house with a burglar problem. The first time, they came through the front door, so you fit a better lock. The second time, the kitchen window, so you fit bars. The third time, the roof. At some point a sensible person stops buying locks and asks a different question: why does everything I own have to be inside this house?
We lived that earlier this month, with code.
What we were building
A small guard whose whole job was to refuse to run when a list it depends on turned out empty. Simple to say. The trouble is that the guard runs inside an environment that anyone launching it can shape, and a hostile launcher has a lot of ways to make "empty" look like "fine".
The first review round found a plain path around the guard. The coder fixed it. The second round found two more: a function imported from outside that swapped the exit code, and a scratch file the check trusted too early. Fixed, both of them, properly. The third round found a fourth door, one the earlier fixes could not have seen, because it lived in a part of the environment the guard never looked at.
Every one of those fixes was good work. The reviewers said so on the record. "The failure this round is not a regression in what was fixed. It is a door outside the two tables the fix reads." That sentence is the whole story. The coder was not losing. The design was.
The rule
We now have a written rule for this. If the same class of failure comes back three times through different doors, the lane stops. No fourth fix without a ruling. The question on the table is no longer "who patches it" but "why does this design have so many doors".
Three reds on one class is not a bad coder. It is a design that hands the attacker more doors than you can fit locks.
What the redesign looked like
We inverted the direction of the evidence. Instead of the guard defending itself against every trick its environment could play, it now produces a small receipt of what it actually did, and a separate checker, running somewhere the launcher cannot reach, reads that receipt. An environment that lies can stop the guard from running, but it cannot forge a valid receipt. The problem changed shape: from "block every door" to "make one thing the attacker cannot produce".
The same inversion closed a second stuck build the same day, one that had spun through six rounds on a sister project. That is what happens when you stop patching and change the question.
Why this is hard to do in the moment
Because each fix feels like progress. The reviewers approved it. Nobody wants to say "throw it away" after a week of green ticks. The three-red rule exists so that nobody has to be brave. The count does it for you.
We stay until it works. Sometimes that means admitting the thing we were staying with was the wrong thing.
For the technical reader
The guard was a bash roster check with a fail-closed contract: zero arms must exit non-zero. Round one bypassed it via a plain PATH edit. Round two used an imported function shadowing the exit builtin and a pre-frozen scan scratch. Round three used alias expansion, which lives in a table the fix's guards never read, since they inspected only the function and builtin tables. Bash offers more of these doors than we can enumerate: DEBUG traps, PATH shims, loadable builtins. The adversary enumerates interpreter features faster than guards accrete.
The rescope moved from guarding the interpreter the roster runs in to verifying an artefact the roster emits: a signed run receipt read by an external checker with its own input surface sealed on the launcher side. The parked branch was kept as evidence, not deleted. The rule is now written into our build discipline: non-convergence declared by two consecutive review rounds on one failure class floors the work item to a design decision, with "one more guard" listed as the disfavoured option by default.