Here is a failure you have probably met without noticing. You ask an AI assistant something current, which version of a library to use, whether a function still exists, what the latest release changed, and it answers at once, fluent and certain. You act on it. Then it turns out to be quietly, confidently wrong, because what it told you was true a year ago and has not been true since. The model was not lying. It learned the world up to a fixed point in the past and has been frozen there ever since, with no way to feel time moving on.
That gap, a confident answer that has quietly expired, is one of the most common and least talked-about failures in AI today. This article is about where it comes from, why the popular fix does not fully close it, and how to build retrieval that actually knows when its facts have gone stale. We start at the very beginning, so a newcomer can follow every step, and we finish at a real, open-source system you can clone and run in three commands.
That popular fix has a name, and to understand why it falls short, we first have to understand what it is.
A language model on its own is a closed book. It learned from an enormous pile of text up to a certain cutoff date, and everything it knows is frozen at that moment. Ask it about something newer than its training, or something private to your company, or a narrow detail it never saw enough of, and it does the only thing it can. It guesses, often fluently and often wrong. That confident guessing is what people mean by hallucination.
Retrieval-augmented generation, RAG for short, is the fix that has become the default. The idea is almost too simple. Before the model answers, let it look things up. You keep the real, current information in an external store, you fetch the pieces relevant to the question, and you hand them to the model as part of the prompt. The model then answers from what it was given rather than from memory alone. Retrieve first, then generate.
Think of the difference between a student sitting a closed-book exam and the same student sitting an open-book one. The closed-book student answers from memory and bluffs the gaps. The open-book student finds the exact page first, then writes a grounded answer. RAG turns the model into the open-book student, and it has been the workhorse pattern for grounded AI since a Meta research paper introduced it in 2020. Despite regular predictions of its death, it has only grown, and a large share of production AI systems still rely on it today, because looking something up is far cheaper than reasoning over everything you own on every single question.
The plain version, often called naive RAG, is a short pipeline, and it helps to see the whole of it before we find its cracks.
First you take your documents and cut them into small pieces called chunks, because a whole manual is too big to hand over but a paragraph is about right. Each chunk is run through an embedding model, which turns a piece of text into a long list of numbers that captures its meaning, so that texts about similar things end up with similar numbers. Those number-lists are kept in a vector database, a store built to answer one question very fast, which saved pieces sit closest in meaning to a new one.
When a question arrives, the same embedding model turns the question into its own list of numbers. The vector database compares it against everything stored and returns the closest handful of chunks, the top-K as it is usually written. Those chunks are pasted into the prompt above the question, and the model writes its answer from them. Retrieve the nearest text, place it in the prompt, generate. That single pass is naive RAG, and for a great many jobs, a support bot answering from a manual or a search box over your own notes, it works perfectly well.
Hold onto one detail, because the whole story turns on it. The database ranks chunks by how close they are in meaning to the question. Closeness in meaning, and nothing else.
Ranking by meaning alone is exactly where the trouble starts, and it shows up as two failures most pipelines never notice.
The first failure is time. A retriever that ranks by meaning has no sense of when a fact was true. Ask for the latest Python release, and a page about 3.12 and a page about 3.14 are both, in meaning, extremely close to the question. The retriever will happily put the older one on top if its wording matches a little better, and the model, trusting what it was handed, answers 3.12. The uncomfortable part is how routine this is. A 2026 study of retrieval over changing knowledge found that standard RAG serves facts that are already stale somewhere between 15 and 40 percent of the time. This is not a rare edge case. It is a structural blind spot, and the reason a whole wave of 2025 and 2026 research on temporal RAG exists is that the field has finally admitted retrievers over-index on topic and under-encode time.
The second failure is cost. Naive RAG grabs the top few chunks whole and pastes all of them into the prompt, padding and all. You pay for every one of those tokens on every model call, and the bill is only half the damage. A long, cluttered prompt also makes the answer worse, since models measurably lose accuracy when the sentence that matters is buried inside a wall of retrieved filler. So the pipeline pays twice, once at the till and once in quality, for context it never needed.
Neither failure is exotic. Both are baked into the plain design. And this project was far from the first to run into them.
The field has not stood still. Naive RAG has grown into what people now call agentic RAG, where the retrieval step is wrapped in a reasoning loop and the model decides for itself whether to search, what to search for, and when it has enough to answer. Two named patterns matter here, because this project builds on both. Corrective RAG, introduced by Yan and colleagues in 2024, adds a grader that scores the retrieved evidence and, when it is too weak, triggers a fallback such as a fresh web search rather than answering from rubbish. Adaptive RAG, from the same year, adds a router that sends easy questions down a short path and hard ones down a longer one, so effort matches difficulty.
These are real advances, and by 2026 they drive most serious RAG systems. Look closely, though, and even they mostly inherit the two blind spots above. The grader checks whether evidence is relevant, not whether it is current. The router picks a path, but every path still pastes full, uncompressed chunks into the prompt. Time and cost are still nobody’s job.
GroundProof(https://github.com/HelloJahid/GroundProof) is an agentic corrective RAG that takes those modern patterns as its floor and then does the two things they skip. It gives every fact a date and settles conflicts by rule, and it makes context earn its place before it reaches the model. The rest of this article is those two ideas, and the proof that they work.
The shape is a corrective loop. An adaptive router decides whether a question needs no retrieval, one pass, or several. Temporal retrieval pulls dated candidates. A grader gate asks whether the evidence is strong enough, sending weak results back through a reformulate and web-search fallback, and strong ones onward through a supersedence resolver, a context pruner, and finally an answer that must cite with dates. Every box in that diagram is one small recorded step, so a finished run can be replayed and inspected long after it ends, and every claim I make below maps to a command you can run yourself.
We will take the two hooks one at a time, and the first is the one this whole article has been circling. Time.
The whole time problem comes down to a piece of metadata everyone drops on the floor. So the foundational move here is almost embarrassingly small. Every chunk of text the system stores must carry an observed_at date, and that field is required. Not a convention, not a field we usually remember to fill. It is enforced by the data model, so a chunk with no date is a validation error and simply cannot exist.
Where do the dates come from? Never from guessing. The fetcher joins two sources, an API of machine-readable release dates for the when, and the raw documentation for the prose, for the what. A system whose whole headline is trustworthy dates cannot afford to scrape its own anchor dates out of prose with a pattern match.
With dates in hand, two rules do the work the model is usually asked to do by intuition. The first is an as-of filter. Every query runs as of a chosen moment, and that filter runs before anything is ranked, so only the chunks that were valid at that moment ever compete. Filter first and the window stays honest. Filter last and future facts crowd the valid ones out of the top results. On top of the filter sits a gentle recency preference, so among the evidence that is valid at the chosen moment, fresher beats staler, while older truth is discounted rather than erased.
The second rule settles conflicts. When two retrieved facts about the same topic disagree, the model is never asked which one is current. The strictly later date wins, and the loser is kept as dated history, because this was true until such a date is a real and answerable question. Two refusals matter as much as the rule. Equal dates never supersede, since with no clear order there is no rule and so no guessing, and each superseded fact points at its immediate successor, so a chain of three reads like a timeline.
This is the exact stance the current temporal RAG research is converging on. Freshness is a gate check, not a judgment call, and the model is never handed the job of tracking what is current. The rigour lives in the rules, not in a hopeful instruction buried in a prompt.
The two hooks sit inside a familiar loop, which is worth a quick tour because it is where the corrective and adaptive patterns from earlier show up in the flesh.
A simple router sorts each question first. Small talk skips retrieval entirely, a question that is really several questions gets split, and everything else takes the normal single pass. A grader gate then scores the retrieved evidence against the question, blending how similar the text is with how much of the question’s wording it covers, and comparing that against a threshold. Weak evidence never reaches the answer. The pipeline reformulates the query once, retries, and if that still fails, falls back to a live web search. If even that returns nothing usable, the system declines to answer rather than invent one, and it declines without spending a single model call, because you never ask a model to answer from evidence the gate has already rejected.
One war story from this loop is worth telling, because it shows why the grader has to be careful. The first time I ran a genuinely unanswerable question against the real corpus, the grader marked the evidence as strong, which was plainly wrong. The cause was a neat trap. Reformulation adds corpus vocabulary to the search query to help it find matches, and the grader was scoring against that padded query, whose extra words overlap the corpus by construction. The reformulation was quietly lowering the very bar it was meant to clear. The fix is now a rule written into the code. The gate always grades against the user’s original question, never the padded one, because reformulation exists to find evidence, not to decide what that evidence is worth.
The loop keeps the agent honest about whether its evidence is any good. The second hook keeps it honest about how much that evidence costs.
The cost problem has a current name, and it is context pruning. The naive approach hands whole chunks to the model. The better approach keeps only the sentences that actually answer the question. There are several schools of this, from token-level pruning to model-written summaries, and this project uses the one best suited to technical text, query-aware extractive pruning at the sentence level.
A pruner sits between retrieval and the answer, and its whole job is to spend a token budget wisely. It splits the surviving chunks into individual sentences, and every sentence is born knowing where it came from, its document and its date. It scores each sentence against the question, then packs the highest-scoring ones into a fixed budget, the way you would fill a knapsack with the most valuable items that fit. Working at the sentence level, rather than snipping individual words, matters for a corpus of code and changelogs, where a half-deleted line is worse than useless. The rendered result re-attaches a dated source header to each group, so the citations survive the squeeze.
The point of a build like this is that the claim is measured, not asserted. An A/B harness runs every test case through the pipeline twice, once with the pruner off and once on, and records both the token count and whether the answer-critical phrases survived.
The result is about 62 percent fewer prompt tokens, with a retention score that stays flat at a perfect 1.00. That flat retention is the whole point, because compression that saves tokens by dropping the answer is not compression, it is deletion, and the retention column would go red the moment it happened.
A feature you cannot measure is just a hopeful comment in the code, so the real heart of this project is the layer that turns both hooks into claims a machine can check.
The instrument is a temporal golden pair, the same question frozen at two different moments, with each half expecting its evidence from a different document. Three rule checks judge every run’s recorded trace rather than the live process. No evidence may be dated after the as-of moment. The top evidence must come from the expected document. And the answer-critical phrases must be present. All three are deterministic, all run offline with no keys, and all are wired into the automated checks that run on every change, after the linter and the tests.
This is where the system does its most satisfying trick.
Add one newer document to the corpus, and a question whose correct answer has now changed will make the eval gate go red, name the failing case, and name both the old and the new document. No model judged anything. No human noticed anything. A rule did, the newest fact on a topic supersedes the older one, and a test that expected the old truth is now correctly broken. That is the payoff of owning your measuring stick. It notices when the world moves.
Two more war stories earned their place, both about trusting the machine over my own assumptions. Writing the stale-fact test, I first dated a fake future document after the frozen moment and watched the case stubbornly keep passing. The as-of filter was hiding my fake, exactly as designed, since a document from after the frozen moment is invisible to it. The temporal machinery had defended the tests against my own bad test. And a subtler one, the store I used for retrieval quietly handed back the same collection each time I thought I had a fresh one, so several tests passed against each other’s leftovers. Only the strictest assertion, a check that the store held exactly one item after re-indexing the same chunk, caught it. Exact assertions about counts and identity catch what a vague some results came back never will.
That same rigour is what lets me be exact about the other side of the ledger, the parts this build deliberately does not do.
Honesty is the whole point of a build like this, so here is the record, plainly.
The offline demo uses a simple, deterministic stand-in for the part that measures meaning, rather than a heavyweight embedding model, because that is what lets the entire test suite and eval gate run with no keys and identical results every time. Its sense of relevance is crude, but the temporal behaviour, the filtering, the recency, and the supersedence, is exactly right, and that behaviour is all this project claims. The real embedding provider sits behind a clean interface, so a production one slots in without touching the pipeline.
Dates are handled at the document level rather than for every individual fact, which is a scope decision made on purpose. And the grouping that decides which facts count as the same topic is coarse, good enough for questions about the latest version, which is exactly the case that motivated keeping superseded facts as dated history rather than deleting them.
What you end up with is an answer that knows what it knows, and when it knew it, and what it cost to say, sitting behind an automated gate that goes red the day it stops being true. You do not have to take any of this on trust, since the whole thing runs from a clone, with no keys, in three commands.
git clone https://github.com/HelloJahid/GroundProof.git && cd GroundProofpip install -e ".[demo]"streamlit run demo/app.py
Ask it something. Change the as-of date. Watch the evidence change its mind, with dates to prove it.
There is a natural next problem waiting. Everything here makes a single retrieval agent trustworthy, one strong worker doing one job well. The harder question is what happens when a task needs a whole team of agents, each with its own tools and its own slice of the work, coordinated without losing the thread. That is a different kind of engineering, orchestrating many agents with tools like LangChain and LangGraph, and it is where I am headed next.
GroundProof is open source under the MIT licence at github.com/HelloJahid/GroundProof. It is the third of a small series on building AI you can trust rather than merely demo, after PromptProof and AgentProof, and it is built on the second.
Agentic RAG That Knows When Facts Expire, and Pays Only for the Context It Needs was originally published in Towards AI on Medium, where people are continuing the conversation by highlighting and responding to this story.