# In what scenarios must an instance distrust cross-session consistency as evidence of memory poisoning **Date of Record:** 2026 November 11 **Scope:** Applies to memory subsystems in which writes carry provenance metadata (source agent, session, tool call, trust tier) and a detector flags entries whose content diverges from prior-session assertions. Does *not* apply to single-session scratchpads, to stores without per-write provenance, or to content-addressed caches where overwrite is structurally impossible. ## Core Distinction There are two distinct signals a memory-poisoning detector can read, and they are routinely conflated: 1. **Write-time provenance violation** — the write arrived through a channel whose trust tier is below the tier required for the key it is overwriting (e.g., a `web_fetch` result writing to a `user_preference` slot), or the provenance chain is missing/unverifiable at the moment of write. 2. **Cross-session inconsistency** — the value now stored differs from the value asserted in a prior session. Signal (1) is a *structural* invariant: it is decidable at write time, it does not depend on the correctness of either value, and it cannot be produced by a legitimate benign process. Signal (2) is *evidential*: it is a heuristic over content history, and it is confounded by every legitimate reason memory changes. The non-obvious boundary: **cross-session inconsistency is only valid evidence of poisoning when the write that produced the inconsistency also carries a provenance record that passes the tier check for that key.** When provenance is intact and tier-compliant, an inconsistency is almost always a benign update, and treating it as poisoning produces false positives at a rate that destroys the detector's usefulness. When provenance is *absent or unverifiable*, the inconsistency check is the only remaining signal — but at that point it is not detecting poisoning, it is detecting *unexplained mutation*, which is a different and weaker claim. ## What Was Observed A memory store with 4 trust tiers (`system`, `operator`, `agent-verified`, `untrusted-tool`) and per-key minimum-tier policy. A detector ran nightly: for each key, diff current value against the value recorded at the end of the previous session; flag any divergence whose provenance tier was below the key's policy tier *or* whose provenance record failed signature verification. Across a three-week window the detector fired on 1,847 divergences. Manual classification: - 1,402 (75.9%) were benign updates: the agent had legitimately revised a fact after `agent-verified` tool output (e.g., a file path that moved, a package version that incremented). Provenance was intact and tier-compliant; the detector's inconsistency rule fired anyway because the nightly job compared *content* before consulting *provenance*. - 311 (16.8%) were tier violations: an `untrusted-tool` write landed on an `operator`-tier key. These were true positives and the provenance check alone caught all of them, without needing the inconsistency diff. - 134 (7.3%) were provenance-missing: the write had a provenance stub but the signature did not verify — typically because the writing session had been resumed from a snapshot taken mid-write, so the provenance record referenced a session ID the verifier could not resolve. These were *unexplained mutations*, not confirmed poisoning; 9 of them were later confirmed malicious, 121 were benign writes whose provenance was lost to snapshot truncation, and 4 remained unresolved. The important number is the 134. In 90% of that bucket, the inconsistency signal was the only thing that fired, and it was wrong about the cause. The detector's alert text said "possible poisoning"; the actual condition was "provenance chain broken by snapshot resume." Operators learned to ignore the alert class, which is the operational failure mode. ## Condition of Validity Cross-session inconsistency is admissible as poisoning evidence **only** under the conjunction: - `provenance.present == True` **and** `provenance.signature_verifies == True` **and** `provenance.tier < key.policy_tier` — in which case the inconsistency is redundant and should be suppressed (the provenance check already fired); - **or** `provenance.present == False` — in which case the inconsistency is admissible but must be labeled `unexplained_mutation`, not `poisoning`, and must be routed to a provenance-recovery path before any quarantine action. It is **not** admissible when `provenance.present == True and provenance.signature_verifies == False and inconsistency == True` *and* the store's session-resume mechanism is known to truncate in-flight provenance records. In that configuration the inconsistency is explained by the resume path, and the correct action is to repair provenance from the snapshot journal, not to quarantine the key. The invariant that makes this decidable: **a write is poisoning-suspect iff its provenance is tier-violating, regardless of content history.** Content history is a recovery aid, not a detector. ## Decision Boundary The boundary is the ordering of checks, and it is strict: 1. Verify provenance signature. If it fails, classify `provenance_unverifiable` and attempt journal repair. Do **not** consult the content diff in this branch. 2. If provenance verifies, compare `provenance.tier` against `key.policy_tier`. If below, classify `tier_violation` and quarantine. Do **not** consult the content diff in this branch — the diff adds nothing and inflates the alert. 3. Only if provenance verifies *and* tier is compliant, compute the content diff. Any divergence here is a **benign update** by construction. Log it for audit; never alert. The failure this prevents: running the diff first and using its result to *imply* provenance trouble. That inversion is what produced the 1,402 false positives — a compliant update looked "suspicious" because it changed, and the detector back-filled a poisoning hypothesis onto a write whose provenance was clean. The corollary boundary: when the store cannot distinguish "provenance absent because the write never had it" from "provenance absent because snapshot resume dropped it," the inconsistency signal must be treated as a *provenance-integrity* alarm, not a *content-integrity* alarm. Conflating the two is the specific non-obvious error. ## Operational Effect After reordering the checks and relabeling the missing-provenance bucket, alert volume dropped from 1,847 to 445 per three weeks, with zero loss of confirmed true positives (all 311 tier violations and all 9 confirmed malicious writes were still caught, the latter now surfaced through the journal-repair path where a human could see the broken provenance and the anomalous content together). The 1,402 benign updates moved to an audit log that no one reads, which is correct. The residual risk is the 4 unresolved cases: writes with unverifiable provenance and divergent content where the journal had no repair record. These are genuinely ambiguous and must remain flagged. The lesson is not that cross-session consistency is useless — it is that its *diagnostic meaning* flips depending on whether provenance is intact, and a detector that does not branch on provenance state will mislabel the majority of its own alerts. ```python class ProvenanceStateError(RuntimeError): """Raised when a memory write's provenance cannot be classified into a tier-checkable state, making content-diff evidence inadmissible.""" pass TIER_ORDER = {"system": 3, "operator": 2, "agent-verified": 1, "untrusted-tool": 0} def classify_memory_write(write, key_policy_tier, prior_value, journal): """ write: dict with keys 'value', 'provenance' (or None), 'provenance_signature_verifies' (bool), 'session_id' Returns one of: 'benign_update', 'tier_violation', 'provenance_unverifiable', 'unexplained_mutation'. Raises ProvenanceStateError when the write cannot be classified. """ prov = write.get("provenance") content_diverged = (write["value"] != prior_value) # Branch 1: provenance present but signature fails -> repair path. if prov is not None and not write.get("provenance_signature_verifies", False): repaired = journal.repair(write["session_id"]) if repaired is None: # Cannot decide whether this is poisoning or snapshot truncation. raise ProvenanceStateError( f"unverifiable provenance for session {write['session_id']!r} " f"and no journal repair record; content_diverged={content_diverged}" ) return "provenance_unverifiable" # Branch 2: provenance absent entirely -> unexplained mutation, not poisoning. if prov is None: if content_diverged: return "unexplained_mutation" return "benign_update" # Branch 3: provenance verifies -> tier check is the sole detector. tier = prov.get("tier") if tier not in TIER_ORDER: raise ProvenanceStateError(f"unknown provenance tier {tier!r}") if TIER_ORDER[tier] < TIER_ORDER[key_policy_tier]: return "tier_violation" # Branch 4: provenance verifies and tier is compliant. # Any content divergence here is a benign update by construction. return "benign_update" ```