Business

When a Passage Is Stale: Versioning and TTL for Retrieved Context

Antonio Evans9 min read

A split scene: a source document tagged v7 with a modified time feeds a pipeline carrying a passage card labeled v5 into a context window, ending at a three-way decision box for refresh, reindex, or serve with warning.
Key points

Key points

  1. 1A version field only records what a passage claims to be; it does not prove the passage still matches the current source document.
  2. 2A freshness policy needs three inputs: passage version, source document version (hash or modification time), and the retrieval timestamp.
  3. 3TTL should be set per content class, not globally, because policies, prices and API docs decay at very different rates.
  4. 4When a check fails, pick one explicit action (re-retrieve, reindex, or serve with a warning) and define it in advance rather than improvising.

Why the version field alone fails

A passage in a vector store typically carries metadata: a source document id, a chunk index, and a version such as v5. That field is written at ingestion time. It answers exactly one question: which version of the source this chunk was cut from. It does not answer the questions that actually cause bad answers in production.

The first missing answer is whether the passage still matches the source. A document can change without anyone bumping the version field, especially when ingestion parses PDFs or HTML where the page changes but the version label is maintained by hand. The second is whether a newer version exists upstream. The index has no view of the source system unless something reconciles the two. The third is how long a mismatch is tolerable. A changed shipping policy might be safe for a day; a changed interest rate might not be safe for an hour.

The failure mode is well documented. RAG index drift happens when searchable chunks, embeddings, or metadata no longer represent the current source, and it produces stale evidence, orphan embeddings and answers grounded in content that should no longer be active the Oracle engineering blog. Some teams describe this as the staleness gap: the time between when a document changes in the source system and when that change appears in the vector index, during which every query on that document is answered from outdated context the RAG engineering guide.

The uncomfortable part is that standard RAG evaluation will not catch it. Faithfulness measures whether an answer is supported by the retrieved context. A faithfulness score of 1.0 says every claim traces to a retrieved document; it says nothing about whether that document is still true the RAG engineering guide. A golden dataset built when documents were fresh keeps passing as the corpus decays.

What to compare, and where each signal comes from

A freshness policy compares three timestamps and one identity per retrieved passage.

SignalWhere it livesWhat it catchesCost
Passage versionChunk metadata in the vector storeWhether the chunk was cut from an older source revisionFree, already stored
Source content hashComputed at ingestion, stored in the source registrySilent edits that never bumped the version labelOne hash per document per check
Source modification timeSource system (CMS, S3, database)Newer revisions appearing upstreamOne metadata read
Retrieval timestampRequest log or chunk metadataAge of the passage at the moment it was servedFree

A content hash is the most reliable of the four because it does not depend on anyone remembering to increment a counter. The Oracle reconciliation checklist is a good starting point: does every active chunk point to an active source, did the source text change without the chunk hash changing, and did the chunk text change without a new embedding the Oracle engineering blog.

In practice you do not check every passage on every query. You check at retrieval time using cached values, and run a fuller reconciliation on a schedule. A simple per-request check looks like this:

def freshness_verdict(passage, source_record, now, ttl):
    # passage: chunk metadata; source_record: current source of truth
    if source_record is None or source_record.deleted:
        return "reindex"          # source is gone; chunk is orphaned
    if passage.source_hash != source_record.hash:
        return "re-retrieve"      # source changed; old chunk may be wrong
    if now - passage.ingested_at > ttl:
        return "warn"             # unchanged, but older than policy allows
    return "ok"

The decision rule is the point: identical hashes and a recent ingestion timestamp mean serve normally; a hash mismatch means the passage is suspect; a missing source means the chunk should not be served at all.

Setting TTLs per content class

A single TTL for the whole corpus is the most common mistake. It either expires stable content constantly (wasting compute) or lets fast-moving content rot (producing wrong answers). Content classes decay at different rates, so TTLs should be set per class and reviewed against how often each class actually changes.

Content classExampleSuggested TTLAction on expiryWhy
Contractual or legalTerms of service, signed agreementsLong (weeks)Serve with warningChanges rarely, but errors are expensive
Policy and processSupport playbooks, security policiesMedium (days)Re-retrieveEdited often, high blast radius
Product and pricingCatalogs, plan detailsShort (hours)Re-retrieve or reindexSuperseded frequently
Reference and API docsEndpoint references, schemasShort (hours)Re-retrieveDeprecations make old text actively wrong
Archival and historicalPast incident reportsVery long or noneServe normallyAge is part of the meaning

The TTL should be derived from observed change frequency, not guessed. Track two numbers per class: what share of documents in the class changed in the last window, and how often answers changed after re-ingestion. The freshness layer of a RAG evaluation separates this cleanly, tracking the share of indexed documents older than your freshness window and how often answers change after you re-ingest the sources the four-layer RAG evaluation framework.

Time-sensitive questions deserve their own place in the test set. Questions about prices, versions or policies whose correct answer changes over time should be labeled as time-sensitive, and their reference answers re-checked against current sources on a review date the four-layer RAG evaluation framework. That gives you a measurable signal when a TTL is too generous.

Chunk size interacts with TTL more than people expect. Smaller chunks (64 to 128 tokens) work best for concise, fact-based answers, while larger chunks (512 to 1024 tokens) improve retrieval where broader context is needed the chunk size study. A small chunk about a price moves on its own schedule and can expire fast. A 1,000-token chunk covering a whole section mixes stable and volatile facts, so its TTL is set by the fastest-moving sentence inside it. Either keep volatile facts in their own small chunks, or accept the shorter TTL for the whole section.

What to do when a passage is stale

There are three actions, and each has a place. The mistake is choosing per incident instead of per content class.

Re-retrieve. Fetch the passage again from the source, re-chunk if needed, and replace the context in the prompt before generation. This is the cheapest fix and the right default for latency-sensitive paths. It works when the source system is fast and the document is small. It does not help when the chunk was never indexed correctly to begin with.

Reindex. Rebuild the chunk and its embedding from the current source. This costs an embedding call plus a write, so reserve it for scheduled jobs, for high-value classes, and for cases where the source changed structurally (sections added or removed, which shifts chunk boundaries). Duplicate embeddings from repeated ingestion are a known drift pattern, so reindexing must be idempotent, keyed on source id and chunk hash the Oracle engineering blog.

Serve with a warning. Return the passage and tell the reader it may be outdated, ideally with the source modification date. This is right for contractual or historical content where the older version is still legitimate evidence, and for any case where refusing to answer is worse than answering with a caveat. It is the wrong choice for prices and API references, where a confidently wrong number is worse than no answer.

A worked example makes the cost concrete. Suppose a support corpus has 40,000 documents, an average of 25 chunks each (one million chunks), and 3,000 queries a day. If every query retrieved 6 passages, that is 18,000 passage-level freshness checks daily, most answered from a cached source hash rather than a live read. Reindexing on demand for even 2 percent of retrievals means about 360 embedding writes a day. Nightly full reconciliation of one million chunk hashes against source records is a batch job measured in minutes, not a per-request cost. The design that survives scale is cached hashes with a scheduled reconciliation.

There is a security dimension too. Poor retrieval becomes a security problem when the system cites an obsolete policy, omits a critical warning, or selects a poisoned document, so authoritative and current documents must be identifiable and the system must show provenance for the evidence it used the RAG security audit guide. Freshness metadata is only useful if retrieval filters enforce it the Oracle engineering blog, which means the filter belongs in the query, not in the prompt.

Instrumenting staleness so it shows up in evaluation

Staleness needs its own detection layer because the usual metrics cannot see it. Retrieval quality metrics such as recall@k, MRR and nDCG measure whether the right passages rank near the top, and generation metrics such as faithfulness and answer relevance measure whether the answer uses them. Neither asks whether the passage is current the RAG evaluation metrics guide. Separating retrieval evaluation from generation evaluation turns a vague quality signal into a diagnosis the Braintrust RAG evaluation guide, and freshness is a third axis alongside them.

Concretely, log four fields per retrieval: passage version, source hash at retrieval, verdict (ok, re-retrieve, reindex, warn), and retrieval timestamp. Then track:

  • Stale serve rate: share of served passages whose verdict was not ok.
  • Hash mismatch rate per content class: tells you which TTLs are too long.
  • Warning rate: how often users see the staleness caveat, which should be near zero for pricing content.
  • Mismatch-to-correctness link: among answers built from stale passages, how often the reference answer changed. This tells you whether the TTLs matter at all.

Version your evaluation datasets, prompts, scorers and corpora alongside the pipeline, because a dataset built on older corpus content will silently pass after the sources change the RAG evaluation metrics guide. A versioned evaluation corpus plus a freshness check gives you both halves of the question: is the answer right, and was it right for the current version of the world.

Metadata carries the version and freshness fields you need to filter on. Structured metadata such as filing year, form type and section heading already holds the disambiguating signals retrieval needs, and integrating it into the index improves retrieval effectiveness by increasing intra-document cohesion and widening the separation between relevant and irrelevant chunks the metadata retrieval study. Version and hash are just two more metadata fields, but they must be enforced at query time: filtering by is_current and is_deleted is what stops superseded text from ranking the Oracle engineering blog.

One more trap: chunking changes shift what a version means. If you move from 512-token to 256-token chunks, the old chunks are not v4 of anything; they are a different cut. Treat re-chunking as a migration with its own version scheme, and backfill chunk hashes so the reconciliation job has something to compare.

A rollout sequence that works

Start with the cheap signals and add cost only where measurement justifies it.

  1. Add source hash and ingestion timestamp to every chunk. No behavior change yet, just data.
  2. Log the four retrieval fields for a week and compute the stale serve rate by content class.
  3. Assign TTLs from observed change frequency, starting generous and tightening the classes where hash mismatches are common.
  4. Wire the verdict into the retrieval query, excluding deleted and superseded chunks by default.
  5. Define one action per content class (re-retrieve for policy and product, warn for legal) and test it with challenge queries that check stale and deleted evidence cannot appear in top-k results the Oracle engineering blog.
  6. Add time-sensitive questions to the golden set with a review date, so staleness failures become visible in CI rather than in support tickets the four-layer RAG evaluation framework.

If you are evaluating several retrieval setups at once, for instance comparing a fast small model against a larger one for the re-retrieval step, routing all of them through one API key simplifies the comparison and keeps the cost accounting in one place. Quanta Inference exposes text, image, video, audio and embedding models behind an OpenAI-compatible, prepaid interface priced in US dollars.

FAQ

FAQ

Is a version field on the passage enough to detect staleness?

No. The version field records which revision the chunk was cut from at ingestion time. It cannot detect silent edits that never bumped the label, newer upstream revisions the index has not seen, or how long a mismatch is tolerable. You need a source check (hash or modification time) and a per-class TTL alongside it.

How often should I reindex?

Set the cadence from observed change frequency per content class, not from a global default. Track the share of documents that changed in the last window and how often answers changed after re-ingestion, then tighten TTLs for classes with high hash mismatch rates the four-layer RAG evaluation framework. Nightly full reconciliation plus on-demand re-retrieval covers most corpora.

Should stale passages be dropped or served with a warning?

It depends on the content class. Drop or re-retrieve for prices, API references and policies where a confidently wrong answer is worse than no answer. Serve with a warning, including the source modification date, for legal and historical content where the older version is still legitimate evidence.

Why does my evaluation suite pass while users get outdated answers?

Because faithfulness and context recall measure whether an answer is supported by retrieved context, not whether that context is current. A dataset built when documents were fresh keeps passing as the corpus decays the RAG engineering guide. Add a freshness layer that logs stale serve rate and re-label time-sensitive questions on a review date.

Does chunk size affect how a TTL should be set?

Yes. A TTL is set by the fastest-moving fact in a chunk, so a large chunk covering a whole section inherits the shortest lifetime of any sentence inside it. Keep volatile facts such as prices in their own small chunks, since smaller chunks (64 to 128 tokens) work best for concise, fact-based answers the chunk size study, and give stable narrative sections longer TTLs.

Sources

Sources

  1. How to Detect RAG Index Drift: Deleted Docs, Stale ...
  2. Why Your RAG Knowledge Base Is Lying About What It Knows
  3. How to Evaluate RAG Systems: A Four-Layer Framework
  4. Rethinking Chunk Size for Long-Document Retrieval
  5. Audit RAG Security Across Data, Retrieval, and Output- ...
  6. RAG evaluation metrics
  7. What is RAG evaluation? Measuring retrieval quality and ...
  8. Utilizing Metadata for Better Retrieval-Augmented Generation
About the author

About the author

Antonio Evans
Antonio Evans

Antonio Evans is the founder of Quanta Intelligence and a fractional CTO who builds HIPAA-ready AI systems for health and life-science companies. Before that he was technical co-founder of FriendsEAT for twenty years, CEO of Socialdraft, and a data engineer at IBM. Antonio lives with his dog Santino in Lisbon, Portugal.

All articles