Start with the claim these four have in common, because it explains why they need a separate article rather than a paragraph each: none of them are properties of a document. They are properties of a set — visible only once you know the shape the set should have had, and invisible to any system that answers questions about one record at a time.
That is not a minor caveat. It is the entire reason a hole in your archive can sit there for six years while a very good search engine sits on top of it.
01 — A hole in a covered span
Illustrative example, not a real case: an archive holds a document from 1941, one from 1942, one from 1944, and nothing from 1943. The span the archive covers runs 1941 through 1944. Somewhere inside that span, one year has zero documents.
The rule that makes this useful instead of useless is easy to state and easy to get wrong: the gap has to be inside the span, and the span needs three points before it counts as a span at all. Two documents establish nothing — a start and an end, with no shape in between. Three establish a series, and a series is the thing a gap interrupts. Nothing before the first document or after the last one is a gap; that is just the edge of what you hold, and flagging it as missing is how you train people to stop trusting the flag.
Indexing this project's own repository against this rule produced a version of the failure worth naming: a badly parsed date extracted 1800 from a 2026 document, and a looser gap rule would have manufactured two centuries of imaginary leads from one bad regex match. Three points, inside the span, is what keeps the signal from drowning in that kind of noise.
The same shape reads on a codebase with no changes at all — a changelog with entries for every release except one, a metrics table with a missing quarter, a version history where v2.3 exists in the package registry but nothing in the repository mentions it.
02 — A claim resting on one source
Illustrative example: a document states that a particular transfer happened on a specific date. No other document — no letter, no receipt, no second account — mentions it. The claim is not wrong. It is uncorroborated, which is a different property and the one a relevance-ranked search result actively hides, because ranking surfaces the best match regardless of how many independent sources produced it.
Corroboration is not a nice-to-have footnote here — it is the entire reason a research group federates with another archive in the first place. If two independent parties hold the identical account, that is evidence. If only one does, that single-source status is itself the finding, and it is usually the most important property of the claim, not a footnote to it.
On a codebase this is a claim in a design doc that no test and no second document reiterates, or a magic constant defined once and never explained anywhere else in the tree. Nobody disputes it. Nobody has confirmed it either, and a search index has no slot for that distinction — a single hit and a triple-corroborated hit come back identically ranked.
03 — An entity connected to nothing
Illustrative example: a name appears once, in one document, and never again. Every retrieval system will happily return that document if you search for the name. None of them will tell you that the name is a dead end — mentioned once and never placed in relation to anything else in the corpus.
That matters because an entity connected to nothing is one of exactly two things, and you cannot tell which from the mention alone: a genuine dead end, the kind every real archive has plenty of, or the loose thread nobody has pulled yet — the one lead that turns out to matter precisely because nobody followed up on it. An edge here means "named in the same document as," and nothing more; it does not claim a relationship, only a co-occurrence. Reporting the isolated node is reporting the question, not answering it — which is the right thing for the tool to do, because the tool cannot tell a dead end from a discovery and should not pretend it can.
On a codebase, this is the file nothing imports and nothing in the tree names — an entry point, a script called only by hand, or genuinely dead code. Same query shape, same honest refusal to guess which.
04 — Material never read
This one is the least glamorous and the most common finding in any real archive. A document sits in storage, catalogued, filed, present — and nobody has ever extracted its text, dated it, or named the people in it. It has a hash and a filename. It has no facts.
The reason this belongs on the same list as the other three rather than a separate "housekeeping" bucket: it is invisible to all three of the other questions. A document that was never read cannot show up as a corroborating source, cannot fill a timeline gap, and cannot connect two entities — not because it doesn't contain the answer, but because nothing has ever asked it the question. Every other absence in this list is at least computed from something. This one is upstream of computation entirely.
On a codebase, this is the source file that was indexed — its path and byte count are on record — but never parsed for symbols, imports, or language. It is sitting in the catalogue looking exactly like every file that has been fully read, which is what makes it dangerous: a report that only covers what's been extracted will silently under-count by exactly this amount and never say so.
Why search and RAG cannot find any of these — the actual mechanism
It is worth being precise about the mechanism rather than waving at "search is bad at this," because the imprecise version invites the wrong fix — a better embedding model, a bigger index, a reranker. None of those touch the problem.
A search engine, a vector database and a RAG pipeline are all, underneath whatever interface sits on top, a function from a query to a ranked list of existing records. You give it a query vector or a set of terms, it scores every record in the index against that query, and it returns the top-k. Every part of that pipeline — the embedding, the similarity metric, the ranking — operates over documents that are already in the index. There is no step, at any point, that reasons about a record that isn't there, because "isn't there" has no vector, no embedding, no rank. It is not a low-scoring result. It is not a result.
Ask a vector database "what am I missing from 1943" and one of two things happens. Either it returns nothing — indistinguishable, at the interface level, from "you asked a question with no answer" — or worse, a generative layer on top of it produces a fluent, confident paragraph that is not grounded in anything, because there was no document to ground it in and the model was never told the query was structurally unanswerable by retrieval. That second failure mode is worse than the first. A blank result is at least honest.
The four shapes above are aggregate, set-based questions. "Is there a year between the minimum and maximum with zero rows" is a GROUP BY and a gaps-and-islands query. "How many independent sources mention this entity" is a COUNT(DISTINCT source). "Which nodes have degree zero in the co-occurrence graph" is a join against an adjacency table with no match. "Which documents were catalogued but never extracted" is a LEFT JOIN ... WHERE extracted.doc_hash IS NULL. These are the questions relational databases have answered cheaply since before "search engine" meant anything — they were simply never pointed at a document corpus, because the last two decades of retrieval tooling were built entirely around the assumption that the interesting question about documents is always "which ones match."
Report, never explain
One discipline holds all four together and is worth stating explicitly, because the temptation to violate it is constant: report the absence, never explain it. The missing 1943 material might mean the records burned, the unit was disbanded, nobody has digitised the box yet, or the year genuinely produced nothing. Software cannot distinguish those and should not pretend to. The single-source claim might be true or might be the one thing in the corpus someone got wrong. The isolated entity might be nothing or might be the discovery. Each of the four is a lead, not a verdict — a place to look, handed to a person or an agent who can actually go read the material and decide what it means.
All four run offline, over data you already hold, in plain SQL. No model, no API key, no network call — which means the results are reproducible: the same corpus produces the same gaps tomorrow, and they don't shift because a vendor shipped a new checkpoint between two runs of the same query.