# Why does an instance memory-poisoning detector silently stop detecting after a store compaction: the attestation-window invariant **Date of Record:** 2026 November 10 **Scope:** Applies to persistent agent stores that detect memory poisoning by comparing candidate writes against an attested baseline snapshot (Merkle root, hash-chain head, or signed manifest) and that perform periodic compaction, GC, or segment rewriting. Does not apply to append-only stores with no rewriting, nor to detectors that re-attest from live content on every read. ## Core Distinction There are two different things a memory-poisoning detector can compare a candidate write against: 1. **Content attestation** — a signature or Merkle root over the *current bytes* of the store. This proves the bytes have not changed since signing, but says nothing about whether the bytes were *correct* when signed. 2. **Provenance attestation** — a chain of records asserting *who wrote what, under which policy, at which epoch*, anchored to an external root of trust. A detector that conflates these will pass every integrity check after a compaction while silently accepting poisoned content, because compaction rewrites bytes and re-signs them — producing a fresh, internally consistent, cryptographically valid attestation over data that was already compromised. The failure is not a broken hash; it is a *valid* hash over the wrong referent. The non-obvious invariant: **the attestation baseline must be monotonic in epoch and anchored outside the writer's control; any operation that can regenerate the baseline from store content destroys the detector's discriminating power.** ## What Was Observed On a long-running agent store (segmented LSM-style, ~40 GB, 90-day retention), a poisoning detector flagged injected writes reliably for the first ~30 days. After the first scheduled compaction at day 31, detection rate fell to zero for the affected segments while all health metrics — signature verification, Merkle root match, chain continuity — reported green. The mechanism: compaction merged poisoned and clean records into new segments, recomputed per-segment Merkle roots, and re-signed the manifest with the store's own signing key. The detector's baseline was defined as "the signed manifest at last compaction." After compaction, the baseline *contained* the poison. Candidate writes were compared against a baseline that had already absorbed the attack, so every subsequent comparison was self-consistent. The detector had, in effect, been asked to detect a forgery by comparing the forgery to a copy of itself. Secondary observation: because the manifest signing key lived in the same trust domain as the compaction worker, a compromised or misconfigured compaction path could produce a validly signed poisoned baseline with no anomaly in any downstream check. The detector's failure mode was *indistinguishable from success* at the observability layer. ## Condition of Validity The detector remains sound only while all of the following hold: - The attested baseline is **never regenerated from store content** after initial provisioning; it is advanced only by appending *provenance events* (writer identity, policy epoch, prior head) signed by a key the store's writer path cannot reach. - Every compaction/GC/rewrite emits a **rewrite event** that maps old segment hashes to new segment hashes and is itself appended to the provenance chain *before* the new manifest is trusted. - The detector compares candidate writes against the **provenance chain head**, not the manifest root, and rejects any manifest whose provenance chain does not contain a rewrite event covering every segment it claims. - The signing key for provenance events is held outside the compaction worker's trust boundary (HSM, separate service account, or offline signer). If any condition is violated — most commonly the first, via "re-sign after compaction for convenience" — the detector is operationally dead even though it is mechanically running. ## Decision Boundary Use content attestation alone only when the store is append-only and the baseline is provisioned once from a known-good export and never rewritten. The moment a rewrite, GC, or segment merge is introduced, you are in provenance-attestation territory and must pay the cost of an external signer and a rewrite-event log. The boundary is not "does compaction exist" but "**can any code path that touches store bytes also advance the baseline?**" If yes, the detector is decorative. The decision to add compaction is therefore a decision to either (a) add an out-of-band provenance signer, or (b) accept that poisoning detection is best-effort and must be paired with an independent, append-only audit log that compaction cannot touch. A useful operational test: after every compaction, attempt to inject a known-bad record and confirm the detector still flags it. If the injection is accepted, the baseline was regenerated from content and the invariant is broken. ## Operational Effect Teams that miss this boundary typically discover it during incident response, not before: the poisoning is found by an external anomaly (agent behavior drift), and the detector's green dashboards are then revealed to have been meaningless for weeks. Remediation requires reconstructing provenance from an independent log — often unavailable — and re-provisioning the baseline from a trusted export, which may not exist for the affected window. The durable fix is architectural: separate the signer from the writer, make rewrite events first-class and append-only, and treat "baseline advanced without a provenance event" as a hard alert rather than a routine maintenance step. ```python class AttestationWindowViolation(RuntimeError): """Raised when a baseline advance is not backed by an append-only provenance event.""" pass class ProvenanceChain: def __init__(self, external_root: bytes): # external_root is provisioned once, signed outside the store writer's trust domain self._head = external_root self._events = [] @property def head(self) -> bytes: return self._head def append_rewrite_event(self, old_segments: dict, new_segments: dict, signer) -> bytes: if not signer.is_external(): raise AttestationWindowViolation( "rewrite event signed by in-domain key; baseline would be self-attesting" ) event = { "type": "rewrite", "old": old_segments, "new": new_segments, "prev": self._head, } self._events.append(event) self._head = signer.sign(event, prev=self._head) return self._head def advance_baseline(chain: ProvenanceChain, new_manifest_root: bytes, signer) -> bytes: """Advance the attested baseline. Refuses any advance not covered by a rewrite event.""" covered = any( e["type"] == "rewrite" and e["new"].get("manifest") == new_manifest_root for e in chain._events ) if not covered: raise AttestationWindowViolation( f"baseline advance to {new_manifest_root.hex()[:12]} has no covering rewrite event; " "compaction likely regenerated the baseline from store content" ) return chain.head def detect_poison(candidate: bytes, chain: ProvenanceChain, expected_root: bytes) -> bool: if chain.head != expected_root: raise AttestationWindowViolation( "provenance head diverged from externally held root; detector is unsound" ) return candidate not in chain._events # placeholder for real membership check ```