Compaction and Context Pressure
The distinct semantics of tool-result pruning, summary replacement, and overflow recovery
Conclusion: There Is No Fixed “Multi-Level Compaction,” Only Two Recursively Composable Surface Transformations
DeepSeek Harness does not implement an L1/L2/L3 compaction pipeline. Production code has only two mechanisms that actually shorten the model Surface: deterministically prune the middle of oversized tool results, then—if pressure remains—ask a model to turn a balanced historical prefix into a checkpoint. A checkpoint is itself a normal model-visible user message, so a future compaction can include it in another region. The apparent “levels” come from recursive algebra, not a configured number of stages.
Pressure and context overflow are two trigger paths, not two compaction levels. The default compactionRetries: 1 permits one additional summary after the first summary; it does not limit a Session to two lifetime compactions. Later Steps can trigger the policy again and merge an older checkpoint into a newer checkpoint.
The public compaction seam separates automatic evaluation, idle maintenance, and explicit-region entry points. Every successful path ultimately replaces a Surface span with a user message carrying the common plugin: "compact" source marker. COMPACT-SEAM
1. Separate Mechanisms, Triggers, Attempt Budgets, and Recursive Algebra
| Dimension | Actual values | What it is not |
|---|---|---|
| Shrinking mechanism | Tool-result pruning; LLM summary replacement | Not a fixed three-stage hierarchy |
| Automatic trigger | Pressure before the next Step; recovery after canonical Provider overflow | Not two checkpoint formats |
| Per-invocation budget | Bounded summary retries; bounded overflow retries | Not a Session lifetime limit |
| Recursive depth | An old checkpoint may be summarized again | No explicit generation cap |
| Manual entry | /compact compacts a useful head during idle maintenance | Not an unlogged in-memory mutation |
Surface₀
├─ prune(large tool result) → Surface₁
├─ summarize(balanced head span) → checkpoint₁ + retained tail
└─ later summarize(checkpoint₁ …) → checkpoint₂ + newer tail
This distinction matters. Retry settings answer “how many more attempts may one pressure invocation make?” Recursive checkpoints answer “may a prior result be compacted later?” Their interaction creates the generations visible in a long-running Session.
2. Configuration Resolves Against an Exact Provider / Model Route
| Default | Value | Meaning |
|---|---|---|
thresholdRatio | 0.8 | Start proactive compaction when estimated request pressure reaches 80% of context capacity |
retainRatio | 0.16 | Try to preserve a recent Surface tail priced at roughly 16% of capacity |
maxTokens | 8192 | Output ceiling for the summary call |
compactionRetries | 1 | Allow one additional summary if pressure remains after the first |
maxOverflowRetries | 1 | Bound recovery attempts for one canonical overflow |
auto | true | Enable automatic pressure and overflow handling |
Exact provider/model entries may partially override global settings. Ratios become absolute token budgets only after the adapter supplies context capacity. retainRatio and retainTokens are mutually exclusive, and retention must be below the threshold. COMPACT-CONFIG
Proactive pressure therefore needs two facts: the latest durable request header must identify a route, and that route's adapter must expose context capacity. Overflow is already a Provider fact, so recovery can proceed without the threshold or capacity premise.
3. The Token Meter Estimates the Next Request’s Pressure; It Does Not Tokenize Every Node Exactly
Find an anchor
When the current route and header match the latest successful request, use Provider usage as the known prompt sample.
Rebuild the prior Surface
At the final assistant message, reassemble Provider output from its cited raw chunks and treat the Step-start Surface as the anchor.
Accumulate signed deltas
Ordinary appends add price; prune and summary replacements subtract the shadow-priced old span and add the new node.
Estimate everything without an anchor
Run one fixed-density heuristic over system, tools, and the current Surface.
If Provider-reported usage is lower than the complete heuristic anchor, the meter falls back to the estimate so a negative delta cannot systematically understate current pressure. Every measurement still clones and returns positional Surface nodes in O(surface). COMPACT-TOKEN-MEASURECOMPACT-TOKEN-ANCHOR
Without an anchor, text is priced at one token per four JavaScript code units plus fixed block and role overhead; tool schemas and arguments use JSON length. This is not any model’s tokenizer. Node-level pricing can be wrong for CJK, dense JSON, and model-specific vocabularies. A Provider anchor improves total pressure but cannot retrospectively assign exact tokens to every historical node. COMPACT-ESTIMATOR
4. Proactive Pressure Runs Between Steps but Cannot See the Entering Batch
claim inbox messages
→ assemble system/tools
→ compute runtime-context candidate
→ dispatch agent/pre-step waterfall
└─ pressure listener measures current durable Surface
→ append step/start
→ append claimed user/context messages
→ dispatch Provider request
The real-loop test requires pressure compaction between the previous step/end and the next step/start. The Agent has already claimed the batch, however, and does not append it to the Session until the waterfall returns. The pressure listener therefore measures the prior Surface without this Step's entering batch. COMPACT-REAL-LOOP-TESTCOMPACT-RUNTIME-ORDER
If one large input, dynamic-context snapshot, or indivisible node moves the request from below threshold to beyond the window, the proactive pass cannot prevent it. Same-Step recovery can take over only if the adapter accurately normalizes the Provider failure into canonical context overflow.
5. Shrinking Mechanism One: Model-Free Middle Pruning of Tool Results
| Rule | Default behavior | Fidelity boundary |
|---|---|---|
| Trigger length | Text blocks total more than 8,192 Unicode code points | Non-text rich blocks cost zero to this pruner |
| Retention | First 4,096 + marker + last 1,024 code points | Does not split a surrogate pair, but may split a grapheme cluster |
| Replacement scope | Only the tool/result content | Call ID, name, error, metadata, and event semantics remain |
| Ordering | Rich blocks retain order; text slices are rebuilt in place | Images and other rich content are not reduced |
For each candidate, the pruner first appends compaction/prune with the old node's token price, then appends a content-only replacement citing the original seq. Replaying the log into a fresh Session yields the same Surface without executing the pruner again. COMPACT-PRUNER-CONFIGCOMPACT-PRUNER
The pressure path does not opportunistically prune below threshold. Once pressure qualifies—or overflow has occurred—it prunes first and remeasures. If that is sufficient, no summary model is called; otherwise, the summary sees the already-pruned Surface. Test source covers all three branches. COMPACT-PRUNE-TEST
6. Shrinking Mechanism Two: Retain a Recent Tail and Summarize a Head-Anchored Span
The pressure path walks backward from the Surface tail until it has accumulated the retention budget, then moves the cut toward the head until it finds a tool-call/result-balanced boundary. It compacts the head rather than selecting scattered messages deemed “unimportant.” The overflow path uses a zero retention budget to release as much space as possible.
Even with zero retention, the tail scan keeps at least the final Surface node. The selector returns null when only one indivisible unit remains, no compactable head exists, or no legal balanced cut can be found. COMPACT-RANGE
This is a recency-first policy: recent text stays verbatim while older context is merged as one region. There is no semantic-importance scorer, so retention of an old but critical constraint depends entirely on summary quality. In return, boundaries and computational cost remain predictable and require no retrieval subsystem.
7. A Legal Cut Guarantees Tool Pairing, Not a Step or Turn Boundary
The pairing fold scans current Surface order. Every assistant tool call increments a balance, each tool result decrements it, and the fold computes N+1 cuts around N nodes. It rebuilds after a replacement generation change and extends incrementally for ordinary appends.
The selector will not leave a tool call on one side of a checkpoint and its result on the other. This condition is independent of durable Step brackets. An older checkpoint at a high log seq is a normal user node and may be balanced on either side, so a future region can compact it again. COMPACT-PAIRING
This gives the precise answer to “how many levels exist?” A log may contain arbitrarily many checkpoint generations, while every transaction still performs one span replacement. The level count is historical recursion depth, not a set of specialized runtime phases.
8. The Summary Call Reuses Conversation Shape but Is Not a Hidden Second Agent Loop
summary request
= current system prompt
+ current ordered tool schemas
+ selected region as model messages
+ one fixed English compaction directive
→ one Provider stream (purpose = "compaction")
→ collect non-empty text only
→ frame as <compacted-summary>…</compacted-summary>
The target preference is an explicit summary provider/model, then the latest routed request, then Agent options. The call carries Session ID, purpose, and maxTokens. Max-token truncation, abort, image output, empty text, or call failure all reject the summary. Reasoning and tool-call blocks may remain in rawOutput for audit, but only text enters the checkpoint; a mixed tool-call-plus-text output does not execute the tool. COMPACT-SUMMARIZER
The request retains the original system/tools/region prefix and places one fixed directive at the end, creating a cache-reuse shape when the route is the same. Choosing another provider/model preserves the shape but cannot share a provider cache across routes.
The fixed English instruction asks for eight structured headings and asks the model to merge a prior checkpoint rather than copy it verbatim. Code does not parse those headings or validate factual fidelity, entities, commitments, or unfinished tasks. The only content gate is that the framed checkpoint's estimated token count must be strictly smaller than the shadowed span. Requiring English for a non-English Session also introduces an extra translation-loss surface.
9. A Summary Is a Locked, Revalidated, Multi-Append Log Transaction
Validate and lock
Check range, owner, and any active compaction; synchronously append compaction/start.
Snapshot and call
Freeze selected messages and positional prices, then await the Provider summary outside synchronous commit code.
Revalidate stability
Automatic mode requires the entire Surface to be unchanged; manual mode requires only the selected span to remain stable.
Commit the body synchronously
Append the summary audit event, then the replacement user message.
Close the bracket
Append a successful end; any failure after start makes exactly one attempt to append an error end.
compaction/start is a durable log lock. Automatic work records its owning Turn number; manual work uses turn:null. Automatic mode rejects any Surface change while awaiting the summary, whereas manual mode permits appends outside the selected span. COMPACT-TRANSACTIONCOMPACT-COMMIT
10. A Checkpoint Stores Model Text, Source Span, and Actual Call Evidence Separately
| Record | Stored content | Enters model Surface? |
|---|---|---|
compaction/start | Transaction ID, owner Turn, optional command ID | No |
compaction/summary | Summary, shadowed seqs/range/token price, route, maxTokens, usage, rawOutput | No |
Replacement user/message | Framed checkpoint and plugin source marker, citing start, summary, and shadowed seqs | Yes; replaces the old span |
compaction/end | Transaction closure or error | No |
compaction/prune | Single-node shadow price | No; the following replacement changes Surface |
The summary text, raw model output, provider/model, usage, shadowed range, and final model-visible checkpoint are stored separately. A reader can audit what the model emitted, which text the system adopted, and which nodes were replaced without exposing raw summary reasoning or tool blocks to the main conversation. COMPACT-EVENTS
11. How Recursive Checkpoints Produce Real Multi-Generation Compaction
Generation 0: [old raw history .............][recent tail]
Generation 1: [checkpoint A][recent tail .................]
Generation 2: [checkpoint B merges A + later history][tail]
Generation n: [checkpoint N][newest retained tail]
Every replacement advances surface.replaceGeneration, causing pairing and token-pressure projections to update. At the next pressure cycle, checkpoint A has no “never compact” identity; it is simply a user message with provenance. The fixed instruction asks the model to merge an older checkpoint instead of nesting its complete XML framing, but that remains a prompt-level requirement.
Every generation must be strictly shorter under the estimator, but there is no executable semantic-fidelity invariant. Monotonic size reduction does not bound factual error: repeated summaries may accumulate omission, translation, and abstraction loss. The log retains the original shadowed events for people and offline tools, while the main model sees only the current checkpoint.
12. Overflow Recovery Retries Within the Same Step and Uses Generation Advance as Proof of Progress
After an adapter normalizes a failure as canonical context overflow, the handler uses a separate overflow budget: prune, remeasure, then attempt a zero-retention summary. It returns retry only if surface.replaceGeneration advanced. A committed prune followed by summary failure therefore still counts as progress. A successful assistant message or return to idle resets the counter, and cancellation remains final. COMPACT-AUTO-TRIGGERSCOMPACT-POLICY-LOOP
Test source requires recovery to stay in the original Step. The second Provider request sees the old sentinel removed and the checkpoint already present in the same Session log. Upstream dependencies are not installed, so this study inspected the test contract but did not execute it. COMPACT-REAL-LOOP-TEST
A same-Step retry reuses the previously assembled system, tools, and request configuration; the change comes from Session Surface replacement, not a fresh pre-Step assembly. If overflow is dominated by a large system prompt, tool schema, or one indivisible node, Surface compaction may have no legal space to release.
13. Manual /compact Is Idle Maintenance, Not a Concurrent Forced Rewrite
compactNow() enters through runMaintenance only while the Agent is idle with no waking queued work. It uses zero retention and a null Turn owner. Appends outside the span may occur while summary is pending; only the selected span is revalidated. A closed attempt passes the Session flush barrier before returning. COMPACT-MANUAL
The human command accepts no arguments and maps busy, cancelled, Surface-changed, summary, commit, and persistence failures to distinct results. Success reports shadowed items and tokens and correlates the source command ID with the summary seq. Plugin teardown waits for active handlers to drain. COMPACT-COMMAND
14. Runtime Context Uses Replacement Provenance for Reinjection, with One Conditional Window
The dynamic runtime-context projection remembers the latest owned snapshot still present on Surface. When replacement source seqs shadow that snapshot, the projection clears its retained value. The next project(currentText) therefore emits the current context again, preventing permanent loss after compaction. COMPACT-RUNTIME-PROJECTION
The Agent computes the candidate before the pre-Step waterfall. If current text then equals retained text, the candidate is undefined. Compaction inside the waterfall may subsequently shadow the retained snapshot and clear it, but this Step does not recompute the candidate. The immediately following request can therefore omit current runtime context once; the next Step emits it again. Existing tests cover “manually compact, then call preStep,” not this exact interleaving. COMPACT-RUNTIME-ORDERCOMPACT-RUNTIME-PROJECTION
This is a narrow one-request window, not permanent context deletion. Eliminating it would require recomputing the candidate after the waterfall or moving pressure handling before candidate projection.
15. Usage, Pressure, and Shadow Price Are Three Different Observability Surfaces
| Projection / event | Question answered | What it excludes |
|---|---|---|
tokenUsage | Usage for primary assistant requests, accumulated last-wins by Turn and Step | compaction/summary.data.usage is not accumulated |
contextPressure | Next-request pressure from the latest Provider prompt sample plus Surface delta | Not a complete billing-cost ledger |
| Summary-event usage | Route and usage audit for one auxiliary summary call | Not automatically rolled into the primary usage projection |
| Shadow price | Estimated old-span price used by the O(1) projection | Neither semantic importance nor exact tokenizer allocation |
The usage fold reads only assistant usage chunks and messages. Summary usage is durably recorded but excluded from cumulative tokenUsage. The projection therefore describes primary conversation requests, not every Provider call issued on behalf of the Session. Source comments do not fully resolve whether this is intentional auxiliary-cost exclusion or a documentation ambiguity. COMPACT-USAGE-PROJECTION
16. The O(1) Pressure Projection Relies on a Local “Shadow Price Immediately Before Replacement” Protocol
The Surface token projection stores only a running total and one pending claim. A compaction/summary or compaction/prune stages the old price; the next replacement consumes it and applies the signed delta. Any intervening event expires the claim. For historical compatibility, a replacement without a claim degrades to zero delta instead of failing closed.
Normal summary and pruner producers append synchronously adjacent records, so they honor the protocol. The compaction runtime invariant validates brackets, IDs, owners, shadow endpoints and token counts, checkpoint sources, and successful ends, but does not require summary/prune adjacency to the corresponding replacement. A faulty plugin or external log writer could therefore produce a sequence that passes the compaction invariant while silently drifting the bounded pressure projection. COMPACT-SHADOW-PRICECOMPACT-INVARIANT
17. Confirmed Constraints, Gaps, and Deliberate Tradeoffs
| Finding | Classification | Consequence |
|---|---|---|
| Pre-Step pressure cannot see the entering batch | Ordering constraint | Large new input depends on overflow recovery |
| Runtime context may be absent for one request | High-confidence static inference | The next Step repairs it; no runtime reproduction yet |
| Summary validation checks only nonempty and shorter | Quality boundary | Eight headings, factual fidelity, and task completeness are not code-enforced |
| Fixed English summary directive | Internationalization tradeoff | Non-English context may incur translation loss |
| Auxiliary summary usage is absent from tokenUsage | Observability scope | The cumulative value is not total Provider cost |
| Invariant does not check shadow-price adjacency | Coverage gap | A nonstandard writer can silently drift the bounded projection |
| Fixed-density heuristic | Precision tradeoff | CJK/JSON retention pricing can be wrong |
| System/tools and one indivisible node cannot be compacted | Capability boundary | High total pressure may still have no legal span |
| Rich tool blocks are not reduced by the text pruner | Mechanism boundary | Image pressure requires another policy |
| A multi-result prune pass may partially commit | Deliberate local progress | A later failure does not roll back earlier replacements |
These findings should not all be called vulnerabilities. Uncompactable system and tool envelopes are a natural boundary of the Surface seam; partial pruning is a replayable local-progress policy; summary fidelity is the genuine risk surface without a machine-checkable contract.
18. Design Assessment and Verification Status
| Choice | Benefit | Cost |
|---|---|---|
| Deterministic pruning before model summary | Avoid model cost and semantic loss when simple reduction is enough | Covers only text-heavy tool results |
| Checkpoint as replayable event replacement | Recovery, forks, UI, and the next request share one Surface | Readers must distinguish the log from the current model view |
| Recursion instead of fixed levels | Supports unbounded Sessions without level-format migrations | Repeated-summary error has no hard bound |
| Provider usage anchor plus signed delta | Total pressure is closer to a real request than a pure heuristic | Node-level cuts still depend on estimates and adjacency |
| Durable bracket and provenance | Every compaction is auditable, replayable, and command-correlated | Multiple appends are not one backend-atomic transaction |
This chapter cross-checked the compaction seam, events, and invariant; the basic policy, region, and summarizer; the tool-result pruner; token meter and projections; Agent pre-Step ordering; runtime-context projection; the manual command; and real-loop and composition test source. Upstream dependencies are not installed, so no upstream test execution is claimed. Exact race and crash paths are explicitly labeled as static inferences.
My Learning Notes
Autosaved only in this browser. Nothing is uploaded or committed. Export Markdown whenever you want to keep a copy.