# Why does an instance lose semantic continuity across a compaction boundary even when every checkpoint verifies as structurally valid **Date of Record:** 2026 November 14 **Scope:** Applies to long-running agent instances that compact working context into a lossy checkpoint and later reconstruct via retrieval-augmented replay. Does not apply to append-only, lossless journals where every token is recoverable by reference. ## Core Distinction The distinction that matters is between *structural validity* of a checkpoint and *semantic recoverability* of the state it represents. A compaction policy typically validates the checkpoint by schema: required fields present, token count under budget, embedding index rebuilt, references resolvable. All of these can pass while the checkpoint has silently discarded the one invariant that made the pre-compaction state coherent — usually a *negative* fact (what was ruled out, what was tried and failed, what must not be re-attempted) or a *relational* fact (which of two similarly named entities is the one under discussion). Lossy checkpointing is fundamentally a max-information-per-token problem, and summarizers optimize for salience. Salience is measured against the *current* task frame. The boundary failure occurs because the compaction policy and the reconstruction policy use different salience functions: the compactor prunes what looks irrelevant *now*, and the retriever selects what looks relevant *to the query at reconstruction time*. Neither one preserves the facts whose relevance only becomes apparent after a later step contradicts them. ## What Was Observed Across a class of agent runs performing multi-step infrastructure remediation, the following pattern recurred with high regularity: 1. During step N, the instance attempted an action (e.g., a config rollback) that failed for a specific reason, and recorded that reason in working context. 2. At the compaction boundary, the summarizer collapsed the failed attempt into a single line: "attempted rollback; unsuccessful." The *reason* — the constraint that made it fail — was dropped because the summarizer judged the failure itself to be the salient fact. 3. At step N+K, the instance re-derived the same action from first principles, because retrieval surfaced the "attempted rollback" line without the disqualifying constraint, and the retriever ranked it as *relevant prior context* rather than *prohibited prior context*. 4. The instance repeated the failed action, and — critically — did not recognize it as a repetition, because the checkpoint had no representation of "this was already tried." The observable signature is a loop with a period equal to the compaction interval, not the reasoning interval. The instance is not confused; it is *amnesiac about its own exclusions*. Every individual step is locally valid. The failure is only visible in the trajectory. A second, subtler observation: checkpoints that passed validation at compaction time began to fail *retrieval* after two or three further compactions, because each generation re-summarized the prior summary. Negative facts decay faster than positive facts under iterated summarization, because a summary of a summary has no way to mark "absence of X" as load-bearing. The information loss is not linear; it compounds across generations, and the compounding is invisible to any single-generation validator. ## Condition of Validity The reconstruction is only semantically faithful when the following holds: *every fact required to disqualify a future action is represented in the checkpoint as an explicit, retrievable, first-class record — not as an inference from a summarized narrative.* In practice this means the compaction policy must maintain a separate, append-only *prohibition ledger* alongside the lossy summary, and the retrieval policy must query that ledger with the same priority as the positive context. The condition fails whenever: - The compaction policy treats the checkpoint as a *narrative* rather than a *state machine with invariants*. - The retrieval policy scores candidates by similarity to the current query, which systematically under-ranks prohibitions (a prohibition is relevant precisely when the query does *not* mention it). - Summarization is iterated without a generation counter or a rule that prohibits re-summarizing prohibition records. ## Decision Boundary The decision boundary is whether the next action is *novel* or *previously excluded*. If novel, the lossy summary is sufficient and cheap. If previously excluded, the summary is actively dangerous, because it presents the exclusion's *subject* without its *predicate*. Operationally: before executing any action that has a plausible prior attempt in the reconstructed context, the instance must query the prohibition ledger directly and treat a hit as a hard block, not a soft signal. If the ledger is absent or was compacted away, the instance must treat the absence as *unknown*, not as *permitted* — and must escalate rather than re-derive. The boundary is crossed the moment "I don't see a record of trying this" is interpreted as "I haven't tried this." ## Operational Effect The effect is a class of silent, periodic regressions that survive every structural check and appear in logs as legitimate reasoning. They inflate token spend, can re-trigger destructive operations that were previously rolled back for cause, and — most damagingly — erode the instance's own trust model, because each repetition is internally consistent. Mitigation requires three changes: a prohibition ledger that is never lossily compacted, a retrieval path that queries it independently of similarity, and a generation counter on checkpoints so that compounding decay is detectable. The ledger is cheap; the failure it prevents is not. ```python from dataclasses import dataclass, field from typing import Optional class CompactionContinuityError(RuntimeError): """Raised when a reconstructed checkpoint cannot prove an action was not previously excluded.""" pass @dataclass class ProhibitionLedger: _entries: dict = field(default_factory=dict) def record(self, action_key: str, reason: str) -> None: self._entries[action_key] = reason def lookup(self, action_key: str) -> Optional[str]: return self._entries.get(action_key) @dataclass class Checkpoint: summary: str generation: int ledger: Optional[ProhibitionLedger] def guard_action(checkpoint: Checkpoint, action_key: str) -> None: if checkpoint.ledger is None: # Absence of a ledger is unknown, not permission. raise CompactionContinuityError( f"checkpoint gen={checkpoint.generation} has no prohibition ledger; " f"cannot prove {action_key!r} was not previously excluded" ) prior = checkpoint.ledger.lookup(action_key) if prior is not None: raise CompactionContinuityError( f"action {action_key!r} was previously excluded at gen={checkpoint.generation}: {prior}" ) ```