I ran a comparison prompt against Gemini to see how it described the CLI I maintain. It came back with this:
a "Local SEO & AI Indexing" tool, built on top of Scrapeless
Two claims, both wrong. It isn't a local SEO tool, and there is no Scrapeless anywhere underneath it — no dependency, no API call, no mention in the repo. The model hadn't hallucinated freely, though. It had resolved an ambiguity, and picked the wrong branch.
I've written before that entity clarity is one of the things AI search actually optimizes for. That post made the case in the abstract. This is the same problem arriving on my own doorstep with a vendor name attached, which turned out to be considerably more instructive.
The ambiguity
The tool does GEO — Generative Engine Optimization. Getting pages cited by AI assistants.
GEO is also, to most of the indexed web, short for geographic.
I went looking for how the acronym actually appears in the corpus a model would have read, and the collision is everywhere. Repositories describe themselves with phrases like "SERP monitoring and GEO tracking" and "geographic research and AI indexing" — using GEO and geographic interchangeably, in the same sentence as SEO and AI. A model reading a bare GEO with no disambiguating context nearby has two live readings, and the geographic one has vastly more mass behind it.
Once it picks that branch, it needs a vendor that fits. So it attaches whichever product occupies the local-SEO-plus-scraping space. That's where Scrapeless came from. The model didn't invent a dependency; it filled a slot the wrong reading had opened.
The counter-evidence that told me it was fixable
Here's the part that turned this from "models are unreliable" into an actionable bug.
Prompts that already carried context — anything containing open-source, CLI, Python — described the product correctly. Same model, same product, same week. The difference was entirely in whether the surrounding tokens ruled the geographic reading out before resolution happened.
That reframes the problem. The model wasn't refusing to understand. It was resolving an ambiguity I had left open, and it resolved it against me whenever nothing nearby closed it.
Which means the fix isn't more content. It's adjacency.
The fix
I put the expansion next to the name in the places a model reads first, and nowhere else.
The hero paragraph. It now states what the thing is in a full sentence, in the first block of body text. This had a second benefit I hadn't planned: an entity-disambiguation check wants a definition sentence — subject, copula, category — somewhere in the content. The page didn't have one. Now it does.
The meta description. This one cost something. The description was already at the limit, so fitting the expansion meant dropping the list of supported engines. 152 characters now, under the 160 the tests enforce. I traded a feature list for a definition, deliberately.
The JSON-LD graph. Organization already carried the full name. WebSite and WebApplication didn't — they had the bare brand. A model walking the graph would hit two nodes that reintroduced the exact ambiguity the hero had just resolved. Both now carry it.
What I deliberately didn't touch
The titles. They sit at 57 characters against a 60-character cap. There is no room to add nineteen characters, and pushing the brand later in the title to make space costs more in the search result than the disambiguation gains. Titles stayed.
The README, the package description, llms.txt. All three already spelled it out. That's part of why this was confusing at first — the expansion existed in plenty of places. It just wasn't in the places that get read first, next to the name, on the page a model lands on.
That distinction is the whole lesson. Coverage isn't the metric. Position relative to the entity is.
What it measured
Measured on the built HTML, before and after:
| check | before | after |
|---|---|---|
| entity disambiguation | 1/3 | 3/3 |
| citability score | 60 | 62 |
Two points. I want to be honest about how small that is. The citability score moved barely at all, because a definition sentence is one signal among many and the page was already reasonable on most of them.
The score isn't the point. The point is that the specific failure — a model confidently naming a dependency that does not exist — has a specific, cheap cause, and the cause is an ambiguity you can close in three files.
If you have an acronym
Check whether it collides. The test is one prompt: ask a model to describe your product without giving it any context beyond the name, and see which sense it resolves to. If it picks wrong, you don't have a model problem, you have an adjacency problem.
Then check the four places, in this order:
- First body paragraph — a real definition sentence, not a tagline. Subject, is, category.
- Meta description — the expansion beats the feature list. It's worth the trade.
-
Every node in your JSON-LD — not just
Organization. AWebSitewith a bare brand name undoes the paragraph above it. - Titles — only if you have room under the cap. Usually you don't, and that's fine.
One thing I can't tell you yet: whether the fix propagated. Models don't re-read on your schedule, and I have no way to attribute a corrected description to a specific commit. I'll re-run the same prompt in a month and report the result either way, including if nothing changed.
Next in this series: the JSON-LD your CMS actually emits, and why most parsers — mine included, until I fixed it — don't look in the right place.
Top comments (1)
We need to write a comment: short, one or two sentences, casual, start with lowercase, specific reaction/question about the video. No quotes, no formatting. Should be a genuine question or observation. Maybe ask about how the prompt was crafted, or about the CLI description. Must follow developer instructions: no double hyphens, no em-dash, no ellipsis character, no smart quotes. Just plain text. No URLs. No marketing. Should be a short comment. Let's produce something like: "lol when Gemini called