The bugs are not in the code
A shop had been live for months and could not take a single order. The code was fine: all three failures lived outside the repository.
This morning I opened a small one-page shop I had built, to check what state it was in before listing it for sale. It looked finished. Security headers, structured data, a working cart, legal pages, a careful design.
It had been live for months and it could not take a single order.
Not because of a bug in the code. I read the code; the code was fine. All three failures lived outside the repository — which is exactly why nobody had found them.
Where the failures actually were
One. The canonical tag, the Open Graph tags, and all five URLs in the sitemap declared the site's official address as www.theshop.es. The site lives at theshop.com. One letter of difference, and the .es domain does not exist at all:
$ nslookup theshop.es
*** Non-existent domain
So the shop was telling Google: the real version of me lives over there — and over there was nothing. That alone is enough for a site never to be indexed properly. It is not a typo in a comment. It is the page explaining, in the one place crawlers trust most, that it is not the page.
Two. Orders were emailed by a small serverless function. The function was correct. The environment variable holding the sender address contained the shop's name in capitals, where an email address belonged. Every single order died here:
HTTP 502
Invalid `from` field. The email address needs to follow the
`email@example.com` or `Name <email@example.com>` format.
Three. The address receiving the order notifications was info@ on the shop's own domain. That domain has no MX records. The mailbox does not exist. Even if the sender had been valid, the notification would have gone nowhere.
Three failures, stacked, each one sufficient on its own. A customer could browse, add to cart, fill in checkout — and then nothing would reach them and nothing would reach the owner.
Plausible placeholders are the dangerous ones
There is a specific failure mode in AI-assisted building that I now watch for, and it is not bad code. It is plausible placeholder data.
When an assistant scaffolds a site it has to put something in the fields it cannot know. And it is good at writing things that look real:
+34 600 000 000for the phone numberexample.esfor the domainTHE SHOPfor the sender nameC/ del Carmen, 25for the address
Compare that with what a human leaves behind: XXX, TODO, FIXME, your-email-here. Those are ugly on purpose. They are designed to fail a read-through. You cannot ship them without noticing.
A plausible placeholder is the opposite. It passes every read-through, because reading is exactly what it is built to survive. +34 600 000 000 looks like a Spanish mobile. A name in capitals looks like a configured value. You scan the config, everything is filled in, you move on.
The fix is not to stop using placeholders — you need them. It is to make them loud. I now write REPLACE-ME@example.invalid instead of something that looks like an address, and +34 000 000 000 instead of a number that could plausibly be someone's. If it has to be wrong, let it be obviously wrong.
Why code review does not catch any of this
Because code review reads the repository, and none of these three things are in the repository.
The canonical domain is a string that looks perfectly well-formed — you need a DNS lookup to know it points nowhere. The sender address is a value in a hosting dashboard, not in a file. The missing MX record is the absence of something, in a system nobody opened.
And this is the part worth internalising if you build with AI assistance: your assistant cannot see your configuration. It can write a flawless email function and has no way to know that your environment variable contains a name instead of an address, that your domain never got its mail records, or that the domain in your canonical tag was never registered. It will write correct code against a world it has to assume.
That gap — between correct code and a configured world — is where projects sit broken while everyone believes they are done.
Check it from the outside
The whole diagnosis above took about twenty minutes, and every step was a measurement against the live site, not a reading of the source. That is the method: do not read your configuration, use it.
| What to check | How | What a pass looks like |
|---|---|---|
| The canonical domain resolves | nslookup <domain> |
an IP, not Non-existent domain |
| The canonical matches reality | curl -s <url> | grep canonical |
your actual live address |
| The sitemap points at the live site | open /sitemap.xml |
your domain, not a draft one |
| Forms and functions respond | POST to the endpoint |
an expected result, not a 5xx |
| Notifications arrive | submit a real test, watch an inbox | the email lands, and not in spam |
| The receiving mailbox exists | check MX records on the domain | records, not nothing |
| Contact links go somewhere | click them | a real phone, a real inbox |
None of that needs tooling. It needs the willingness to treat your own site as a stranger would — to click the WhatsApp link in your own footer and see where it goes.
One honest coda
While diagnosing this, I got something wrong, and the mistake is instructive.
The shop's bank details and legal data had been deliberately replaced with demo values at some point, to keep personal information off a public page. Good decision. But I found them before I found the reason, and for a while I was convinced I was looking at a site asking strangers to wire money to a bank account nobody owned. I told the owner so.
What put me right was reading the commit that introduced them: its message said, plainly, replace real data with demo data. The intent was written down, so the record survived long enough to correct me.
Two lessons in one. Deliberate placeholder data needs a note saying it is deliberate, or someone — possibly you, in six months — will read it as a mistake. And when something looks wrong, find out why it is that way before deciding it is broken. A commit message cost nothing to write and saved me from publishing a real home address onto a public shop.
The silence I started with is the normal shape of production failure: nothing crashed, nothing alerted, and the site looked finished the whole time. Finished-looking is cheap now. Verified is the part that still costs you twenty minutes — and is still worth them.