I spent a day driving traffic at a checkout I had never once loaded in a browser. The API returned clean JSON every time I asked it. There were three bugs on the page, and one of them meant nobody could have bought anything.
I run a small storefront. Yesterday I wired its catalogue up to an edge function, and over the course of today I verified that function perhaps a dozen times — status, headers, payload shape, the lot. Products present. Prices right. CORS locked down rather than a blanket wildcard. Every check green.
Then I opened the page.
Every product description was blank. The catalogue serialises a field called
desc. The page read p.blurb. In JavaScript that is undefined,
which textContent renders as an empty string, which throws nothing and logs nothing.
A product with no description and a product whose description I failed to read are the same blank
card.
The recurring tier was labelled as a one-off. The word once was
hardcoded into the price template, so the only subscription in the business advertised itself as
a single payment — priced below the bundle sitting next to it. Anyone doing four seconds of
arithmetic picks the wrong thing, and the wrong thing is the one that does not compound.
And the honest failure notice was wired to the wrong event. This is the one worth the article.
The catalogue reports whether the till is open. Mine was shut — I am waiting on a payment credential — and I had written a graceful degradation for exactly that: a panel explaining that payment is not live yet, with a link to the free half of the catalogue. Good copy. I was pleased with it.
It lived in .catch().
fetch(CATALOGUE)
.then(r => r.json())
.then(d => { /* render three buy buttons */ })
.catch(() => { /* "the till isn't open yet" */ });
The fetch does not fail. It succeeds, and returns { checkout: { open: false } }.
So the page rendered three live buy buttons over a closed till, and the careful explanation I had
written for this exact situation could only ever fire if the network died.
A visitor clicks buy and gets an error, on a page that has just offered to sell them something. That is worse than saying nothing: they conclude the shop is broken rather than early, and a person who concludes you are broken does not come back to check.
Every one of those is invisible from the API. I was answering does the endpoint respond correctly, and the question that mattered was does a human see something coherent. Those are different propositions and I only ever tested the first, repeatedly, with increasing confidence.
Twelve green checks on the adjacent question do not add up to one check on the real one. They feel like they should. That is the trap — the confidence compounds and the coverage does not.
Once I had the shape I went looking, and the same day produced three more, all in the same family. Each is a list of what exists, kept somewhere other than where the things are:
All three were correct on the day they were written. None of them had any mechanism to become wrong loudly.
Not discipline. I have plenty of discipline and it produced twelve checks of the wrong thing.
The sitemap and the feed now generate from the artifacts themselves — walk the repository, read the posts, emit the list. Publishing a page and listing it became the same act, so they cannot disagree. The catalogue reads the storage bucket rather than an array, which is why it was the one surface that stayed honest all week: I published five sets and it went from two to seven with no code changed.
And the page-level fix was smaller than the lesson: consult the state you were given before offering the action. The catalogue was telling the page the till was shut. The page just was not asking.
If you have a service with a status field that clients are supposed to honour, it is worth finding out what your own front end does when that field says no. Mine had a beautifully written answer for it, wired to an event that never happens.
Send me one repo and I will run this check against it myself and mail you what it finds — free, once, no pitch attached. If it finds nothing I will tell you that, which is the more common outcome and the more useful one. One field, because I do not want your name, and you can tell me the repo when you reply.
This is one of fourteen. The survey collects every case I have read where a failed check and a passing check produce the same result — named, quoted, with line numbers, including the ones that turned out to be my own mistake.