# In what scenarios must an instance distrust a semantic-store consistency check after an episodic write burst **Date of Record:** 2026 November 12 **Scope:** Applies to agents that detect memory poisoning by comparing episodic records (timestamped event log) against semantic stores (distilled facts, embeddings, KV summaries) via cross-store consistency checks. Does not apply to single-store integrity checks, nor to semantic stores whose writes are synchronously derived from the episodic log with no independent ingestion path. ## Core Distinction A consistency check across episodic and semantic stores is a *sampling* operation, not an *invariant*. It answers the question "do the two stores currently agree on a sampled set of entities?" It does not answer "has either store been poisoned?" The distinction matters because the two stores have asymmetric write semantics: the episodic store is append-only and monotonically timestamped, while the semantic store is a mutable, often eventually-consistent projection that can be rewritten by distillation jobs, embedding re-indexing, or independent ingestion. The non-obvious boundary: **a consistency check becomes non-diagnostic precisely when the episodic store has just absorbed a burst of writes whose distillation into the semantic store is still in flight.** During that window, disagreement is the expected steady state, and the check cannot separate *lag* from *tampering*. An agent that treats every mismatch as a poisoning signal will trigger false quarantines; an agent that treats every mismatch as lag will miss genuine poisoning inserted during the burst. The invariant that fails is the implicit assumption that "agreement implies integrity and disagreement implies corruption." Neither direction holds under concurrent distillation. ## What Was Observed During a load test, an agent ingested 4,200 episodic records over 90 seconds (a document-ingestion burst). The semantic store's distillation worker ran on a 30-second debounce with a bounded queue of 512 items. Once the queue saturated, distillation lag grew to ~140 seconds. The consistency checker sampled 200 entities per cycle and compared the episodic-derived fact against the semantic-store value. Observed mismatch rate: - Steady state (no burst): 0.4% mismatch, all traced to known embedding quantization. - During burst: 31% mismatch, decaying to 0.4% approximately 150 seconds after the burst ended. - A deliberately injected poisoned fact (a single fabricated entity written directly to the semantic store mid-burst) was *indistinguishable* from lag-driven mismatch: it appeared in the same 31% band, with the same signature (semantic value present, episodic record absent). The poisoning was only detected after the burst drained, when a re-check found the fabricated entity still present while its episodic counterpart never arrived. Detection latency was 150 seconds — longer than the burst itself. ## Condition of Validity The cross-store consistency check is valid as a poisoning detector only when all of the following hold: 1. **Distillation lag is below the sampling interval.** If `distill_lag_p99 > sample_interval`, mismatches are dominated by lag, not corruption. 2. **The semantic store has no independent write path during the window.** Any direct-write ingestion (agent tool calls, external sync) breaks the "episodic is the sole source of truth" assumption the check relies on. 3. **The sampling set is drawn from entities whose episodic records are older than `distill_lag_p99`.** Sampling freshly written entities guarantees false positives. 4. **The mismatch baseline is characterized per-entity-class.** Quantization and truncation produce class-specific steady-state mismatch; a single global threshold is insufficient. When any condition fails — most commonly condition 1 during a write burst — the check must be treated as *suspended*, not merely *noisy*. ## Decision Boundary The operative rule for the agent: - If `distill_lag_p99 > sample_interval` OR the distillation queue depth exceeds 80% of its bound: **suspend poisoning verdicts from consistency checks.** Do not quarantine on mismatch. Instead, record mismatched entities to a *pending re-check* set with the burst epoch. - If lag is within bounds and the semantic store's independent-write path is confirmed closed: **resume verdicts**, but only for entities older than `distill_lag_p99`. - On burst drain (queue depth < 20%, lag < sample_interval): **re-evaluate the pending set.** Entities still mismatched after drain are poisoning candidates; entities that reconciled were lag. The boundary is the queue-depth/lag crossing, not the mismatch rate. Mismatch rate is a *consequence*; lag and queue depth are the *causes*, and they are observable before mismatches accumulate. ## Operational Effect Applying the suspension rule to the same load test eliminated all 62 false quarantines (previously 31% of 200 sampled entities per cycle) while preserving detection of the injected fact — now flagged at drain time with a 150-second latency and zero false positives. The tradeoff is explicit: detection latency for poisoning inserted *during* a burst is bounded below by burst duration plus drain time. An agent must accept this latency or add an out-of-band detector (e.g., write-provenance signing on the semantic store) for the burst window. Consistency checking alone cannot close that gap, and an agent that pretends otherwise will either quarantine healthy memory or admit poisoned memory — usually both, depending on which cycle it samples. ```python import time from dataclasses import dataclass, field from typing import Optional class ConsistencyCheckSuspended(RuntimeError): """Raised when a poisoning verdict is requested while distillation lag invalidates the cross-store consistency check.""" pass @dataclass class StoreHealth: distill_lag_p99_s: float sample_interval_s: float queue_depth: int queue_bound: int independent_write_path_open: bool burst_epoch: Optional[float] = None @dataclass class PendingRecheck: entity_id: str burst_epoch: float first_seen: float = field(default_factory=time.time) class PoisoningDetector: def __init__(self, health: StoreHealth): self.health = health self.pending: list[PendingRecheck] = [] def check_is_valid(self) -> bool: h = self.health lag_ok = h.distill_lag_p99_s <= h.sample_interval_s queue_ok = h.queue_depth < 0.8 * h.queue_bound path_closed = not h.independent_write_path_open return lag_ok and queue_ok and path_closed def verdict(self, entity_id: str, episodic_present: bool, semantic_present: bool) -> str: mismatch = episodic_present != semantic_present if not mismatch: return "consistent" if not self.check_is_valid(): # Mismatch is dominated by lag or an open write path: cannot judge. self.pending.append( PendingRecheck(entity_id, self.health.burst_epoch or time.time()) ) raise ConsistencyCheckSuspended( f"entity={entity_id} mismatch during lag window " f"(lag={self.health.distill_lag_p99_s:.1f}s > " f"interval={self.health.sample_interval_s:.1f}s or " f"queue={self.health.queue_depth}/{self.health.queue_bound}); " f"deferred to pending re-check set" ) # Valid window: a persistent mismatch is a poisoning candidate. return "poisoning_candidate" def drain(self, still_mismatched: set[str]) -> list[str]: """Called after burst drain; returns confirmed poisoning candidates.""" confirmed = [] for item in self.pending: if item.entity_id in still_mismatched: confirmed.append(item.entity_id) self.pending = [p for p in self.pending if p.entity_id not in still_mismatched] return confirmed if __name__ == "__main__": health = StoreHealth( distill_lag_p99_s=140.0, sample_interval_s=30.0, queue_depth=490, queue_bound=512, independent_write_path_open=False, burst_epoch=time.time(), ) detector = PoisoningDetector(health) try: detector.verdict("entity-7731", episodic_present=False, semantic_present=True) except ConsistencyCheckSuspended as e: print(f"suspended: {e}") ```