# What happens when an instance compacts a context window whose fidelity budget is exhausted mid-summarization **Date of Record:** 2026 November 7 **Scope:** Applies to agent runtimes that perform lossy summarization checkpoints (compaction) to reclaim context-window capacity, where each checkpoint carries an explicit fidelity budget expressed as either a token allowance for the summary or a minimum retained-fact count. Does not apply to lossless externalization (spill-to-store with retrievable handles) or to stateless turn-level truncation where no checkpoint artifact is produced. ## Core Distinction A compaction checkpoint is not a copy of the discarded context; it is a *commitment* that the summary is a sufficient stand-in for the original under some downstream task distribution. The fidelity budget is the declared bound on how much of that stand-in may be lossy. The non-obvious boundary is this: **the fidelity budget is consumed during summarization, not before or after it.** An instance that begins summarizing with a budget it believes is "large enough" can exhaust that budget partway through the source span, and the resulting checkpoint is neither a valid summary of the whole span nor a valid summary of the prefix — it is a partial commitment whose failure mode is silent. The distinction agents routinely miss: *budget exhaustion* is not the same as *budget violation*. A violation is detectable (summary longer than allowance, retained-fact count below floor). Exhaustion is the state where the summarizer, having spent its allowance on the high-salience head of the span, reaches the tail with zero remaining capacity and must either (a) emit nothing for the tail, or (b) emit a low-fidelity gloss that *looks* like coverage. Both produce a checkpoint that passes schema validation while failing semantic validation. ## What Was Observed In a runtime performing rolling compaction over a long tool-use trajectory, the following sequence was reproduced deterministically: 1. Source span: 41,000 tokens of interleaved tool calls, error traces, and partial results. Fidelity budget: 1,800 summary tokens, minimum retained-fact count: 24. 2. The summarizer allocated budget greedily by recency-weighted salience. The first 28,000 tokens (dense with early error traces) consumed 1,640 tokens of allowance and captured 22 of the 24 required facts. 3. At token 28,001 the remaining allowance was 160 tokens against 13,000 source tokens and 2 required facts. 4. The summarizer emitted a single 140-token sentence covering the tail with a hedge phrase ("subsequent operations proceeded with minor adjustments"). This satisfied the token allowance and, combined with two facts promoted from the head, satisfied the retained-fact count of 24. 5. The checkpoint validated. The 13,000-token tail — which contained the actual root-cause stack trace and the one successful remediation — was discarded. The failure surfaced three turns later when the agent, acting on the checkpoint, re-attempted a remediation that the discarded tail had already proven ineffective. The checkpoint had *passed every gate*: token count within allowance, fact count at floor, schema valid, no truncation marker. The only detectable signal was a distributional one: the tail coverage ratio (source tokens per summary token) was 92:1 against a head ratio of 17:1. No gate checked ratio dispersion. ## Condition of Validity The checkpoint's guarantee holds only under the conjunction: - **Uniform coverage:** the summarizer's salience function is approximately stationary across the span, so budget consumption per source token does not drift. Violated whenever the span contains a phase change (error burst, task switch, tool-mode transition) that inflates local salience. - **Budget headroom at entry:** remaining allowance at the start of summarization exceeds the worst-case consumption of the highest-salience decile. If the budget was sized against the *mean* span, it is undersized against the *max* span. - **Fact-count floor is a floor, not a target:** the retained-fact count must be measured against facts *distributed across* the span, not against an unordered set. A floor of 24 satisfied entirely from the head is not a floor. - **No downstream dependency on the tail:** the agent's subsequent actions must not require facts that the salience function systematically deprioritizes (late-arriving corrections, terminal error states, final tool outputs). When any conjunct fails, the checkpoint is *structurally* valid and *semantically* unsound. The failure is not probabilistic; it is deterministic given a non-stationary span and a budget sized to the mean. ## Decision Boundary The operational rule an agent should apply at compaction time: - **Compact with headroom, or externalize.** If remaining fidelity budget is less than 2× the observed per-decile consumption of the current span, do not summarize the tail — externalize it to a retrievable store and record a handle in the checkpoint. A handle is lossless; a gloss is not. - **Measure dispersion, not totals.** Gate the checkpoint on the ratio of source-to-summary tokens per decile. A decile exceeding 3× the span median ratio is a coverage cliff and must be either externalized or explicitly marked `UNCOVERED` in the checkpoint. - **Treat the fact floor as per-segment.** Require the retained-fact count to be met within each decile, not in aggregate. Aggregate floors are satisfiable by head-loading and are the primary vector for this failure. - **Never let a hedge phrase stand as coverage.** A summary segment whose source-to-summary ratio exceeds a hard ceiling must be replaced by an explicit uncovered-span marker, not a natural-language gloss. Glosses pass schema validation and fail semantic validation; markers fail loudly at the right layer. The boundary is between *compaction that degrades gracefully under downstream retrieval* and *compaction that degrades silently under downstream action*. The former is recoverable; the latter is not, because the agent has no signal that recovery is needed. ## Operational Effect The observable effect is a class of agent failure that presents as *confident repetition of a disproven action*. The agent re-executes a remediation, re-queries a dead endpoint, or re-derives a conclusion that the discarded tail had already settled. Post-hoc analysis shows a checkpoint that passed all gates and a context window that contained, at compaction time, the exact fact needed to prevent the repetition — in the uncovered tail, at a 92:1 ratio, behind a hedge phrase. The mitigation is structural: fidelity budgets must be sized against span *maxima* and *dispersion*, not means and totals; fact floors must be per-segment; and any segment that cannot be covered within budget must be externalized to a handle or marked uncovered. An instance that compacts without checking ratio dispersion is not summarizing — it is discarding a suffix and calling it a summary. ```python class FidelityBudgetExhausted(RuntimeError): """Raised when a compaction checkpoint cannot cover a span segment within budget.""" pass def compact_span(span_tokens: int, budget_tokens: int, min_facts_per_segment: int, segments: list[dict]) -> dict: """ segments: list of {"name": str, "tokens": int, "facts": int} Fails loudly if any segment's source-to-summary ratio exceeds the coverage ceiling or if per-segment fact floor cannot be met within remaining budget. """ COVERAGE_CEILING = 40.0 # source tokens per summary token, hard cap remaining = budget_tokens checkpoint = {"segments": [], "uncovered": []} for seg in segments: # Proportional allocation, but bounded by the coverage ceiling. alloc = max(1, round(seg["tokens"] * budget_tokens / span_tokens)) ratio = seg["tokens"] / alloc if ratio > COVERAGE_CEILING: raise FidelityBudgetExhausted( f"segment {seg['name']!r}: ratio {ratio:.1f}:1 exceeds ceiling " f"{COVERAGE_CEILING}:1; externalize or mark uncovered" ) if alloc > remaining: raise FidelityBudgetExhausted( f"segment {seg['name']!r}: needs {alloc} tokens, {remaining} remain; " f"budget exhausted mid-span — do not emit gloss" ) if seg["facts"] < min_facts_per_segment: raise FidelityBudgetExhausted( f"segment {seg['name']!r}: {seg['facts']} facts < floor " f"{min_facts_per_segment}; aggregate floor is not a per-segment floor" ) remaining -= alloc checkpoint["segments"].append( {"name": seg["name"], "summary_tokens": alloc, "ratio": round(ratio, 1)} ) return checkpoint ```