This week I found out my site thought the earth was flat. Twice. I also found the one link that had been quietly spending my entire crawl budget on URLs that did not exist the day before, and spent an evening breaking and then unbreaking my own link previews.
All of it was built with AI. All of it was found with AI. I want to be precise about what that actually means, because "vibe coding" is doing a lot of work in people's heads at the moment, and the reality is more useful than either the hype or the sneering.

The earth is not flat
The first bug is my favourite, because it is so obviously wrong once you see it.
To find "hotels near this point", you draw a box around the point and then measure precisely inside it. Drawing that box means converting kilometres into degrees. The code did this:
``` if (Math.abs(candidate.lat - lat) > 0.5) continue if (Math.abs(candidate.lng - lng) > 0.5) continue ```
Half a degree, on both axes, with a comment cheerfully explaining that this was generous for a 25km search.
Half of that is true. Half a degree of latitude is about 55km anywhere on the planet — the lines are parallel. Half a degree of longitude is about 55km at the equator and zero at the poles, because the lines converge. It shrinks with the cosine of the latitude.
At London's latitude, 51.5°N, half a degree of longitude is 35km. The caller was asking for 35km. So from London northwards, that filter could quietly throw away the nearest city and hand back the second nearest, with nothing to show it had happened.
The same mistake was in a second file. When I went looking for the consequences, I found 2,247 hotel records — 3.2% of the catalogue — linked to a city more than 75km away. 1,550 of them were linked to a city more than a thousand kilometres away. Same city name, wrong continent. After the repair, none are beyond 75km and 98.35% are within 25.
Then, testing the fix, I found a third version of the same family. The distance function measured longitude by subtraction, which works fine until you cross the 180th meridian. Two points 20km apart either side of that line came out as 39,000km apart. In practice that meant Fiji, Chukotka and the Samoas. Asking "what's the nearest city" from one side of the line returned nothing at all, while a real town sat 75km away on the other side.
None of these were exotic. They are the sort of thing that has been catching people out since navigation was invented. They were written confidently, with reassuring comments, and they survived a lot of passing tests.
One href, six million URLs
The expensive one was not a maths error.
On 10 July, a change moved some default dates from the browser to the server, fixing a real rendering bug. A "back to results" link on every hotel page was built from those dates. So every one of my 16,400 hotel pages started publishing a link like:
``` /?location=Granada&checkIn=2026-08-24&checkOut=2026-08-25 ```
Those dates roll forward every day. Which means the site began emitting 16,400 URLs that had never existed before, every single day. Roughly six million a year, against a real site of about 27,000 pages.
Nothing wrong was ever indexed — every one of those URLs pointed back at the homepage as the canonical version. But Google has to fetch a URL to learn that, and those fetches come out of the same budget as the pages that matter.
Within a fortnight Googlebot had all but stopped visiting the pages I actually wanted it to read. It was not being punished or demoted — it was busy, working through an infinite pile of URLs my own site was generating faster than anything could crawl them.
A full technical audit came back clean. Canonicals, robots.txt, sitemaps, redirects, status codes — all correct. That is exactly why it took five weeks to find: nothing was misconfigured. One link simply outgrew the site.
The part about AI
Here is what I think is honest.
AI wrote those bugs. The flat-earth filter, the rolling-date link, all of it — written quickly, plausibly, with confident comments explaining the reasoning. The comments were the tell, in hindsight. A human unsure about longitude tends to leave a question. The machine left an explanation.
AI also found them. Every one. Not by being asked "is this broken", but by being pointed at a class of mistake and told to go looking slowly: *find me anything that applies one distance to both axes*. That turned up the second flat-earth bug in minutes, and the antimeridian one fell out of writing tests for the fix.
One thing to be clear about before I go further, because it would be cheap not to be. Everything here shipped under my name. When I say a machine wrote a bug, I am describing where the keystrokes came from, not where the responsibility sits — I read it, I approved it, I deployed it, and when it was wrong it was wrong on my site. I mention who typed what only because it is the actual subject: what the tool is good at, and what it is confidently bad at. Not to stand next to my own repository pointing at it.
The bit people miss is that it does not police itself by default. This week, mid-repair, we shipped a fresh one. To stop Google crawling those duplicate hotel URLs the fix blocked them in robots.txt — and put the rule in the group that link-preview crawlers also read. Twitter, Facebook, LinkedIn, Slack and WhatsApp all obey robots.txt. A dated hotel link is exactly the thing a person shares. For about two hours, every share of one lost its preview card. This site had already been bitten by that once, in July, and the explanation was sitting in a comment three lines above the edit. Written, presumably, by the same thing that then failed to read it.
What this actually replaces
I want to be careful here, because "AI wrote my app" is a genre and I am not writing that.
I have owned this domain for 27 years. I have launched on it twice before. This is the first time I have been able to do it globally, and with any distinction — and the difference is not that I want it more now.
Nor is it that I did not know what I was building. I have been doing this for more than thirty years, and every decision in this codebase is one I made on purpose: the pricing model, the supplier strategy, what gets indexed, what a page is allowed to claim. That is the bit "vibe coding" gets wrong as a description of the work. Nobody is vibing. I am specifying, in detail, all day, and then arguing with what comes back.
And teams were never only a source of the expertise I lacked. They are also a cost. Every decision has to be socialised, every disagreement is a week, a share of the effort goes to coordination rather than the product, and the people who most want to slow a thing down are rarely the ones who understand it best. Anyone who has spent thirty years in this industry has met the whole cast.
I want to be careful here, because that reads like an argument for working alone and it is not one. I would take good collaborators tomorrow. This site already runs on open data — GeoNames, OpenStreetMap, Wikimedia — and open source is where I would like it to end up; I intend to open this project up, and to build more that way.
That is not a recent enthusiasm. I started out writing PHP specifically because it was open source, at a point when a good many people were working hard to steer me onto Microsoft's stack instead. When MySQL was sold to Oracle I went and visited Oracle, had a look at what was on offer, and moved my databases to open-source ones. Thirty years of choosing the same way, usually when the other option was the easier one — and, as it turns out, for the same reason I am building this site: I have watched what happens to a market after the big name buys it, and it has never once got better for the people using it. Good developers make things better, and that has been true for the whole thirty years. What I have not missed is the committee, which is a different thing entirely and always was.
There is a real trade in it, mind. The committee occasionally catches you, and I have had to build my own version of that instead — hence testing everything twice and attacking my own work. A reviewer who disagrees with you is worth a great deal. A process that disagrees with you on principle is worth nothing at all.
Look at what one week touched. Spherical geometry and the antimeridian. Search-engine crawl budget and the semantics of robots.txt group matching. A JavaScript runtime migration. Analytics instrumentation and what a browser will and won't let you observe. A supplier's API contract, and what happens to a booking when a required field arrives empty.
Those are not one job. In a company they are four or five people, and the ones who are genuinely good at the second and third are expensive and hard to hire. A solo founder does not get them. The realistic options have always been: don't build the thing, build a much smaller thing, or build it and quietly carry the defects. That is where the two earlier attempts landed, and it was never for want of trying — you cannot review a longitude bug you have never had reason to learn about, and no amount of effort turns that into a thing you can spot.
That is the part that changed. Not that the code gets written faster — that it gets written across specialisms I do not have, and then gets attacked from angles I would not have thought of. Pointing something at my own repository and saying *go and find every place that applies one distance to both axes* is not code generation. That is a review a geospatial engineer would have given me, and I have never been able to afford one.
The discipline still has to come from me
Two things earned their keep this week.
The first is that I test constantly, by hand, on the live site. Not because I distrust the tests, but because tests only know what somebody thought to ask. Fetching my own sitemap and timing it is how I found a file taking 23 seconds to build — every time Googlebot asked for it, which is the only thing that ever asks. Curling my own pages pretending to be Googlebot is how I found 48,800 URLs nobody had noticed the site was minting.
The second is refusing to accept a single pass. Everything that mattered was found by going back over ground already signed off, with a different question each time. Write it, then attack it, then attack the fix. The green suite of 15,000 tests is necessary and it is nowhere near sufficient — one of them asserted a hotel link contained `checkIn=`, which was true whether the dates sat in the query string, where they minted a duplicate page for Google to crawl, or after a `#`, where they mint nothing at all. That distinction was the entire point of the change, and the test could not see it.
So: a full team, and the same obligation I would have if they were people — to keep asking whether the confident thing in front of me is actually true. This week it was not, five separate times, and every one of them was found by looking again rather than by looking harder the first time.
I would not want any of it to read as easy, or as quick. The suite that stayed green through all of this is fifteen thousand tests across a thousand files. The site behind it is thirty-odd thousand pages in eight languages, priced live by third parties who can time out mid-sentence. Tonight alone went out in six separate deployments, each one built, checked and watched. None of that assembled itself, and none of it stays standing on its own.
And a team you can summon is not a team that shares the weight. Nobody else notices you have been on the same file for an hour, and nothing is going to mind tomorrow whether you went back and looked one more time. The tooling changed what one person can reach. It has not changed how much of it there is.
Why bother
Worth saying what this is for, since a piece about my own bugs implies a certain amount of caring.
I am not trying to get rich. I am trying to take business off the handful of companies that have spent a decade making this market worse, and who are now large enough that making it worse is simply how they grow.
That is not an argument against making money, and I want to be exact about it, because "disrupting the middlemen" is usually said by someone who intends to become one. Everybody in this chain should do alright. The hotel should keep more of what you pay. The person booking should get a price that does not depend on how carefully they read. I need this to work as a business or it stops existing, which helps nobody. There is enough here for all of that.
The objection is to control. To a market where two or three companies set the terms for everyone in it, take a cut of every transaction whether they contributed anything to it or not, and are large enough that a hotel cannot afford to argue and a traveller cannot easily look elsewhere. Making money is fine. Owning the road and charging everyone who uses it is a different business, and it is the one that has to be competed with rather than joined. You see it in the data if you go looking. When Edinburgh introduced its visitor levy — capped, by law, at the first five consecutive nights — I went round the big sites to see how each handled it, and found one of them charging the levy on every night of a stay regardless of the cap. Not a scandal. Just a thing that is wrong, in their favour, that nobody had checked.
That is the shape of it. Fees that appear at the last screen. Prices that differ depending on how you arrived. Rooms that are "only 1 left" for a fortnight. None of it illegal, all of it a small tax on people not paying close attention, and all of it profitable enough that no incumbent will fix it.
So: one flat margin rather than a variable one. The total you pay, shown before you commit rather than at the last screen. Where a hotel is cheaper booked direct, I would rather tell you than hide it. I am not going to lay out the commercial mechanics here — some of it sits under supplier agreements that are not mine to publish — but the direction is transparency, and where I can open something up I will. That is not charity. It is the only part of this market actually available to compete on, because the incumbents cannot follow without giving up the revenue that makes them what they are.
And it is why the crawl-budget thing genuinely mattered rather than being an interesting bug. A site nobody can find does not take business off anybody.
The link was fixed on 17 August. Crawl budget rebuilds over weeks rather than days, and the first sign is simply Googlebot turning up at the real pages again — every one I checked this week was last crawled in early July. I will write up how that goes, either way.