← Projects
Retrieval / Verification2026

A Portfolio That Refuses to State an Unverified Number

This site is the fourth product. Every claim on it is bound at build time to a passage that exists, and the chat answers from retrieval over the same documents rather than from a model's memory.

Livetrigsight.vercel.appSourceRaghu23-dev/trigsight
Reproducenpm run verify:citations && npx tsx bench/retrieval/eval.ts --k 5
Citations bound to a real passage
68 of 68
Unbound citations tolerated
0
recall@5, hybrid retrieval
1.000
Lighthouse, mobile
100/100/100/100
Recall gained by real embeddings
none

The problem

A portfolio makes claims about work a reader cannot inspect. The normal solution is a link, which asks the reader to go and check, which nobody does. The dishonest solution is a number with no provenance, and it is dishonest whether or not the number happens to be true — a figure nobody can trace is indistinguishable from one that was invented.

So the interesting question is not "how do I present the work" but what would have to be true for a stranger to trust a number on this page without leaving it.

What I built

Two mechanisms, both of which fail the build rather than degrade quietly.

Every citation is bound to a passage at build time. A claim on this site carries a token naming the document and quoting the sentence it rests on, verbatim. npm run verify:citations resolves each one against the actual content and writes an allowlist. A citation whose quoted text does not appear, character for character, in the document it names is unbound, and an unbound citation fails the build.

The count is deliberately not stated in this paragraph. Writing "there are N citations" on a page that itself contains citations makes the sentence falsify itself the next time anyone adds one — this page went from 56 to 68 by existing. The invariant is what matters: zero unbound, or no build.

The verbatim requirement is the load-bearing part. A paraphrase would let a claim drift away from its source one edit at a time, which is exactly how a page ends up asserting something no document supports.

The chat answers from retrieval, not from memory. Ask it something and it runs hybrid retrieval — BM25 over chunked prose, fused by reciprocal rank with a vector leg — then a model writes an answer constrained to those passages, emitting the same citation tokens the rest of the site uses. Anything it cannot ground, it declines to answer.

That refusal is a feature and it is tested. A question about something not in the corpus gets "that is not covered here", not a plausible invention.

What it measured

recall@5 = 1.000 across 38 hand-written queries, each paired with the document that must be retrieved to answer it. The queries were written by reading the content, not by running the retriever — otherwise the set measures the retriever against itself.

What went wrong

The evaluation set had a blind spot the whole time, and it was the obvious one. Thirty queries, and not one of them named a product. Every question was phrased the way the content is written — "how do you stop a reconnecting client from duplicating events" — so the set was measuring whether prose retrieves its own prose. Recall read 0.900 and looked healthy.

Then I asked the live chat "what is fusegrid", which is what a visitor types first, and it said it had no information about it. Neither did asking about this site's conformance checker. No project on this site names itself in its own body text — a document titled "Cost Ceilings That Hold Under Concurrency" talks about "the ledger" and "the reservation", never "fusegrid" — and retrieval indexed only the prose. The product name sat in the document id, the title and the URL, and in nothing that was searched.

The fix took ten minutes. Finding it took a fortnight, because the gate designed to catch exactly this was asking a question the failure could pass: it verified that the corpus retrieves what the corpus says, and the thing a stranger asks about is not in the corpus at all.

Adding eight product-name queries dropped recall to 0.775 — below the 0.85 threshold — which is the gate finally doing its job. After the fix, 1.000.

And a benchmark that argued against its own design. Real embeddings, text-embedding-3-small at 1536 dims served by Upstash, were expected to beat the deterministic trigram stand-in written for offline testing. They did not: 0.967 recall both ways. The gain was in MRR — 0.831 to 0.889, better ranking of what was already found — and at 61 chunks a recall difference of 0.034 is a single query.

The honest reading is that this corpus is too small for a vector leg to earn its place on recall alone. It stays because ranking quality is worth having and the infrastructure is already paid for, not because the number justified it.

What this is not

It is not a template, and it is not reusable as one. The citation gate assumes prose written to be quotable and content authored in the same repository as the code that verifies it. Applied to a site whose claims come from elsewhere, it would verify nothing and say so cheerfully.

It also does not check whether a claim is meaningful — only whether the text it quotes exists. "Substantially faster" passes every gate here and means nothing, which is a matter for the writer rather than the build.