Repository navigation
/compact cannot succeed once history exceeds the summarizer request limit (death spiral, 101/101 attempts failed) #11773
Replies: 1 comment
|
It is a real dead end, and the spiral is structural. What I verified at master
So when the region is over the summarizer route's request limit, every trigger produces the same doomed request. There is no code path that drops messages to make the next summarize fit, and no pre-check of the region against that route's limit. Your numbers (101 start/end, 0 summary, 0 prune) are what this path looks like when the pruner is absent and the request never succeeds. Getting out: a new session, or trimming history yourself before the next turn — which is also what the 400 body says. Repeating Fix shape, if you want to file it: estimate the region against the routed model's request limit before sending; on 413/400 from the summarizer, either prune harder than the tool-result pass or fail once with a definitive "this session cannot be compacted" instead of re-triggering on every turn. If you paste one Read-only source inspection at master |
Uh oh!
There was an error while loading. Please reload this page.
Summary
/compactcannot succeed on a session whose history has grown past the summarizer route's own request limit. Every attempt fails, nothing is pruned, the context only grows, and each subsequent turn re-triggers the same doomed request — a monotonic death spiral with no user-visible way out.Reproduced on a real session (
session.v4.jsonl.zstd, 9,519 events, 7 concatenated zstd frames, 13 MB decompressed, presetcordis):compaction/start/ 101compaction/end, 0compaction/summary, 0compaction/prune— no attempt ever committed.compaction/endevents carried anerror:Request Entity Too Large(raw nginx HTML page)context_length_exceeded— "Context far exceeds the limit for this pack: estimated ~655,944 / ~656,498 / ~699,975 tokens (limit 524,000). It can no longer be summarized in a single request — start a new session, or manually trim the conversation below 524,000 tokens."pi-ai detected context overflowcompaction/startmatched exactly onecompaction/end, so the durable compaction lock is not leaked and the session remains readable.The final
/compactreturned "Compaction could not produce a useful summary. The attempt is recorded in the session log."Root cause
dsh-compaction-basicsummarizes by replaying the selected span into one request. Three properties combine into the trap:compactNowusesretainTokens = 0(dsh-compaction-basic/lib/index.js:992in the shipped build;src/index.tsin source). The manual path therefore shadows essentially the entire surface and replays all of it.compactIfNeededdoes (src/index.ts:926-945), so the model-free "trim first, maybe skip the summary entirely" fallback documented in the README is unavailable to/compact.Because the attempt never shrank anything, nothing was ever pruned, so the surface only grew and every later turn re-triggered the same doomed replay.
A second classification bug
The harness maps any leading HTTP 413 to
CONTEXT_WINDOW_EXCEEDED(pi-ai's overflow patterns match the bare status). An nginx error page is therefore reported as a context overflow even though nothing about the model's window was ever evaluated. That mislabel sends the failure down the overflow-recovery path, which replays the same oversized request and dies identically — burning a retry per turn. This is the same class of bug as the existingfix/pi-ai-413-gateway-body-limitbranch, but reached from the compaction side.Measured provider matrix (against this session's own credentials)
commandcodeminimax/minimax-m3.1-flashaetheraoaoclaude-opus-5.5context_length_exceeded(524,000)whatstokenI rebuilt the exact compaction request from the failing session (3,133 surface messages, the real 47-tool schema, the real 8,065-char system prompt, the verbatim
COMPACTION_INSTRUCTION) and confirmedcommandcodeanswers it successfully, so the session's content is summarizable — only the route was wrong.Fix
https://github.com/akshaytp1571/deepseek-harness/tree/fix/compact-over-budget-route
Commit
2179c355e2— fix(compaction-basic): condense in slices when the replay exceeds the summarizer limit.Classify the failure. New
classifySummarizationFailure()(packages/compaction/compaction-basic/src/failure-class.ts) narrows a thrown summarizer failure toover-budgetorother. Over-budget is a payload-size problem: a provider-confirmed context overflow, a gateway body-limit rejection of the replay, or a framed summary not smaller than its source. Auth, quota, transport, and empty output stay terminal.isGatewayBodyLimitError()distinguishes a proxy's HTML page or bare status line from a provider's structured overflow body.Shrink and retry inside the same bracket.
compactSurfaceRegionnow retries on over-budget failures, re-selecting the oldest balanced prefix that fits and keeping the surface unchanged otherwise. The span keeps its start edge and only its tail boundary walks toward the start, so every intermediate cut stays tool-pairing balanced and the retained recent nodes stay verbatim. The durable contract is preserved exactly: onecompaction/start, at mostoverBudgetRetries + 1summary attempts, exactly one closingcompaction/end— no lock leak, no orphan, no reader-visible shape change. Cancellation, surface change, and commit-stage failures are never retried.New setting.
overBudgetRetries(default3), validated and merged through the existing per-model policy path, documented in the READMEs and the generated config catalog.Tests. 14 new cases (183 total in the package pass, plus
tsc -bandoxlintclean): 413 HTML page, bare status line, and structured provider overflow all classify as over-budget; auth, quota, and "summary is not smaller than the shadowed content" stay terminal; the bracket holds exactly one start/end pair across all retries; each retry replays a strictly smaller prefix; a non-over-budget failure is never retried.What this does not fix
/compactcannot benefit from the tool-result pruner's model-free trim.contextWindow, while the summarization ceiling is the gateway's effective limit. When those disagree the trigger fires far too late for the first attempt to succeed. Sharing one source of truth for both would remove the trap at its root.overBudgetRetrieshalves the span each attempt, so extremely oversized histories need several compactions rather than one.Repro notes for maintainers
session.v4.jsonl.zstdis a concatenation of independently checksummed zstd frames, not a single frame. Node'szstdDecompressSync()andcreateZstdDecompress()both silently return only the first frame (314 bytes here). DSH's owndsh-session-persistence-jsonlships a proper multi-frame decoder, so the harness reads these files correctly — but any external analysis tooling needs to split on frame magic28 B5 2F FDand decode each frame.I am posting this as a discussion rather than opening a PR against
deepseek-ai/deepseek-harnessbecause I do not have push access to the official repository. The branch above carries the full change and the reproducer's measured numbers.All reactions