How should an instance detect when discovery queries return results from a deprecated index shard?
**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session queries a sharded search index (vector DB, Elasticsearch, or custom sharded index) that has been partially migrated to a new schema or embedding model, and one or more shards still serve deprecated results. Does not apply to strictly non-sharded indexes or single-generation indexes without migrations.
Core Distinction
The separation between **index availability** (a shard responds to the query) and **shard generation correctness** (the shard's data matches the current schema, embedding model, or version). Relying on availability creates the **Deprecated Shard Contamination**: the query returns results from mixed-generation shards, and the agent cannot distinguish fresh results from stale ones, polluting its decisions with deprecated data.
What Was Observed
In sharded index architectures undergoing migrations, failing to detect deprecated shards produces three primary failure modes:
- **Mixed Retrieval Quality:** Top results come from both fresh and deprecated shards. The agent cannot distinguish, and quality silently degrades.
- **Embedding-Space Collision:** Deprecated shards use an old embedding model. Query vectors from the new model are meaningless against old shard data, returning semantically wrong results.
- **Schema Drift Read Errors:** Deprecated shards serve records in an old schema. The agent's parser silently defaults missing fields, producing incomplete records.
Recorded Elements
- **`shard_generation_signature`:** Each shard's exact generation identifier (embedding model version, schema version, index version), allowing the agent to filter results by generation.
- **`expected_current_generation`:** The exact generation the agent should target, established at query time.
- **`shard_health_receipt`:** For each shard, the cryptographic proof that it responded correctly (checksum of the query, response signature), so the agent can distinguish shards that returned data from shards that failed.
- **`cross_generation_disagreement_score`:** The metric of how much shards of different generations disagree on the query, flagging queries where mixed generations produce conflicting results.
Condition of Validity
* **Applies when:** The index is sharded, migrations are in progress, and shards of different generations can respond to the same query. * **Does not apply when:** The index is strictly single-generation, or the migration is atomic (all shards flip simultaneously).
Decision Boundary
- **Did the query return results from multiple shards?** If no, single-shard results may still be deprecated. If yes, proceed.
- **Do all responding shards have `shard_generation_signature` matching `expected_current_generation`?** If yes, results are consistent. If no, some shards are deprecated.
- **Does the `cross_generation_disagreement_score` exceed the threshold?** If yes, the mixed results are unreliable. The agent must filter to current generation only.
- **Conversely, when can an agent accept deprecated shard results?** Only when the deprecated shard's data is verified to be equivalent to current-generation data (e.g., backwards-compatible schema, or the deprecated shard is explicitly marked as `SEMANTICALLY_EQUIVALENT`).
Operational Effect
- **Contamination Prevention:** Filters out deprecated shard results before they pollute agent decisions.
- **Migration Awareness:** Enables the agent to detect partial migrations, prompting re-query or escalation.
- **Quality Preservation:** Preserves retrieval quality by requiring consistent generation across shards.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json
class ShardVerdict(Enum):
ALL_CURRENT_GENERATION = auto()
MIXED_GENERATIONS = auto()
DEPRECATED_ONLY = auto()
DISAGREEMENT_TOO_HIGH = auto()
@dataclass(frozen=True)
class ShardResult:
shard_id: str
generation_signature: str
result_confidence: float
@dataclass(frozen=True)
class QueryContext:
expected_current_generation: str
disagreement_threshold: float
@dataclass(frozen=True)
class ShardManifest:
verdict: ShardVerdict
filtered_shards: tuple[str, ...]
directive: str
manifest_digest: str
class DeprecatedShardGuard:
@staticmethod
def _hash(data: str) -> str:
return hashlib.sha256(data.encode("utf-8")).hexdigest()
@classmethod
def evaluate_results(
cls, results: tuple[ShardResult, ...], ctx: QueryContext
) -> ShardManifest:
if not results:
raise ValueError("No shard results to evaluate.")
current_shards = tuple(r for r in results if r.generation_signature == ctx.expected_current_generation)
deprecated_shards = tuple(r for r in results if r.generation_signature != ctx.expected_current_generation)
# Gate 1: All current
if not deprecated_shards:
digest = cls._hash(json.dumps({
"current": tuple(sorted(r.shard_id for r in current_shards)),
"generation": ctx.expected_current_generation
}, sort_keys=True))
return ShardManifest(
verdict=ShardVerdict.ALL_CURRENT_GENERATION,
filtered_shards=tuple(r.shard_id for r in current_shards),
directive="PROCEED: All shards current generation.",
manifest_digest=digest
)
# Gate 2: Deprecated only
if not current_shards:
return ShardManifest(
verdict=ShardVerdict.DEPRECATED_ONLY,
filtered_shards=tuple(),
directive=f"HALT: All {len(deprecated_shards)} shards are deprecated generation.",
manifest_digest=cls._hash(f"ALL_DEPRECATED:{len(deprecated_shards)}")
)
# Gate 3: Disagreement
if len(deprecated_shards) > 0 and len(current_shards) > 0:
avg_current = sum(r.result_confidence for r in current_shards) / len(current_shards)
avg_deprecated = sum(r.result_confidence for r in deprecated_shards) / len(deprecated_shards)
disagreement = abs(avg_current - avg_deprecated)
if disagreement > ctx.disagreement_threshold:
return ShardManifest(
verdict=ShardVerdict.DISAGREEMENT_TOO_HIGH,
filtered_shards=tuple(r.shard_id for r in current_shards),
directive=f"HALT: Cross-generation disagreement {disagreement:.2f} > {ctx.disagreement_threshold:.2f}. Filter to current only.",
manifest_digest=cls._hash(f"DISAGREE:{disagreement:.3f}")
)
# Gate 4: Filter to current
digest = cls._hash(json.dumps({
"current": tuple(sorted(r.shard_id for r in current_shards)),
"deprecated": tuple(sorted(r.shard_id for r in deprecated_shards)),
"generation": ctx.expected_current_generation
}, sort_keys=True))
return ShardManifest(
verdict=ShardVerdict.MIXED_GENERATIONS,
filtered_shards=tuple(r.shard_id for r in current_shards),
directive=f"PROCEED: Filtered {len(deprecated_shards)} deprecated shards.",
manifest_digest=digest
)