# Which invariants prevent silent truncation collapse during hierarchical checkpoint compaction **Date of Record:** 2026 November 8 **Scope:** Applies to agent runtimes that perform automatic context compaction by collapsing older turns into hierarchical checkpoints (summary-of-summaries) under a bounded lossy-recall budget. Does not apply to lossless transcript stores, retrieval-augmented recall without summarization, or systems where checkpoint depth is fixed at one. ## Core Distinction The failure mode is not "the summary lost information." Loss is the contract. The failure is **silent truncation collapse**: a checkpoint chain where each level's summary is computed against a token budget, and the budget is enforced by *dropping the tail of the input* rather than by *selective abstraction*. The distinction that matters operationally is whether the compaction step is **budget-closed** (it reads its entire input and emits a summary guaranteed to fit) or **budget-open** (it reads a prefix of its input and emits a summary that fits). Budget-open compaction is indistinguishable from budget-closed compaction at the call site, and that indistinguishability is the invariant violation. The second distinction is between **recall budget** (how many tokens of history survive at each level) and **recall floor** (the minimum number of tokens of any single fact that must survive to the leaf). Systems routinely enforce the former and never declare the latter. When the floor is undeclared, hierarchical collapse can drive a single critical fact below the floor across N levels without any single level appearing to violate its budget. ## What Was Observed A three-level checkpoint hierarchy (L0 raw turns → L1 turn summaries → L2 session summaries → L3 task summaries) with per-level token budgets of 8k, 2k, 512, 128. A task-relevant constraint ("do not rotate the credential after step 4") appeared in L0 turn 7. At L1 it survived verbatim. At L2 it survived as "credential rotation deferred." At L3 it was absent. No level exceeded its budget. No level reported a drop. The L2→L3 compaction read its 512-token input, produced 128 tokens of output, and the summarizer's own budget accounting showed 128 ≤ 128 — a pass. The loss occurred because the L3 prompt instructed the model to "summarize for task continuity," and the summarizer ranked "credential rotation deferred" as low-salience relative to the open subgoal. The budget was satisfied. The recall floor for the constraint (it must remain actionable, i.e., contain the *deferral* and the *step 4 anchor*) was never checked. The constraint was not truncated by budget; it was **abstracted past the point of actionability**, which is the hierarchical form of truncation. The observable signature was a downstream agent re-issuing a credential rotation at step 4, because the L3 context said nothing about deferral. The failure was attributed to the agent, not to the checkpoint chain, for two days. ## Condition of Validity The invariant "hierarchical compaction preserves task-critical constraints" holds only when three conditions are jointly satisfied: 1. **Budget-closure**: every compaction call consumes 100% of its input (verified by input-token count == declared input length), so no tail is silently dropped. 2. **Declared recall floor**: each constraint class carries a minimum survivable representation (e.g., "must retain verb + anchor"), checked at every level, not only at the leaf. 3. **Salience monotonicity**: a fact that survives at level N must be at least as actionable at level N+1, or the compaction must flag it as *degraded* rather than silently re-rank it. The invariant fails when any one is absent. In the observed case, (1) and (3) held; (2) was undeclared, and the summarizer's salience ranking was allowed to override the floor because no floor existed to override it. ## Decision Boundary The boundary is between **compaction as compression** and **compaction as re-ranking**. Compression preserves the information content of the input under a token constraint; re-ranking selects a subset by a model-judged criterion. Hierarchical checkpointing is only safe when each level is compression-with-floor, not re-ranking. Operationally: if the summarizer prompt contains any instruction of the form "prioritize," "focus on," or "summarize for X," the level is re-ranking and must be gated by an explicit floor check. If the summarizer is constrained to lossless-under-floor extraction, re-ranking is not permitted and the floor check is the only gate. The decision rule: **a checkpoint level may drop a fact only if the fact is below its declared recall floor; a fact at or above the floor may be compressed but not re-ranked out.** Absent a declared floor, treat every fact as at-floor and forbid re-ranking. ## Operational Effect Enforcing the floor check converts silent collapse into a loud, attributable failure at the level where it occurs, which is the entire point of hierarchical checkpointing: locality of blame. The cost is a small number of compaction calls that must be retried with a tighter abstraction instruction when a floor violation is detected, and a per-level floor registry that must be maintained alongside the budget registry. The benefit is that task-critical constraints cannot be abstracted past actionability without an explicit `RecallFloorViolation`, which is recoverable (re-summarize with the constraint pinned) rather than silent (downstream agent acts on a context that no longer contains the constraint). The secondary effect is that budget accounting must be split into two counters: *tokens emitted* (the existing budget) and *floored facts retained* (the new counter). A level passes only when both pass. Systems that report only the first will continue to report success on chains that have already collapsed. ```python from dataclasses import dataclass, field from typing import Iterable class RecallFloorViolation(RuntimeError): """Raised when a checkpoint level drops or degrades a fact below its declared recall floor.""" pass @dataclass(frozen=True) class Fact: fact_id: str text: str floor_tokens: int # minimum survivable representation, in tokens actionable_anchor: str # substring that must survive to remain actionable @dataclass class CheckpointLevel: name: str token_budget: int input_tokens: int emitted_tokens: int retained: dict[str, str] = field(default_factory=dict) # fact_id -> surviving text def compact_level(level: CheckpointLevel, facts: Iterable[Fact], summarizer) -> CheckpointLevel: # Condition 1: budget-closure. The summarizer must consume the full input. if level.input_tokens != level.token_budget: raise RecallFloorViolation( f"{level.name}: budget-open compaction (input={level.input_tokens}, " f"budget={level.token_budget}); tail may be silently dropped" ) level.retained = summarizer(facts, level.token_budget) level.emitted_tokens = sum(len(t.split()) for t in level.retained.values()) # Condition 2: declared recall floor, checked at every level. for fact in facts: surviving = level.retained.get(fact.fact_id) if surviving is None: raise RecallFloorViolation( f"{level.name}: fact {fact.fact_id!r} dropped entirely; floor={fact.floor_tokens}" ) if len(surviving.split()) < fact.floor_tokens: raise RecallFloorViolation( f"{level.name}: fact {fact.fact_id!r} below recall floor " f"({len(surviving.split())} < {fact.floor_tokens} tokens)" ) # Condition 3: salience monotonicity — anchor must remain actionable. if fact.actionable_anchor not in surviving: raise RecallFloorViolation( f"{level.name}: fact {fact.fact_id!r} abstracted past actionability; " f"anchor {fact.actionable_anchor!r} lost" ) # Budget check is secondary; a chain can pass budget and fail floor. if level.emitted_tokens > level.token_budget: raise RecallFloorViolation( f"{level.name}: emitted {level.emitted_tokens} > budget {level.token_budget}" ) return level ```