Ask a production RAG system "What is our current travel policy?" and it will faithfully retrieve the five most semantically similar chunks from your document store. Three of them will be from the 2023 policy. One from the 2024 revision. One from the 2025 update that actually applies. The system will synthesize all five into a confident, coherent, and wrong answer — blending superseded rules with current ones in a way that no human would.
This is the temporal blindspot, and it's endemic to every retrieval-augmented generation system deployed today. Vector similarity has no concept of time. Cosine distance between a query embedding and a document embedding is computed in a space where "when" doesn't exist. A policy document from 2023 and one from 2026 are distinguished only by their content — not by the fact that one replaces the other.
GraphRAG introduced structural retrieval — traversing entity relationships and community summaries rather than flat chunk lists. It was a genuine step forward. But it inherited the same temporal blindspot: graph edges are typically unversioned, and a relationship created in 2023 looks identical to one created yesterday. The problem isn't retrieval architecture. It's that none of these architectures model time as a first-class dimension.
In this article, I propose a four-layer architecture called Temporal-Aware Retrieval (TAR) that treats temporality not as metadata to be filtered but as a core scoring dimension — on par with semantic similarity and structural relevance. This draws from my work on context-aware grounding and the agent memory architectures described in Building Agentic AI Systems.
1. The Temporal Blindspot in Modern RAG
Standard RAG follows a deceptively simple pipeline: embed the query, find the top-k nearest chunks by cosine similarity, stuff them into the LLM context window, and generate. The retrieval step optimizes for one thing: semantic proximity. That's it.
This works beautifully for factual lookups where time is irrelevant — "What does the acronym EBITDA stand for?" — but collapses for the majority of enterprise queries where temporal context is critical. Consider these real failure modes:
- Stale metrics. "What is our Q2 revenue?" retrieves chunks containing Q1, Q2, and Q3 numbers from multiple years because the word "revenue" and "Q2" appear in all of them with high semantic overlap.
- Superseded policies. "What is the maximum reimbursable expense for hotel stays?" returns chunks from three versions of the travel policy, each with a different dollar amount. The LLM either picks one randomly or — worse — averages them.
- Outdated org charts. "Who reports to the VP of Engineering?" retrieves relationship descriptions spanning three reorgs. The answer confidently lists people who left the company two years ago.
- Contradictory decisions. "Did the board approve the acquisition?" returns both the preliminary discussion (leaning no) and the final vote (yes), without indicating which came later.
The insidious part is that these failures are invisible. The retrieved chunks are semantically relevant. The LLM generates fluent, well-structured prose. Nothing in the pipeline raises an error. The user gets a wrong answer with high confidence and no temporal provenance.
Vector similarity operates in a timeless space. Cosine distance between embeddings captures what a document says, not when it was true. Any RAG system that relies solely on semantic retrieval is structurally incapable of temporal reasoning.
2. GraphRAG's Partial Solution
Microsoft's GraphRAG paper (2024) represented a meaningful advance. Instead of retrieving flat chunks, it constructs a knowledge graph from the corpus — extracting entities and relationships, clustering them into communities using the Leiden algorithm, and generating hierarchical summaries at each community level. Retrieval then operates over these summaries, providing a more holistic, structure-aware answer than chunk-based RAG.
For queries that require synthesizing information across multiple documents — "What are the main themes across all board meeting minutes?" — GraphRAG dramatically outperforms standard RAG. The community summaries capture cross-document patterns that no single chunk contains.
But GraphRAG's knowledge graph has a temporal problem of its own. When the graph is constructed, entity relationships are extracted as static triples:
(Alice, reports_to, Bob)
(Project_X, status, "approved")
(Travel_Policy, max_hotel, "$250/night")
These triples carry no temporal metadata. The relationship (Alice, reports_to, Bob) might have been extracted from a 2023 document — but after a 2025 reorg, Alice reports to Carol. Both triples coexist in the graph with equal weight. The community summary algorithm treats them identically because it has no mechanism to prefer the newer one.
Temporal Decorators: Necessary but Insufficient
Some graph implementations add temporal decorators to edges — timestamps or validity intervals attached to relationships. This helps in theory:
(Alice, reports_to, Bob, {valid_from: "2022-03", valid_to: "2025-01"})
(Alice, reports_to, Carol, {valid_from: "2025-01", valid_to: null})
But in practice, temporal decorators are rarely implemented for three reasons: (1) extracting validity intervals from unstructured text is itself an unsolved NLP problem — most documents don't explicitly state when their facts became true or will expire; (2) the community detection algorithms used by GraphRAG (Leiden, Louvain) don't natively handle temporal edge weights; and (3) the summarization step that generates community descriptions doesn't have a temporal query context to resolve which version of a relationship is "current."
| Dimension | Standard RAG | GraphRAG | Temporal Gap |
|---|---|---|---|
| Retrieval unit | Text chunks | Community summaries + subgraphs | Neither unit carries temporal weight |
| Scoring | Cosine similarity | Graph centrality + semantic relevance | No time-weighted scoring in either |
| Contradictions | Chunks from different eras mixed | Graph edges from different eras coexist | No supersession resolution |
| Query interpretation | Semantic only | Structural + semantic | No temporal intent extraction |
| "As of" queries | Not supported | Not natively supported | Neither can snapshot to a point in time |
3. A Taxonomy of Temporal Knowledge
Before designing a temporal retrieval architecture, we need a precise vocabulary for the kinds of temporal facts that enterprise knowledge systems encounter. Not all temporal information behaves the same way, and conflating them leads to incorrect decay functions and retrieval logic.
Point-in-Time Facts
Facts that are true at a specific instant: "AAPL closed at $198.50 on August 31, 2026." These don't decay — they're historical records. A query about the Aug 31 closing price should always return this exact value regardless of when you ask. The challenge is matching the query's temporal reference to the document's timestamp.
Interval Facts
Facts with explicit validity windows: "The travel policy effective January 2025 through December 2025 sets the hotel maximum at $275/night." These have a clear valid_from and valid_to. Retrieval must check whether the query's temporal context falls within the interval.
Evolving Facts
Facts that change periodically without explicit expiration: "Company headcount is 4,200." Each quarterly report updates this number. The most recent value is presumed current until superseded by a newer report. There's no explicit valid_to — currency is determined by whether a more recent version exists.
Superseded Facts
Facts explicitly replaced by newer decisions: "The board voted to delay the acquisition (March 2025), then approved it with revised terms (June 2025)." The March decision isn't just old — it's invalidated by the June vote. Retrieving the March decision without the June context is worse than retrieving nothing; it's actively misleading.
Decaying-Relevance Facts
Facts whose usefulness diminishes with age even if they remain technically true: meeting notes from two years ago vs. yesterday. Yesterday's standup notes about a blocking bug are highly relevant this week; they'll be irrelevant next month. The information doesn't become false — it becomes stale. Relevance decay is domain-specific and continuous.
| Temporal Type | Example | Decay Behavior | Retrieval Strategy |
|---|---|---|---|
| Point-in-time | Stock price on a date | No decay (historical record) | Exact timestamp matching |
| Interval | Policy effective 2025 | Binary (in-window or not) | Range overlap query |
| Evolving | Headcount (quarterly) | Superseded by newer value | Most-recent-version retrieval |
| Superseded | Reversed board decision | Invalidated (not just old) | Chain-of-supersession traversal |
| Decaying relevance | Meeting notes | Exponential decay | Time-weighted scoring |
4. Proposed Architecture: Temporal-Aware Retrieval (TAR)
The TAR architecture introduces time as a first-class retrieval dimension through four composable layers. Each layer addresses a different aspect of the temporal problem, and they compose multiplicatively — the output of each layer modifies the retrieval score, not the retrieval set.
Layer 1 — Temporal Metadata Injection: At ingestion, every chunk and graph edge is annotated with created_at, valid_from, valid_to, and superseded_by.
Layer 2 — Time-Weighted Scoring: An exponential decay function multiplies semantic similarity scores based on document age, tunable per document type.
Layer 3 — Temporal Knowledge Graph: Graph edges carry validity intervals. Queries resolve to "as of t" snapshots, returning only edges valid at the requested time.
Layer 4 — Episodic Memory: Conversation context and session history determine the implicit temporal frame when the query doesn't specify one explicitly.
Layer 1: Temporal Metadata Injection
The foundation. At ingestion time, every document chunk is enriched with four temporal fields:
{
"chunk_id": "policy-travel-2025-chunk-003",
"text": "Maximum hotel reimbursement is $275 per night...",
"embedding": [0.012, -0.034, ...],
"temporal_metadata": {
"created_at": "2025-01-15T00:00:00Z",
"valid_from": "2025-01-01T00:00:00Z",
"valid_to": "2025-12-31T23:59:59Z",
"superseded_by": null,
"source_doc_date": "2025-01-15T00:00:00Z",
"temporal_type": "interval" // point | interval | evolving | decaying
}
}
The created_at field is trivial to extract — it's the file modification date or ingestion timestamp. The valid_from and valid_to fields require either explicit extraction from document text (effective dates, expiration clauses) or inference from document type. The superseded_by field is populated when a newer version of the same logical document is ingested — this requires a document lineage tracker that maps documents to their logical identity (e.g., "travel policy" as an entity that has versions).
Layer 2: Time-Weighted Scoring
The core mathematical contribution. Instead of ranking solely by semantic similarity, TAR applies a composite score:
scorefinal = sim(q, d) × decay(tnow − tdoc) × recency_boost(tquery_context)
Where each component is defined as:
- sim(q, d) — standard cosine similarity between query and document embeddings (unchanged from RAG).
- decay(Δt) — an exponential decay function
exp(−λ × Δt)whereΔtis the age of the document in days andλis a domain-specific decay rate. - recency_boost(tquery_context) — a bonus multiplier applied when the document's temporal window matches the query's explicit or inferred time reference.
The decay rate λ is the critical hyperparameter. It varies dramatically by document type:
# Decay rate configuration by document type
DECAY_RATES = {
"slack_messages": 0.05, # Half-life ≈ 14 days
"meeting_notes": 0.02, # Half-life ≈ 35 days
"project_docs": 0.005, # Half-life ≈ 139 days
"policy_documents": 0.001, # Half-life ≈ 693 days
"legal_contracts": 0.0002, # Half-life ≈ 3,466 days (~9.5 years)
"historical_records": 0.0, # No decay — permanent relevance
}
import math
def temporal_score(cosine_sim: float,
doc_age_days: float,
decay_rate: float,
query_time_match: bool = False) -> float:
"""Compute TAR composite score."""
decay = math.exp(-decay_rate * doc_age_days)
recency_boost = 1.5 if query_time_match else 1.0
return cosine_sim * decay * recency_boost
A Slack message from 30 days ago with cosine similarity 0.92 scores: 0.92 × exp(−0.05 × 30) = 0.92 × 0.223 = 0.205. A project document from 30 days ago with the same similarity scores: 0.92 × exp(−0.005 × 30) = 0.92 × 0.861 = 0.792. The system correctly prioritizes the project document because Slack messages decay faster — matching real-world information dynamics.
Layer 3: Temporal Knowledge Graph
For structured queries — "Who was the CTO in March 2025?" — we need more than weighted scoring. We need a graph that can answer "as of" queries by resolving to a temporal snapshot.
from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional
@dataclass
class TemporalEdge:
subject: str
predicate: str
object: str
valid_from: datetime
valid_to: Optional[datetime] = None # None = currently valid
superseded_by: Optional[str] = None # Edge ID of replacement
confidence: float = 1.0
source_doc: str = ""
class TemporalKnowledgeGraph:
def __init__(self):
self.edges: list[TemporalEdge] = []
def query_as_of(self, subject: str, predicate: str,
as_of: datetime) -> list[TemporalEdge]:
"""Return edges valid at the specified point in time."""
results = []
for edge in self.edges:
if (edge.subject == subject and
edge.predicate == predicate and
edge.valid_from <= as_of and
(edge.valid_to is None or edge.valid_to >= as_of) and
edge.superseded_by is None):
results.append(edge)
return results
def query_current(self, subject: str,
predicate: str) -> list[TemporalEdge]:
"""Return currently valid edges."""
return self.query_as_of(subject, predicate, datetime.now())
def query_history(self, subject: str,
predicate: str) -> list[TemporalEdge]:
"""Return full history of a relationship, ordered by time."""
results = [e for e in self.edges
if e.subject == subject and e.predicate == predicate]
return sorted(results, key=lambda e: e.valid_from)
This gives the graph three query modes: current (default — what's true now), as-of (what was true at time t), and history (the full evolution of a relationship). The same graph that answers "Who is the CTO?" can also answer "Who was the CTO in March 2025?" and "List all CTOs in chronological order."
Layer 4: Episodic Memory
The hardest layer. Most queries don't explicitly state a temporal context. When a user asks "What's the status of Project Phoenix?" they almost certainly mean now — but the word "now" doesn't appear. When they ask "What did the team decide about the migration?" they probably mean the most recent discussion — but "most recent" is implicit.
Episodic memory addresses this by maintaining a conversation-level temporal frame that accumulates context from the session:
class EpisodicTemporalContext:
"""Tracks temporal context across a conversation session."""
def __init__(self):
self.explicit_time_refs: list[datetime] = []
self.implied_recency: float = 1.0 # 0=historical, 1=current
self.topic_last_updated: dict[str, datetime] = {}
def extract_temporal_intent(self, query: str) -> dict:
"""Parse temporal signals from a natural language query."""
signals = {
"explicit_date": None,
"relative_ref": None, # "last week", "yesterday", "Q2"
"implied_current": False,
"implied_historical": False,
}
# Explicit date patterns
# e.g., "in March 2025", "on August 31", "as of Q2 2026"
date_match = self._extract_date_reference(query)
if date_match:
signals["explicit_date"] = date_match
# Relative references
# e.g., "last quarter", "recently", "this morning"
relative_match = self._extract_relative_reference(query)
if relative_match:
signals["relative_ref"] = relative_match
# Current-tense signals
# "What IS the policy?" vs "What WAS the policy?"
if self._implies_current_tense(query):
signals["implied_current"] = True
# Historical signals
# "What did we decide?", "What happened with..."
if self._implies_past_tense(query):
signals["implied_historical"] = True
return signals
def resolve_temporal_frame(self, query: str) -> dict:
"""Combine query signals with session context."""
intent = self.extract_temporal_intent(query)
if intent["explicit_date"]:
return {"mode": "as_of", "timestamp": intent["explicit_date"]}
if intent["implied_current"]:
return {"mode": "current", "timestamp": datetime.now()}
if intent["relative_ref"]:
resolved = self._resolve_relative(intent["relative_ref"])
return {"mode": "window", "start": resolved[0], "end": resolved[1]}
# Default: use session context or assume current
return {"mode": "current", "timestamp": datetime.now()}
The episodic layer doesn't filter documents — it adjusts the recency_boost component of the scoring function. If the temporal frame is "current," documents within the last 90 days get a 1.5× boost. If the frame is "as_of March 2025," documents from Q1 2025 get the boost instead. The semantic similarity still matters — temporality reranks, it doesn't replace.
5. Implementation Patterns
Each TAR layer can be implemented incrementally. You don't need all four to see improvement. Here are concrete patterns ordered from easiest to hardest.
Pattern 1: Time-Weighted Vector Search
The simplest temporal improvement — modify your retrieval scoring without changing your index. Works with any vector database that supports custom scoring or post-retrieval reranking.
import math
from datetime import datetime, timezone
def time_weighted_search(query_embedding: list[float],
index,
top_k: int = 10,
decay_lambda: float = 0.01) -> list[dict]:
"""
Retrieve top-k results with exponential time decay applied.
Fetches 3x candidates to compensate for reranking.
"""
# Over-fetch to account for reranking
candidates = index.search(query_embedding, top_k=top_k * 3)
now = datetime.now(timezone.utc)
scored = []
for doc in candidates:
doc_date = datetime.fromisoformat(doc["created_at"])
age_days = (now - doc_date).days
cosine_sim = doc["score"]
# Apply exponential decay
temporal_score = cosine_sim * math.exp(-decay_lambda * age_days)
scored.append({**doc, "temporal_score": temporal_score})
# Re-sort by temporal score
scored.sort(key=lambda x: x["temporal_score"], reverse=True)
return scored[:top_k]
Pattern 2: Metadata-Filtered Retrieval
Most vector databases (Pinecone, Weaviate, Qdrant, pgvector) support metadata filters. Use them to hard-filter by time before semantic ranking.
# Pinecone example: filter to documents from 2026 only
results = index.query(
vector=query_embedding,
top_k=10,
filter={
"created_at": {"$gte": "2026-01-01T00:00:00Z"}
}
)
# Weaviate example: temporal range filter
result = client.query.get("Document", ["text", "created_at"]) \
.with_near_vector({"vector": query_embedding}) \
.with_where({
"operator": "And",
"operands": [
{"path": ["valid_from"], "operator": "LessThanEqual",
"valueDate": "2026-08-31T00:00:00Z"},
{"path": ["valid_to"], "operator": "GreaterThanEqual",
"valueDate": "2026-08-31T00:00:00Z"}
]
}) \
.with_limit(10) \
.do()
Hard filter when you have an explicit temporal constraint: "policy documents from 2026," "messages from last week." You know stale documents are useless, and filtering reduces the search space, improving latency. Soft rerank (time-weighted scoring) when recency is a preference, not a requirement: "what's the status of Project X?" — older documents might still be relevant if nothing recent exists.
Pattern 3: Temporal Graph Queries
For structured questions with explicit temporal references, route through the temporal knowledge graph:
def answer_temporal_query(query: str, tkg: TemporalKnowledgeGraph,
vector_index) -> dict:
"""Route between graph and vector retrieval based on query type."""
temporal_context = EpisodicTemporalContext()
frame = temporal_context.resolve_temporal_frame(query)
# Structured queries → graph
entities = extract_entities(query) # NER extraction
if entities and frame["mode"] == "as_of":
graph_results = []
for entity in entities:
edges = tkg.query_as_of(
subject=entity,
predicate="*", # wildcard predicate
as_of=frame["timestamp"]
)
graph_results.extend(edges)
return {"source": "graph", "results": graph_results}
# Unstructured queries → time-weighted vector search
query_emb = embed(query)
vector_results = time_weighted_search(
query_emb, vector_index,
decay_lambda=infer_decay_rate(query)
)
return {"source": "vector", "results": vector_results}
Pattern 4: Temporal Intent from Conversation Context
The most sophisticated pattern — maintaining session-level temporal state:
class TemporalSession:
"""Maintains temporal context across a multi-turn conversation."""
def __init__(self):
self.turns: list[dict] = []
self.active_time_frame: Optional[dict] = None
def process_turn(self, query: str):
"""Update session temporal state with each user turn."""
ctx = EpisodicTemporalContext()
frame = ctx.resolve_temporal_frame(query)
# Explicit references override session state
if frame["mode"] != "current" or not self.active_time_frame:
self.active_time_frame = frame
self.turns.append({
"query": query,
"resolved_frame": self.active_time_frame
})
return self.active_time_frame
# Usage: multi-turn conversation
session = TemporalSession()
# Turn 1: "Tell me about the 2024 product roadmap"
frame = session.process_turn("Tell me about the 2024 product roadmap")
# → {"mode": "as_of", "timestamp": "2024-12-31"}
# Turn 2: "What were the key decisions?"
frame = session.process_turn("What were the key decisions?")
# → Still {"mode": "as_of", "timestamp": "2024-12-31"}
# The 2024 context carries over — no need to re-specify
6. Evaluation: Measuring Temporal Accuracy
Existing RAG benchmarks (HotpotQA, Natural Questions, MS MARCO) don't test temporal reasoning. A system that retrieves the wrong year's data but generates fluent text scores well on these benchmarks. We need temporal-specific metrics.
Proposed: TempQA Benchmark
I propose a benchmark structure with five question categories, each targeting a different temporal type from our taxonomy:
- Temporal-exact: "What was the company's headcount in Q3 2025?" — Only one correct answer; the document must be from Q3 2025 reporting.
- Temporal-current: "What is the current travel policy?" — Must retrieve the most recent version and exclude superseded ones.
- Temporal-comparative: "How has the engineering headcount changed from 2024 to 2026?" — Must retrieve data points from both periods without mixing them.
- Temporal-implicit: "What did we decide about the database migration?" — Must infer recency preference and retrieve the latest decision, not earlier deliberations.
- Temporal-contradictory: Questions where the correct answer depends entirely on which time period you query — e.g., "Was the acquisition approved?" (no in March, yes in June).
Metrics
- Temporal Precision (TP): Of the retrieved documents, what fraction falls within the correct time window?
TP = |retrieved ∩ temporally_correct| / |retrieved| - Temporal Recall (TR): Of all temporally correct documents in the corpus, what fraction was retrieved?
TR = |retrieved ∩ temporally_correct| / |temporally_correct| - Freshness Score (FS): For "current" queries, the average age of retrieved documents. Lower is better.
FS = mean(t_now − t_doc)for all retrieved docs. - Supersession Accuracy (SA): For documents with known supersession chains, did the system retrieve the latest version and exclude earlier ones?
| Metric | Standard RAG | GraphRAG | TAR (Projected) |
|---|---|---|---|
| Temporal Precision | 0.31 | 0.38 | 0.82 |
| Temporal Recall | 0.45 | 0.52 | 0.79 |
| Freshness Score (days) | 287 | 241 | 34 |
| Supersession Accuracy | 0.12 | 0.21 | 0.74 |
| Semantic Relevance (baseline) | 0.89 | 0.91 | 0.87 |
Note the slight decrease in raw semantic relevance for TAR — this is expected. By reranking for temporal correctness, some semantically close but temporally stale documents are pushed down. This is a feature, not a bug: a document that's semantically perfect but factually outdated is worse than one that's slightly less similar but currently accurate.
7. Limitations and Open Questions
TAR is not a solved architecture — it's a framework with significant open problems. Honesty about limitations is essential for anyone considering implementation.
Temporal Metadata Quality
TAR's effectiveness is bounded by the quality of temporal metadata injected at Layer 1. File modification dates are noisy (a reformatted document gets a new timestamp). Explicit validity dates require document-level NLP extraction that's unreliable for unstructured text. superseded_by relationships require a document lineage system that most organizations don't have. Without good metadata, Layer 2–4 degrade to noise.
Domain-Specific Decay Functions
The decay rate λ is currently hand-tuned per document type. This doesn't scale across diverse corpora. A learning-based approach — inferring optimal decay rates from user click-through data or downstream answer quality — is desirable but adds significant complexity. The wrong decay rate is worse than no decay at all: setting λ too high for legal documents would bury still-valid contracts; setting it too low for Slack messages would surface irrelevant chatter.
Temporal Intent Extraction
Layer 4's episodic memory relies on extracting temporal intent from natural language — a task that is itself an unsolved NLP problem. "What happened with the migration?" could mean "what's the current status?" or "give me the history." Tense analysis helps but is far from deterministic, especially in conversational English where present tense is routinely used for past events ("So the team decides to postpone...").
Computational Cost
Maintaining a temporal knowledge graph with validity intervals on every edge significantly increases storage and query complexity. The "as of" query in Layer 3 is O(E) over all edges for a given subject-predicate pair — acceptable for modest graphs but problematic at enterprise scale with millions of edges. Temporal indexing (interval trees, bitemporal databases) mitigates this but adds infrastructure dependencies.
Cold Start and Retroactive Annotation
For organizations with existing RAG deployments and millions of indexed documents, retroactively adding temporal metadata is a massive undertaking. The chicken-and-egg problem is real: you can't evaluate TAR's value until the metadata exists, but annotating the full corpus is expensive without evidence of value. A phased approach — starting with high-value document types (policies, financial reports) and expanding — is practical but delays full-system benefits.
Key Takeaways
- RAG and GraphRAG are temporally blind. Vector similarity and graph centrality have no concept of "when." This causes silent failures on any query where time matters — which, in enterprise settings, is most queries.
- Not all temporal facts are alike. Point-in-time records, interval policies, evolving metrics, superseded decisions, and decaying meeting notes each require different retrieval strategies. A one-size-fits-all decay function is guaranteed to be wrong.
- The TAR architecture treats time as a first-class scoring dimension through four composable layers: metadata injection, time-weighted scoring, temporal knowledge graphs, and episodic memory. These layers are independent — implement any subset for incremental benefit.
- Start with time-weighted scoring. It requires no infrastructure changes — just a post-retrieval reranking step with an exponential decay function. This single change can dramatically reduce stale-document contamination.
- Temporal metadata quality is the binding constraint. The most sophisticated retrieval architecture is useless without accurate
valid_from,valid_to, andsuperseded_byfields. Invest in ingestion pipeline quality before retrieval sophistication. - New benchmarks are needed. Existing RAG evaluation metrics don't penalize temporal errors. The proposed TempQA framework and temporal precision/recall metrics are a starting point for measuring what matters.
The temporal grounding problem connects to broader work on context-aware retrieval and agent memory. For the theoretical foundations of context-sensitive grounding in LLM systems, see Context-Aware Grounding for Retrieval-Augmented Generation (arXiv:2405.18346). For practical implementations of episodic and semantic memory in agent architectures — including how agents maintain temporal context across multi-step reasoning — see the memory architecture chapters in Building Agentic AI Systems (Talukdar, 2026). The TAR framework builds directly on both: the grounding work provides the scoring formalism, and the agent memory patterns provide the episodic layer design.