Start with what a vector database is for, stated as generously as possible, because the rest of this only means something in contrast to a real target.
What a vector database is genuinely good at
Embed a corpus of documents into a high-dimensional space where semantic similarity becomes geometric proximity, and you can ask "what in here reads like this query" without either side using the same words. That is a hard problem, solved well: a support ticket about a "frozen screen" finds a knowledge-base article titled "display not responding" even though they share almost no vocabulary. A RAG pipeline built on top retrieves the nearest passages and hands them to a model as context, which is exactly the right architecture for "answer this question using what's in the corpus" when the phrasing of the question and the phrasing of the answer don't match.
None of that is in question here. If your problem is semantic search over content you hold (find the passages related to this, surface the documents similar to that one, ground a chatbot's answer in your docs), a vector database is the right tool and Lacunari doesn't compete with it.
Why gap detection is a different shape of problem
Every retrieval system, embeddings-based or not, is a function from a query to a ranked list of things that exist. That's true of full-text search, true of a vector database, true of a RAG pipeline built on either. Ask it "what's similar to X" and it does exactly what it was built for. Ask it "what's missing" and it cannot answer, structurally, because nothing was indexed that isn't there. There is no vector for the absence of a 1943 document, no embedding for the file nobody wrote.
Say you index a project and want to know which source files nothing in the codebase documents. A vector search can find you the files most similar to a query about documentation. It cannot tell you which files exist with zero incoming references from any .md file, because "zero incoming references" is not a similarity judgment about one document. It's an aggregate fact about the whole set, computed by checking every file against every mention and reporting the ones with none. That's a join and a count, not a nearest- neighbor lookup.
That's set-based SQL: an anti-join, the relational-algebra term for exactly "rows on the left with no match on the right." Postgres has been fast at this since before embeddings existed. No model is called, no nearest-neighbor index is consulted, because the question was never "what is close to this." It was "what has no match at all," which a similarity search cannot express because everything has some nearest neighbor. Ask a vector index for the closest match to a 1943 document you don't have, and it will confidently hand you 1944.
The four shapes this covers, and why each is a count, not a query
- A hole in a covered span. You hold years 1941, 1942 and 1944. This is "which integers in a contiguous range have zero rows," answered by generating the range and anti-joining against what exists, not by asking what's similar to 1943, which returns your nearest neighbors and calls it a day.
- Resting on one source. GROUP BY a subject, COUNT(DISTINCT source), filter for exactly one. A similarity search has no notion of "how many independent things support this." It isn't counting corroboration, it's ranking closeness.
- Connected to nothing. An entity with in-degree and out-degree both zero in the mention graph. Graph traversal, not embedding distance.
- Never read. Rows present in the document table with no corresponding row in the extraction table. Another anti-join. This one a vector index cannot even attempt, because an un-extracted document has no embedding to search with in the first place.
Every one of these is answerable because Postgres already knows the full set, every row, every relationship, and the question is about the shape of that set. A vector index deliberately throws away exact structure in exchange for fast approximate similarity over unstructured meaning. That trade is exactly backwards for a question whose entire content is "count precisely, then report what's at zero."
Where the two would actually combine
It's worth being honest that these aren't mutually exclusive. Nothing stops a project from running a vector index over the same documents Lacunari catalogues, for the searches it's actually good at: "find me passages like this one," a RAG chatbot over your archive. Lacunari's own library storage is content-addressed and would sit underneath such an index perfectly well as the record of what's held and who contributed it. The two systems would be answering different questions over the same corpus, which is a reasonable architecture, not a contradiction.
What doesn't work is using one to try to answer the other's question. A RAG pipeline asked "what am I missing" will hallucinate an answer that sounds confident and means nothing, because it was never designed to say "I have no vector for that." It was designed to always return its k nearest matches. And set-based SQL asked "what does this passage mean" has no opinion at all, because it was never given anything to compute semantic distance with. Neither tool failing at the other's job is a defect. It's what happens when you point a hammer at a screw.
The practical consequence
Because none of this touches a model, gap detection runs with no API key, no network call, and no embedding cost that scales with corpus size. It's the same SQL whether you're indexing 90 files or 90,000. It's also reproducible in a way embeddings usually aren't: the same corpus produces the same gap report tomorrow, and it doesn't shift because a vendor shipped a new embedding checkpoint that reshuffles what counts as "similar." For a research team especially, that's not a minor property. Results a colleague can rerun and get identically are worth more than results that were merely convincing once.