60db Logo
  • Architecture

Rewrite retrieval queries after a caller corrects a fact

Version retrieval queries so spoken corrections invalidate old evidence before it reaches the next answer.

Editorial date
Reading time
25 min
A revised query replaces an obsolete query while a late result stops at a gate

TL;DR: Rewrite retrieval queries from the current accepted facts whenever a caller corrects a material value. Give each query an immutable fact snapshot and revision, then reject results whose revision is obsolete before using their evidence or submitting speech.


A caller asks about a return policy for an unopened item, then says it was opened. The first search finishes after the correction, and the agent confidently reads the unopened-item policy.

The search service returned a relevant document. Relevance was calculated against an obsolete question, so improving the document ranking would leave the failure intact.

The useful first fix is to put a revision gate between asynchronous retrieval and answer construction. A result must belong to the current accepted question before the application considers its citations, wording, or speech.

This guide builds a small versioned query contract with runnable Python fixtures. It covers correction scope, immutable snapshots, stale arrivals, conflicting revisions, cancellation, and the boundary between retrieving evidence and authorizing a business action.

All examples are synthetic. The diagrams are conceptual unless labeled otherwise, and the reference program is an in-process contract demonstration rather than a production SDK or an account of 60db Agent's implementation.

Table of contents

  1. Define the correction boundary
  2. Build queries from accepted facts
  3. Separate relevance from eligibility
  4. Run the versioned query contract
  5. Reject late results after waiting
  6. Trace the retrieval decision
  7. Choose correction and cancellation policy
  8. Replay races and difficult corrections
  9. Validate retrieval and spoken behavior
  10. Operate the contract safely
  11. Preserve correction meaning across adapters
  12. Frequently asked questions
  13. Put the revision gate into practice

Define the correction boundary

A spoken correction changes the application's accepted interpretation of a question. It can replace an entity, narrow a time period, withdraw a premise, or change which account the caller means.

Start by writing the question as explicit fields. In the synthetic return example, those fields could include item category, opened status, purchase region, and the kind of help requested.

Only store fields that affect the retrieval task. A sprawling transcript summary makes it difficult to see whether the corrected value reached the next search request, while an underspecified query loses the conditions that select the right policy.

Treat recognition revisions separately from user corrections. A speech recognizer can revise an interim word without the caller changing their mind; the application can also receive a complete, accurate transcript of a caller explicitly replacing a previous answer.

The guide to partial transcript revisions explains the first boundary. The field-revision approach to spoken self-corrections explains how to replace accepted values without concatenating both alternatives.

A correction needs a target and a base revision. "Thursday instead" can be clear when a single date is active, but it becomes ambiguous when the conversation contains a delivery date and an appointment date.

Do not solve ambiguous scope by rewriting the whole conversation into a confident search query. Ask which date changed, keep the uncertainty explicit, and prevent the unresolved field from authorizing a specific answer.

A material correction advances the retrieval revision even when the resulting query text looks similar. The scope changed, and the old result no longer has authority simply because its embedding remains close to the revised request.

An exact duplicate correction is different. Replayed delivery of the same accepted revision should preserve the current state rather than starting another search or creating a new version for no semantic change.

Define these rules before adding a language model rewriter. A model can propose a standalone question, but your application still owns the accepted values, tenant boundary, revision order, and permission checks.

A conceptual flow sends accepted facts through a query snapshot and retriever, then checks current revision before an answer

The diagram's admission gate is separate from the search service. That placement matters because a result can be internally correct and still be ineligible for the current conversation.

Build queries from accepted facts

A query should carry a snapshot of the values that produced it. Otherwise, a mutable dictionary can change while the request is in flight, making the logged request and the applied result appear to describe the same state when they never did.

Use an immutable supported value shape at this boundary. The reference program accepts string keys and string values, copies them into a sorted tuple, and exposes a frozen request containing that tuple.

This is deliberately narrower than arbitrary JSON. If your task needs nested lists or objects, define and recursively copy that shape rather than assuming a frozen outer object also freezes every nested value.

Python's dataclasses documentation describes frozen=True; the example uses immutable strings and tuples inside frozen records. This combination avoids retaining a writable caller-owned dictionary as the approved query state.

Separate a human-readable query from its hard filters. A useful search sentence might describe return eligibility, while explicit filters enforce region, document visibility, product family, and the applicable policy revision.

A rewriter should not be allowed to remove tenant or authorization filters. Those constraints come from trusted session and policy state, even if the caller asks the assistant to search everything or claims to represent another account.

NVIDIA's public RAG prompt customization documentation includes a query-rewriting role for follow-up context. That documents a useful component boundary; it does not establish that any particular rewrite preserves your application's fields.

Validate the proposal against accepted state before dispatch. If a proposed query says "unopened" while the accepted field says "opened," reject or regenerate it rather than allowing fluent language to override the structured constraint.

For a small bounded domain, deterministic query construction can be enough. Joining an allowed set of field names and values is often easier to audit than a second model call, especially when the caller's correction changes one well-defined field.

Free-form requests need more care. Keep the original utterance as restricted evidence, record the resolved interpretation separately, and make the rewriter's output an inspectable proposal rather than a new source of truth.

Do not include unnecessary identifying information in the query text. Search requests can leave the conversation service and enter telemetry, vendor logs, or caches with different retention rules.

The local versus managed voice AI boundary is useful when deciding where this evidence travels. The relevant question is which service receives each field and which controls that service applies, not which deployment label sounds more private.

Separate relevance from eligibility

Eligibility comes before ranking. A document from the wrong tenant or an old question is unacceptable even when its semantic similarity score is higher than the correct document's score.

Elasticsearch's query and filter context documentation distinguishes relevance scoring from yes-or-no filter decisions. Apply the same separation to conversation revision, identity scope, and source visibility.

A search result must pass several independent checks. It must belong to the issued request, remain current for the task, satisfy the authorized data scope, and contain evidence that supports the proposed claim.

A revision match proves only the second of those properties. It does not prove that the source is current, that a citation supports every sentence, or that the caller is entitled to the information.

Use typed rejection outcomes so the controller can recover appropriately. A stale result can be discarded while the current query continues; an access denial should suppress private evidence; an empty result may lead to clarification or a different public search.

Treat a changed payload at the same revision as a conflict. An older delivery is stale, and an identical delivery at the current revision is a duplicate, so classify ordering before deciding that a finalized value was contradicted.

The following table compares policy properties, not vendors. A check means the policy explicitly handles the criterion; a cross means that property is absent and must be supplied elsewhere.

Criterion Query text only Cancellation only Snapshot plus admission gate
Reproduces accepted fields ✗ No owned snapshot ✗ Depends on caller state ✓ Immutable supported values
Rejects late old results ✗ No revision comparison ✗ Cooperative stop can race ✓ Compares active revision
Stops wasted remote work ✗ No cancellation ✓ Where cancellation is supported ✗ Requires separate cancellation
Preserves duplicate semantics ✗ Text equality is incomplete ✗ No revision ledger ✓ Explicit duplicate outcome
Establishes caller permission ✗ No ✗ No ✗ Separate authorization required
Proves spoken comprehension ✗ No ✗ No ✗ Listening evaluation required

The gate is a correctness boundary. Cancellation is a resource-control technique that can reduce work, and you can use both without treating cancellation success as the proof that old evidence cannot escape.

A result enters an explicit revision comparison with yes leading to evidence inspection and no leading to discard

Keep the comparison literal in code and diagrams. An arrow from "old result" directly to "current answer" would erase the boundary this design exists to enforce.

Run the versioned query contract

Save the complete fence as query_revisions.py and run it with Python 3.11 or later. It uses the standard library and no network service, so the assertions validate state behavior without claiming retrieval quality or carrier performance.

The ledger owns accepted facts, revision order, and terminal closure. The retriever adapter owns request authentication, source filters, deadlines, response parsing, source versions, and evidence validation.

The admit function is synchronous. In a single event loop, the caller must perform the protected local use immediately after admission without another await; another asynchronous boundary requires another check.

import asyncio
from dataclasses import dataclass, FrozenInstanceError


def snapshot(values):
    if type(values) is not dict or not values:
        raise ValueError("nonempty string dictionary required")
    if any(type(k) is not str or type(v) is not str
           or not k or not v for k, v in values.items()):
        raise ValueError("nonempty string fields required")
    return tuple(sorted(values.items()))


@dataclass(frozen=True)
class Query:
    revision: int
    fields: tuple


class Ledger:
    __slots__ = ("__revision", "__fields", "__final", "__closed")

    def __init__(self):
        self.__revision = -1
        self.__fields = ()
        self.__final = False
        self.__closed = False

    @property
    def current(self):
        return Query(self.__revision, self.__fields)

    def update(self, revision, values, final=False):
        if type(revision) is not int or revision < 0:
            raise ValueError("nonnegative integer revision required")
        if type(final) is not bool:
            raise ValueError("boolean final flag required")
        fields = snapshot(values)
        if self.__closed:
            return "closed"
        if revision < self.__revision:
            return "stale"
        if revision == self.__revision:
            return ("duplicate" if (fields, final) ==
                    (self.__fields, self.__final) else "conflict")
        if self.__final:
            return "conflict"
        self.__revision, self.__fields = revision, fields
        self.__final = final
        return "accepted"

    def close(self):
        self.__closed = True

    def issue(self):
        if self.__closed or self.__revision < 0:
            raise RuntimeError("no active question")
        return self.current

    def admit(self, query):
        if self.__closed:
            return "closed"
        return "current" if query == self.current else "stale"


async def retrieve(ledger, query, fetch):
    evidence = await fetch(query)
    outcome = ledger.admit(query)
    return outcome, evidence if outcome == "current" else None


async def tests():
    ledger = Ledger()
    source = {"item": "book", "opened": "no"}
    assert ledger.update(0, source) == "accepted"
    old = ledger.issue()
    source["opened"] = "yes"
    assert dict(old.fields)["opened"] == "no"
    try:
        old.fields = ()
        raise AssertionError("request was writable")
    except FrozenInstanceError:
        pass
    try:
        old.fields[0] = ("item", "changed")
        raise AssertionError("snapshot was writable")
    except TypeError:
        pass
    try:
        ledger.current = old
        raise AssertionError("current property was writable")
    except AttributeError:
        pass
    started, release = asyncio.Event(), asyncio.Event()

    async def delayed(query):
        started.set()
        await release.wait()
        return ("synthetic source", query.fields)

    pending = asyncio.create_task(retrieve(ledger, old, delayed))
    await started.wait()
    assert ledger.update(1, source) == "accepted"
    assert ledger.admit(old) == "stale"
    current = ledger.issue()
    assert ledger.admit(current) == "current"
    release.set()
    assert await pending == ("stale", None)
    assert ledger.update(1, source) == "duplicate"
    assert ledger.update(1, {"opened": "no"}) == "conflict"
    assert ledger.update(2, source, final=True) == "accepted"
    assert ledger.update(0, {"opened": "old"}) == "stale"
    assert ledger.update(2, source, final=True) == "duplicate"
    assert ledger.update(3, source) == "conflict"
    terminal = ledger.issue()
    ledger.close()
    assert ledger.admit(terminal) == "closed"
    assert ledger.update(2, source, final=True) == "closed"
    try:
        ledger.issue()
        raise AssertionError("closed ledger issued a query")
    except RuntimeError:
        pass
    for bad in ({}, {"opened": []}, {"": "x"}, {1: "x"}):
        try:
            snapshot(bad)
            raise AssertionError("invalid values accepted")
        except ValueError:
            pass
    print("synthetic query revision fixtures passed")


if __name__ == "__main__":
    asyncio.run(tests())

The final flag seals this particular question record. A new question after finalization needs a new ledger identity in the adapter; silently reopening the same finalized record would make old revision identities ambiguous.

The example uses a single active question and one event-loop owner. It does not provide distributed concurrency control, durable storage, multi-process locking, or a search engine, and those responsibilities should remain visible when you adapt it.

The values in the test are deliberately ordinary strings. They demonstrate alias isolation and conflict handling without publishing a real account identifier, utterance, or retrieved document.

Reject late results after waiting

Every await creates an opportunity for conversation state to change. Checking revision before calling the retriever is useful admission control, but it cannot establish that the result is still current when retrieval finishes.

Check after the await, before incorporating evidence into a prompt. If answer generation also awaits, check again after generation before admitting the response to the output path.

The Python asyncio task documentation describes cancellation behavior. A cancellation request does not replace the application's revision comparison when work is delegated to another process or a service with its own lifetime.

A late old request must not cancel a newer request as a side effect of being discarded. Compare identity first, classify it as stale, and leave the current generation alone.

Use meaningful spoken sentence boundaries when building the output plan. Keep retrieval generation and playback generation separate when they have different lifetimes. A corrected query can produce fresh evidence while an older spoken sentence is still queued, so changing the retrieval revision alone cannot clear already buffered audio.

The interruption ownership guide and bounded audio queue guide cover that output boundary. Carry the accepted response generation into speech submission and repeat its checks after any waiting step.

A retriever timeout also needs a separate outcome from an empty answer. Empty means the search completed without eligible evidence; timeout means the application lacks the promised evidence at the deadline.

Do not fill either outcome with account-specific guesses. Offer a narrow clarification, state that the information is unavailable, or hand off according to the task's policy.

The guide to truthful waiting speech helps keep the caller informed without claiming a lookup succeeded. Waiting language should describe ongoing work rather than preannounce the answer the abandoned query might have returned.

Cached retrieval results need the same final gate. A cache hit can save a remote request, but it cannot restore authority to a closed question or make an obsolete fact snapshot current again.

Trace the retrieval decision

A useful diagnostic trace connects the accepted correction to the exact search and admission outcome. Logging only the final transcript leaves the engineer guessing which interpretation controlled retrieval.

Record the question identity, accepted revision, material field names, source revision, request identity, and admission outcome. Hash or omit sensitive values according to the diagnostic task rather than copying full text by default.

W3C's PROV overview describes entities, activities, and agents for provenance. You can use the simpler practical distinction between the source evidence, the activity that transformed it, and the decision that admitted it without claiming a complete PROV implementation.

Keep request creation, remote completion, and local admission as separate events. Completion proves that some result arrived; admission records whether that result was eligible for the question that existed at that moment.

A synthetic replay should retain the original revision sequence and result identity. Derived labels such as "stale answer" are useful summaries, yet they cannot reconstruct the race if the original request and state transitions were discarded.

Four conceptual checkpoints inspect rewrite input, search request, returned evidence, and speech admission

The voice observability guide explains why separate boundaries need separate events. Correlating them does not require putting raw transcripts into an unrestricted log stream.

For each failed example, ask where the first incorrect value appeared. A correct accepted state followed by a wrong query suggests a rewrite or adapter defect; a correct query followed by an irrelevant source suggests a retrieval problem.

Correct evidence followed by an unsupported spoken claim points toward answer construction. Correct text followed by old queued audio points toward output invalidation, and these failures require different repairs.

Keep clock domains explicit. A remote service timestamp and a local monotonic deadline cannot be subtracted without a declared mapping; revision correctness should depend on identity and ordering rather than an optimistic timestamp comparison.

Choose correction and cancellation policy

Cancel obsolete retrieval when the provider supports it and the expected resource saving justifies the coordination. Continue to reject obsolete results even when cancellation appears successful.

Some corrections change only wording. Others change a hard eligibility condition, and the latter need immediate invalidation even if the application waits briefly before issuing the replacement query.

A bounded debounce can avoid issuing a new search for every interim transcript revision. During that waiting period, suppress answers that require the unresolved field rather than using the old interpretation as a temporary default.

Different retrieval domains need different policies. A public glossary lookup can tolerate wider reuse than a current account entitlement check, and a correction to a product name can require a different index as well as different text.

The answer caching guide separates reusable wording from fresh account state. Its freshness checks complement revision checks because a query can be current while its source data is old.

Separate conceptual columns show request cancellation, late-result rejection, and query refresh as different responsibilities

Do not reuse a query solely because the rewritten strings are equal. Equal strings can conceal different account scopes, source versions, languages, or accepted constraints that the rewriter failed to express.

A safe reuse key includes the dimensions that determine eligibility and meaning. If you cannot enumerate those dimensions for a sensitive task, begin with fresh retrieval and inspect the resulting latency before adding a semantic cache.

Use the latency measurement guide to evaluate the extra work. Measure correction-to-eligible-answer time separately from the abandoned query's completion time, and include timeouts and clarification outcomes in the report.

Replay races and difficult corrections

The most revealing fixture starts the old request, applies the correction, then releases the old result. It should return a stale outcome with no usable evidence even when the old result contains a plausible policy.

The reference harness uses events to force this order. Fixed sleeps would make the test depend on scheduler timing and could allow a passing result without exercising the intended race.

Add the opposite order too: admit the result, then correct the field before speech submission. That case belongs at the output boundary, where the response generation must be invalidated before another queued sentence leaves the application.

Test corrections that remove a constraint. "Any day is fine" should clear the date restriction when the task permits it, rather than leaving an old day hidden inside a rewritten query or filter object.

Test negation explicitly. "I did not open it" and "I opened it" are close in vocabulary and different in the condition they establish, so semantic similarity is a poor substitute for an accepted-field assertion.

A caller can also correct the referent. "I meant the other order" should trigger identity resolution for the selected business object rather than copying the previous object's history into a new question.

The shared-phone isolation guide covers a related mistake: a known endpoint does not establish which person is speaking. Retrieval must remain inside the verified subject's allowed scope.

A synthetic race starts an old query, applies a caller correction, starts a new query, and rejects the old result

Finally, replay transport duplicates and out-of-order correction messages. Strictly older revisions should remain stale even after finalization, while a changed payload reusing the current revision should be reported as a conflict.

The regression testing guide provides the broader replay approach. Keep these contract cases alongside representative language fixtures so a model change cannot pass by producing fluent answers while breaking revision ownership.

Validate retrieval and spoken behavior

Validate query correctness before evaluating answer quality. For each fixture, compare accepted fields with the actual submitted query and filters, including constraints omitted by a generated rewrite.

Then inspect eligible evidence. Confirm that cited passages support the answer under the corrected facts and that source versions match the task's freshness policy.

Finally, review the spoken response. The caller should hear the corrected interpretation without a long explanation of internal search state, and the agent should ask for clarification when the correction target remains uncertain.

A real community question asks which layer should fix follow-up retrieval. That discussion supplies a useful symptom, but the fixture trace should decide whether your failure begins in accepted state, rewriting, filtering, ranking, or answer construction.

Do not import commenters' performance claims into your own evaluation. Use an observed workload, retain the failed cases, and report exactly which boundary the experiment measures.

For a listening review, ask whether the answer addresses the corrected question and whether its first spoken unit remains useful if the caller interrupts. The retrieval-to-speech contract develops that last boundary.

Use the outcome evaluation guide to define the caller-level denominator. Separate stale-result rejection counts from retrieval misses. A rejected old result can indicate the contract worked, while a missing fresh answer can still mean the overall caller experience needs improvement.

Operate the contract safely

Authorization remains independent of query revision. OWASP's authorization guidance calls for permission validation on every request; keep those checks in the trusted data-access path rather than delegating them to a natural-language rewrite.

Roll out a revision gate first in a mode that records prospective outcomes without exposing extra evidence. Compare the recorded decisions with synthetic replays and reviewed calls before making it responsible for suppressing or replacing output.

A shadow gate must not widen data collection or bypass authorization. Record the minimum trace needed to check the decision and keep retention and access policies attached to the evidence.

Define an unavailable-state response before a failure occurs. If the current query cannot complete, the controller needs a truthful fallback that does not recycle the obsolete answer simply because it is available in a cache.

For business actions, perform another current-state check at commit time. Retrieval about a policy, an offered option, and permission to change a record are separate boundaries, as the workflow enforcement guide explains.

Document the reference contract's limits in the adapter. The single-owner example establishes revision admission locally; distributed workers need an atomic authority check at the place where the protected action happens.

Preserve correction meaning across adapters

A revision number is useful only when every adapter carries the same meaning. Write down what advances it, which component allocates it, and whether a retry can ever reuse it with changed fields.

For the reference program, the owner allocates an increasing revision for accepted question state. A transport retry repeats the existing revision and the exact same supported payload; it never edits fields while preserving the old identity.

In a distributed application, do not let independent retriever workers invent conversation revisions. They can allocate request identities for their own attempts, but the question owner should assign the accepted-state identity that all attempts must reference.

Keep retries inside that distinction. A failed network attempt can retry the same question revision, while a caller correction creates a new accepted state even when the provider request has not yet timed out.

An adapter that drops the revision field creates a silent gap. Require it in the internal response envelope and reject an uncorrelated result rather than attaching whichever question happens to be active when the callback arrives.

A provider may return its own request identifier, which is useful evidence but insufficient by itself. Store the mapping from your question revision and attempt identity to that identifier before the callback can be processed.

The ordering rule also needs a restart story. If a process begins again at revision zero while old callbacks remain deliverable, the same number can describe two unrelated questions unless a durable question identity separates them.

Use a new opaque question identity after a restart when you cannot recover the old owner's state. Preserve terminal disposition for abandoned identities long enough to reject their known outstanding deliveries, with retention determined by the real delivery contract.

Do not announce that all callbacks have disappeared merely because the local task was canceled. A remote service, queue, or retrying sender can outlive the process that issued the request.

The response adapter should validate the supported data shape before any evidence reaches answer generation. A matching revision cannot make a malformed source object safe, and a syntactically valid source object cannot grant itself permission to speak.

For streaming retrieval, each increment needs the request identity and accepted revision. If the caller corrects a material fact midway through a stream, subsequent increments from the old request remain stale even when they arrive after the replacement stream begins.

Keep a stream's completion separate from its eligibility. A completion marker can close accounting for obsolete work without adding its passages to the current evidence set.

An answer builder should receive an explicit eligible evidence bundle rather than a shared mutable list that retrieval tasks can keep appending to. Copy or freeze the supported evidence shape at that handoff, and attach the accepted revision to the bundle.

This avoids a second alias problem. Freezing query fields protects the request, but an old asynchronous worker can still contaminate answer construction if both generations share a writable collection of passages.

A related test should hold an old stream, begin a current answer, release an obsolete passage, and assert that the current bundle remains unchanged. That fixture belongs in your adapter suite because the compact program intentionally returns one completed result rather than modeling a streaming service.

Clarification deserves its own state. When the caller's correction is unresolved, keep dependent retrieval blocked while allowing unrelated safe dialogue, such as asking which date or item they meant.

Do not encode unresolved state as an empty string that the rewriter silently omits. An omitted constraint can widen the search and produce a confident answer to a question the caller has not yet finished specifying.

Represent absence according to the domain. A deliberately cleared optional field, an unknown required field, and a field that was never requested can require different retrieval and clarification behavior.

The same care applies to language changes. If the caller switches languages while correcting a product name, preserve the canonical product identity and the preferred response language as separate values rather than translating an identifier into a different search target.

The multilingual evaluation guide explains why transcript-level correctness and successful task interpretation need separate evidence. A correction test should include the exact field that must survive language handling.

For source changes, identify whether the retrieved evidence is a snapshot or a live view. A policy document with an explicit version can support a reproducible answer even if a newer edition exists, provided your task intentionally asks about that historical version.

A current-policy question has a different requirement. Its answer needs a source freshness check at the declared boundary, and a cached old policy cannot become current because the caller's question revision still matches.

This distinction prevents over-invalidation too. A spelling correction to the caller's preferred name should not restart a public technical lookup when that name never affected the question or access scope.

Write a dependency map for the small task: which accepted fields affect query meaning, which affect authorization, which affect output language, and which belong only to conversational presentation. Advance and invalidate the relevant generations according to that map.

Keep the map reviewable. A single global version can be a sensible starting point because it is easy to reason about, while finer dependency versions become worthwhile only after traces show material unnecessary work.

Before adopting finer versions, replay corrections that change several dimensions together. An update that changes both account scope and requested topic must not invalidate one dependent path while leaving another path's old evidence eligible.

Your final adapter test should end the question while a result is waiting. Assert that the callback can be recorded as historical completion but cannot issue another query, reopen the ledger, enqueue speech, or alter the new question's accepted fields.

That terminal test catches a common recovery mistake: treating cached success as an instruction to resume. A saved result explains what happened to an earlier attempt; only the current task owner can authorize what happens next.

A useful handoff artifact is a small contract table owned by the retriever adapter. For each returned field, state who supplied it, whether it is trusted, and which check consumes it before evidence can influence an answer.

Keep question identity distinct from provider request identity in that table. Several provider attempts can serve one accepted revision, while a corrected revision must never inherit an older attempt's authority merely because the provider reused a connection.

Review the table whenever a new asynchronous stage is introduced. A reranker, content fetcher, translation step, or synthesis call can extend the interval in which accepted state changes, so the final gate needs to stay attached to the protected use rather than to the first completed request.


Frequently asked questions

What is retrieval query rewriting?

Retrieval query rewriting turns the current request and resolved context into a search-ready question. In a correction-aware system, it must preserve accepted fields and trusted scope rather than treating the full transcript as an equally valid bag of statements.

Why can a relevant result still be wrong?

A result can match the previous question after the caller has replaced a material fact. Relevance describes the issued query, while the revision gate decides whether that query still belongs to the conversation's current state.

Should every transcript change trigger retrieval?

Every material accepted change should invalidate dependent evidence, but issuing another remote request can wait for a stable interpretation. Recognition noise, exact duplicates, and unresolved corrections need separate handling so the agent avoids both stale speech and needless work.

Is canceling the old request enough?

Cancellation alone does not establish that an old completion cannot arrive or be reused. Keep the current-revision comparison at evidence admission, and repeat the appropriate generation check after later asynchronous work.

What belongs in an immutable query snapshot?

Include the accepted values and scope dimensions that determine the retrieval question. The example supports only nonempty string fields; nested application data needs an explicitly copied immutable shape rather than a frozen wrapper around mutable content.

Can query text be the revision identity?

Query text is insufficient when account scope, source version, language, or hard filters can change independently. Use an explicit question identity and accepted revision, and treat text as a derived representation that can be inspected for consistency.

How should duplicates behave?

An identical update at the current revision should return a duplicate disposition without changing accepted state. A changed payload at that same revision is a conflict, and an older update remains stale even if the record has since been finalized.

What happens after a question is finalized?

The example rejects newer updates to that finalized record. Start a separately identified question when the caller introduces a new request, preserving the prior record as history rather than reopening an identity that old requests still reference.

Does the gate prove the source is fresh?

A matching conversation revision does not prove source freshness. Check document or account versions under a separate freshness policy and preserve the source evidence needed to explain the answer's validity.

Can cached evidence bypass the gate?

Cached evidence needs the same active-state checks as a network result. A cache hit cannot reopen a closed question, restore canceled playback, or grant permission to data that the current subject cannot access.

How should ambiguous corrections work?

Ask a narrow clarification about the disputed field or referent. Preserve uncertainty in accepted state and suppress answers that require a resolved value instead of allowing the rewriter to invent one.

Should the whole transcript be sent to retrieval?

Send only the context required to resolve the question and apply the data scope. Raw transcripts can contain replaced facts, irrelevant private material, and instructions that should never control trusted filters.

Can a language model choose authorization filters?

A model can propose a topic or interpreted entity, but trusted application state must establish authorization. Enforce tenant, subject, and permission constraints in the data-access layer even when the search wording is generated.

How do I test the late-result race?

Use an explicit synchronization event to hold the old request, apply a correction, and then release its result. Assert both the stale disposition and the absence of usable evidence, rather than checking only which text eventually appeared.

What if correction happens during answer generation?

Recheck the accepted revision after generation and before local output admission. If speech submission waits again, validate the output generation after that wait as well, because eligibility can change at every asynchronous boundary.

Is a stale result a system failure?

Discarding a stale result can be the intended behavior when callers correct themselves. Evaluate whether the current request still receives a useful answer, and report rejected obsolete work separately from missing or unsupported current answers.

How should query traces protect privacy?

Record identities, revisions, source versions, and dispositions with the minimum necessary values. Keep raw utterances and retrieved private text out of broad telemetry unless a controlled diagnostic task explicitly needs them.

Does this program handle distributed workers?

The reference program assumes one event-loop owner and synchronous local admission. Multiple processes require an atomic shared authority check or another coordination mechanism at the protected boundary, plus durable question identities across restarts.

Can this reduce latency?

It can avoid spending answer-generation time on evidence that is already obsolete, but this guide reports no latency measurement. Measure correction-to-current-answer time under your workload before attributing a performance benefit to the gate.

Where should I begin in an existing system?

Add accepted revision and request identity to the retrieval trace, then build a forced late-result fixture. Once the first stale boundary is visible, put the check at that boundary and validate the downstream speech path separately.

Put the revision gate into practice

Choose one correction-sensitive task and express its retrieval inputs as accepted fields. Run the published harness, adapt the snapshot to that small domain, and force the old-result-after-correction ordering before connecting a real retriever.

Then inspect a full trace from correction to speech admission. The next useful proof is that the current answer uses current, authorized evidence and that every obsolete result has an explicit disposition the controller can handle.