We Published 55 Blog Posts Nobody Read
Fifty-four of fifty-five titles began with the same word. Nineteen contained tax. The one line of prompt that caused it, and the four things we changed underneath.
We shipped an AI writer that published one blog post a day for fifty-five days. Nobody read a single one of them. Not "few people" and not "engagement was below target." As far as we can tell, no human being outside this company ever landed on one from a search result.
Here is what went wrong, because the failure turned out to be more interesting than the fix.
The pattern nobody noticed until we sorted the URLs
The posts looked fine one at a time. That was the problem. Each morning a new article appeared, it was grammatical, it made an argument, it mentioned the product without begging. If you read one you would think: fine, that is a blog.
Then we pulled every slug out of the sitemap and sorted them.
Fifty-five posts. Fifty-four of them began with the word "The". Nineteen contained the word "tax". Ten contained "friction". Six contained "trap". The rest split between "deadlock", "crisis", "fallacy", "void", and "mirage". Every single title followed one template:
The [Abstract Noun] [Tax|Friction|Trap]: Why your [thing] is [failing]
The average slug was fifteen words long. Here is a real one:
/blog/the-surface-parity-friction-why-disparate-logic-for-web-and-phone-support-creates-knowledge-silos
Nobody types that. Nobody types anything near it. We had written fifty-five articles competing for a set of search queries that does not exist, using vocabulary we invented ourselves.
Five of them were about the same thing
Sorting the slugs turned up something worse. We had published near-duplicates and never noticed:
the-session-expiry-friction-... / the-session-expiry-tax-...
the-tab-tether-tax-... / the-tab-closure-tax-... / the-tab-close-churn-...
the-action-gap-tax-... / the-action-gap-crisis-...
the-read-only-tax-... / the-read-only-ai-trap-...
Five clusters of pages arguing with themselves. The pipeline had a guard against this. It fetched recent posts and passed the titles into the prompt with an instruction not to repeat them. The limit was ten.
So on day fifty-five the writer could see ten titles and was blind to forty-five. It looped, exactly on schedule, roughly every three weeks.
The line of prompt that caused all of it
The generation prompt contained this instruction:
Pick a fresh, narrow angle clearly different from recent titles.
Read that again with fifty-five days of compounding in mind. Every day the model was told to differ from what came before. It was given no external anchor, no query anyone had actually typed, nothing outside its own back catalogue to orient against.
There is only one direction that instruction can travel. Away from the ordinary words people use, deeper into abstraction, each day slightly further out than the last. "The Lookup Lag Tax" is what day twenty-eight of that instruction looks like. "The Surface Parity Friction" is day fifty-two.
We did not build a writer with bad taste. We built a writer with a compass pointed at its own tail.
It was reading our marketing site
The deeper fault was upstream. Before each run, the pipeline crawled our own website and loaded it into a vector store as source material.
Our own marketing copy. The one corpus on the internet guaranteed to contain nothing we had not already said.
Any model handed that input produces what we got. It was not being creative in a bad direction; it was rephrasing our homepage fifty-five times and dressing each pass in a different invented noun. The writer was not too ambitious. It was starving.
The links went to pages that do not exist
One more, found while testing the replacement. A post came back with four internal links:
/voice-ai /how-it-works /about /pricing
All four are 404s. We have never had any of those routes.
The pipeline looks up real internal links in a vector search, and that lookup returned nothing. The error was caught, logged, and swallowed into an empty array, exactly as written. The prompt then asked for contextual internal links and the model, given an empty list and a clear instruction, produced the URLs a site like ours ought to have.
It guessed. Reasonably. And every guess was wrong.
What we changed
The scheduler was never the problem, so it stayed. Four things changed underneath it.
The topic is now an input, not an output. The old pipeline generated an article and then asked the model to label it with keywords, which is backwards. A target query now comes out of a table before a word is written, and the article exists to answer it.
The corpus changed. Pointing a writer at your own marketing site guarantees derivative output. It now reads our documentation, our changelogs, and the web.
Links come from a tool, not from the model. If a URL was not returned by a lookup it does not go in the page. A model cannot invent what it is not permitted to author.
It can decline. The old pipeline had no way to produce nothing, so it produced something, fifty-five times. If the queue is empty it now writes nothing and says so in the log. A system that cannot say no will say fifty-five things instead.
The part worth keeping
The old posts are still up. We have not deleted them and we are not going to pretend they were not ours.
What is uncomfortable is that every individual decision was defensible. Ban the em dash, ban the hype words, ban the rhetorical question, tell it to write like an engineer rather than a marketer. Those rules were good. We kept most of them verbatim.
The rules governed how sentences were built and said nothing about whether the article should exist. You can enforce excellent prose all the way to the bottom of a well nobody is looking into.
The thing we did not measure was the only thing that mattered: whether a single human being had ever gone looking for what we were about to publish.