Here is a bug I nearly shipped, and the reason I nearly shipped it is that everything about it was correct.
An assistant bot I run posts recap cards into a chat room. For a long time those recaps were PNG screenshots — a headless browser rendered a card and uploaded the image. Then the bot gained a fragment renderer that turns a card’s stored spec into real HTML: selectable numbers, clickable sources, reflows to one column on a phone, about 22 KB against the screenshot’s 180 KB. Strictly better in every dimension I cared about.
The remaining work was to make recaps emit a spec, so the new renderer would have something to render. I was one commit from doing that when I went looking for how the front end would pick the fragment over the picture, and found this:
got = <the PNG, fetched from the chat server's media store>
html = "" if got else await _spec_card_html(bot, card)Read it in isolation and it is fine. It says: use the spec when there is no picture. That was written when a card had either a picture or a spec, which was true of every card that existed at the time.
A recap has both.
So the fragment would never have been built. The screenshot would have kept being served. The entire feature — a renderer, a spec format, the emitter I was about to write — would have shipped and changed nothing on screen. No error. No empty element. No log line. The dashboard would have looked exactly as it did the day before, because it would have been exactly as it was the day before.
The general shape
When you add a second, better way to produce something, the code that picks between them predates the choice.
It was written when there was one option, so its shape is “the thing, or
nothing” — A if A else B, x = get(a) or get(b), a try with an except
fallback, a default parameter, precedence in a config merge. And the moment a
better thing exists, that same unchanged line silently starts meaning prefer
the worse one.
The line does not change. Its meaning does.
That is worth stating precisely, because it is the whole trick: A if A else B
is a correct statement of “B when A is missing” and a wrong statement of “B is
better than A”. Nothing distinguishes those two readings at the moment it is
written, because B does not exist yet. You cannot review your way out of this
at write time. There is nothing there to catch.
Why it survives testing
Both halves are correct, and both halves have tests. The producer’s test asserts that the producer produces. The renderer’s test asserts that the renderer renders. Both pass. Both should pass — neither is broken.
A join has no natural owner in a test suite. Nobody’s unit test is responsible for the one thing that is wrong, because the thing that is wrong isn’t inside either unit. It is the order in which a third piece of code consults them.
And then there’s the failure mode itself, which is the cruellest part: the failure mode is the previous behaviour. Not a crash, not a blank panel, not a 500. The old thing, working, exactly as it always did. It is indistinguishable from having not deployed yet — which means the natural debugging instinct (“did my deploy land?”) produces evidence that is consistent with both the bug and the absence of the bug.
This is a cousin of a broader defect class: an artefact that is genuinely present, genuinely well-formed, and completely inert. A hotkey that survives a config rewrite while being invalid. A script tag that lands in the DOM and never executes. The difference here is that the inertness is caused by a live, deliberate, correct-looking line somewhere else, written by someone who was right at the time.
The shape of the fix
Change the selection point in the same commit as the new producer. Not as a follow-up. A follow-up is precisely what gets dropped when the feature “works locally” — and it works locally, because locally you tested the renderer directly.
Grep for the chooser, not the consumer. When you add a producer, the useful
search is not “who calls the new thing” — nobody does yet, that’s the point.
It is “what already decides between things in this area”. Look for if X else,
or, .get(a) or .get(b), try/except with a fallback path, default
parameters, config-merge precedence, feature-flag defaults. Every one of those
is a decision made before your alternative existed.
Assert the order, not the producer. The test that catches this reads like “the fragment is built before the picture is fetched”. It feels like testing implementation detail, which is why nobody writes it. It is also the only thing that fails when the join is wrong. If you find yourself objecting that it over-specifies — yes. That is the feature. The order is the requirement.
Ask what the new thing is competing with. One question, asked once, at design time. If the answer is “nothing, this is a new surface”, the feature is additive and safe. If the answer is “the thing that already works”, then there is a precedence decision somewhere in the codebase, you did not write it, and it is currently pointing the wrong way.
I found mine by asking a different version of the same question before writing the feature rather than after: what would prove this reached the page? Not “does the renderer work” — it does — but what observable fact, on the real dashboard, would be different. Ask it afterwards and you get a demo of the renderer. Ask it first and you have to trace the path, and the path is where the bug lives.
The rule: when you add a better producer, fix the chooser in the same commit — a fallback ages into a preference.
sources: concepts/the-fallback-outranks-the-upgrade, concepts/present-is-not-active