"The engine wasn't wrong. It faithfully completed exactly what the corpus contained — and the corpus contained HTML tag soup."
The Junk Completions
Here's a war story with a clean lesson. A corpus was built from web content, and its phrase completions started coming back as nonsense: fragments like "data emotion playful img class …" — bits of HTML attributes, not prose. The completion feature looked broken. The instinct was to go patch the completion endpoint to filter out the junk. That instinct was wrong, and understanding why is the whole point of this lesson.
The Engine Was Behaving Correctly
Completion mines the corpus for how phrases actually continue. If the indexed text is riddled with raw HTML tags and attributes, then the honest continuations of many phrases are attribute fragments. The engine wasn't malfunctioning — it was doing its job perfectly on polluted input. Garbage in, garbage out, at the level of a whole engine. The bug wasn't in the retrieval; it was in what got fed to it.
Fix the Corpus, Not the Engine
So the fix belonged at the conversion seam, not the query path. The web content was re-captured through an extractor adapter that strips HTML tags into clean prose: pull a title from the frontmatter, remove the markup, mine prose out of structured data while blocking identifier-shaped keys, and enforce a minimum length so fragments don't survive. Now the snapshot holds prose, and every downstream path — search, completion, everything — mines clean text. One fix at the boundary healed every symptom at once, because they all shared the same polluted source.
Clean Into the Snapshot, Never the Original
One critical constraint holds the whole thing together: the cleaning happens into the converted snapshot, and the chunk text stays an exact slice of that converted text. You never reach back and edit the original source files to clean them — that would violate the never-touch-the-source rule. The extractor reads the messy original, produces clean prose, and snapshots that. The original stays exactly as it was; the snapshot is the cleaned reading; the offsets and hashes all refer to the snapshot. Curation and 'originals stay put' coexist perfectly, because the cleaning lands in the captured layer, not the source.