◉GEMINI LABJP
●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●DEEP RES — deep-research-pro-preview-12-2025 shuts down 10/23, 6 days left. Move to deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●MCP — One write-up cut an 85,000-token tool result to 310 tokens by wrapping it in an ADK FunctionTool●FLASH — gemini-3.7-flash and 3.5-flash now route automatically to newer Flash models (10/08)●NEW — Stop Re-Reading Every Crash Report: Gre…●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●DEEP RES — deep-research-pro-preview-12-2025 shuts down 10/23, 6 days left. Move to deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●MCP — One write-up cut an 85,000-token tool result to 310 tokens by wrapping it in an ADK FunctionTool●FLASH — gemini-3.7-flash and 3.5-flash now route automatically to newer Flash models (10/08)●NEW — Stop Re-Reading Every Crash Report: Gre…
Articles/Advanced
⬡ Advanced/2026-07-08Advanced

When Your Knowledge Base Shifts Mid-Run: Pinning File Search to an Execution Epoch for Consistent Agent Grounding

When a File Search store is updated while a Managed Agent is running, a single execution can mix old and new grounding. Borrowing MVCC ideas, pinning an execution epoch keeps one agent run's evidence consistent. Here is the design and implementation.

Gemini API249Managed Agents8File Search7RAG14Architecture10

✦ Premium Article

I was tracing an agent run that a nightly batch had produced, and I stopped cold.

The generated artifact justified its conclusion using a passage from an internal document. But that document had already been retired by a separate update process running at the same moment. The first half of the run cited the old revision; the second half cited the new one. Within a single execution, the grounding had swapped underneath it.

Managed Agents now run autonomously inside Google-hosted, isolated sandboxes, and File Search has reached GA with multimodal support. Behind the comfort of handing off the runtime, there is an easy trap to miss: a single agent run stretches from tens of seconds to several minutes, and the knowledge base keeps moving the entire time.

This article lays out a design for treating an agent execution as a single consistent snapshot, together with the implementation. It is an attempt to bring MVCC — multiversion concurrency control, familiar from databases — into File Search. As an indie developer running apps solo at Dolice, I welcome handing off the runtime; grounding consistency, though, is the one piece I still want to hold in my own hands.

Why an Agent Run Needs a Consistency Boundary

For a one-shot question, this problem never surfaces. Search, answer, done. It takes milliseconds, and the odds of a store mutating in that window are low.

An agent execution is different. It plans, searches several times, runs code partway through, then searches again. This whole sequence behaves like a single transaction, yet each intermediate search independently reaches for the latest store.

The result is inconsistency like this:

TimeAgent sideStore sideRead result
T0Run starts, searches doc-A—doc-A v1 (old)
T1—doc-A updated to v2, v1 retired—
T2Searches doc-A again—doc-A v2 (new)
T3Blends v1 and v2 into a conclusion—Contradictory artifact

In distributed-systems terms, this is a torn read. Without read consistency, the agent cannot notice that the premise of its own reasoning changed midway.

The key is not to solve this with full concurrency control. Freezing writes to the store while the agent runs is impractical — it would mean stopping the production app that is your revenue's front door. What you actually need is a mechanism that lets writes continue freely while the reader — the agent — keeps seeing "the world as it was the instant the run began."

Give Metadata a Version History

File Search lets you attach metadata to chunks and filter on it at query time. We repurpose that mechanism for versioning.

Each chunk carries two fields describing its validity window:

  • active_from: the logical time the chunk became active (a monotonically increasing integer epoch)
  • retired_at: the logical time it was invalidated. A large sentinel value (e.g., 9999999999) while still live.

An update is no longer an overwrite; it becomes "retire the old revision, add the new one." A delete is not a physical removal but a soft delete that sets retired_at to the current epoch. With this, the state at any past point can be reconstructed from a filter expression alone.

Use a logical counter that increments per write, not wall-clock time — clocks can go backward under skew. Stand up a single counter (a transactional Firestore increment, or an atomic KV add) as your one "version issuer."

# Version issuer: hands out a monotonically increasing epoch on each write.
# Assumes an atomic KV increment (Firestore / Redis / Durable Object all work).
 
def next_epoch(kv) -> int:
    # Atomic add. Returns a monotonic value with no duplicates under concurrency.
    return kv.incr("filesearch:epoch")
 
def now_epoch(kv) -> int:
    v = kv.get("filesearch:epoch")
    return int(v) if v is not None else 0
✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦A concrete implementation that pins an execution epoch so a single agent run always sees one consistent snapshot of search results
✦The write-side design that turns updates and deletes into soft deletes, with a cost estimate for when to prune
✦How to build drift detection and a fail-safe for when grounding shifts mid-run
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

⬡ Advanced2026-08-31
Define What Counts as a Duplicate Before Adding Embedding Search to Your Image Pipeline
My dedup check flagged two prints with identical composition but different colors as one image. Here is how I split duplicate detection into three layers, measured where perceptual hashing ends, and decided what embedding search is actually for.
⬡ Advanced2026-09-24
I Stopped Asking Gemini 'Is This Right?' and Started Hiding My Answer Instead
Ask Gemini to confirm a label you already chose and it tends to agree. Here is why I compared three ways of asking, chose blind re-classification, how my answer still leaked in, and the routing code that sends only disagreements to a human.
⬡ Advanced2026-09-14
When BLOCK_NONE Changes Nothing: Telling Adjustable Gemini Blocks from the Ones You Can't Move
Some safety blocks go away when you loosen a threshold. Others never will. Here is how to read the response and decide which kind you are looking at before you touch a single setting.