fix(compaction): recover an over-window restored session at resume admission - #1538
Merged
Merged
Conversation
…mission A restored transcript larger than the model context window was refused by resume admission before any extension was wired, so the session could never be reopened (#1524). Admission now plans a deterministic no-LLM context reduction: it reuses findCutPoint so a retained tool result keeps its originating tool call, measures each candidate against the failed projection, and accepts the first one that still leaves room for the system prompt, tool schemas, output reserve, compaction reserve and safety margin. Nothing is written when no candidate fits, compaction-disabled sessions keep refusing, and interactive mode reports the reduction before the first prompt.
Drives a persisted session whose measured live context exceeds the model window and pins the contract: the session opens, the uncompacted requirement fits the window, the recorded transcript survives on disk and in memory, no tool result is orphaned, reopening adds no second reduction, an impossible fixed overhead still refuses without writing, and a compaction-disabled session still refuses.
Starts a sandboxed session against the scripted local provider, inflates the persisted transcript past the model window, resumes with --continue, and asserts on the wire that the outgoing request fits the remaining budget while every inflated record stays on disk.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A session whose restored transcript is larger than the model's context window could not be reopened at all: resume admission threw
ModelUsabilityBudgetErrorinsidecreateAgentSessionbefore any extension was wired, so neither compaction nor its recovery paths could run (#1524, reported with live 965,016 tokens against an 850,000-token window). The compaction-eligible resume branch only relaxes admission while summarization still fits, and the compaction-required admission from #1517 deliberately excluded exactly this band.Resume now reduces the live context deterministically, without any provider request, before the session opens. The reduction reuses the existing compaction cut-point selection, keeps the recorded transcript intact, and is accepted only when the remaining context still leaves room for the whole request overhead, so the first ordinary request cannot overflow. When the fixed overhead alone cannot fit, the original actionable budget error is raised and nothing is written; sessions with compaction disabled keep refusing as before.
Changes
resume-slice.ts, new, fork-only): derives the fixed admission overhead from the failed projection, walksfindCutPoint()from the largest keep budget downwards, measures each candidate through a preview compaction entry, and returns the first cut whose context plus overhead fits the window. Carries the previous checkpoint summary forward under a bounded budget; returns nothing when the overhead alone cannot fit.sdk.ts): unchanged refusals for fresh starts, non-budget errors and compaction-disabled sessions; the over-window case now asks for a plan and rethrows the original error when there is none, while the in-window case keeps the existing compaction-required admission.agent-session.ts):applyResumeSlice()appends the reduction as asenpi.compaction.resume-slice.v1entry, rebuilds the live context, logs one line, and publishes aresume_context_reducedevent thatsubscribe()replays for listeners attached after construction.interactive-mode.ts): renders that event as a warning next to the existing required-compaction notice.session-manager.tsis deliberately untouched — see Risks.QA & Evidence
Remote host
gorky(linux/x86_64, node 24.20.0, vitest 4.1.11). Evidence underlocal-ignore/qa-evidence/20260910-issue1524/.What was tested: failing-first proof, before any production edit — new regression against unmodified
main.Observed result: vitest exit 1;
ModelUsabilityBudgetErroratsdk.ts:546with measured live 979,364 / window 850,000 / required 1,158,762, the same band as the report.Artifact:
c001-red-before-production-edit.logWhy sufficient: reproduces the reported failure through the real admission path, not a stub.
What was tested: the same regression after the change.
Observed result: 4 passed — session opens, uncompacted requirement fits the window, transcript preserved on disk and in memory, no orphaned tool result, reopening adds no second reduction, impossible overhead still refuses without writing, compaction-disabled still refuses.
Artifact:
c001-green-after-fix.logWhy sufficient: RED to GREEN through the identical scenario.
What was tested: whether the new assertions can actually fail (mutation pass).
Observed result: removing the compaction-disabled guard, removing the post-reduction budget check, stopping the trimmed mirror from reloading the file, and making the trim truncate the session file each fail their owning assertion; the restored tree returns 4 passed.
Artifact:
c002-mutation-matrix.mdWhy sufficient: this pass caught two of my own assertions being unfalsifiable and one unnecessary API change; all three were corrected before this PR.
What was tested: adjacent behavior — resume admission, model usability budget, session persistence, compaction mechanics.
Observed result: 92 files / 731 tests passed.
Artifact:
c003-adjacent-regressions.logWhy sufficient: covers the neighbours of every touched seam, including
#1511and start/switch admission.What was tested:
npm run checkandnpm run build --workspace @code-yeongyu/senpi.Observed result: both exit 0.
Artifacts:
c003-static-check.log,c003-build.logWhy sufficient: matches the repository's static gate. An earlier red run was a stale hybrid test tree, not this change; it is green on a clean tree.
What was tested: real CLI,
node .agents/skills/senpi-qa/scripts/qa-1524-resume.mjs— start a sandboxed session against a scripted local provider, inflate the persisted transcript past the window, resume with--continue.Observed result: 11/11 PASS. Restored context ~156,380 tokens against a 120,000-token window; resumed turn exits 0 with no budget error; the outgoing provider request measured on the wire is ~45,423 tokens inside the 112,000 budget; all 60 inflated records remain on disk; a second resume works with exactly one recorded reduction; the real credential file is untouched.
Artifact:
c004-real-cli-resume-qa.logWhy sufficient: proves the user-visible behavior end to end on the real surface, measuring the actual request bytes rather than in-process state.
Risks & Residuals
preserveTranscriptflag toSessionManager.appendCompaction, assuming compaction truncates the session file. It does not —_trimMirrorAfterCompactiononly trims the in-memory mirror and entry reads reload the full history from the file once trimmed. The flag protected nothing and was reverted, so persistence is unchanged and the transcript guarantee is pinned by tests that fail if it regresses.Related Issues
Fixes #1524. Follows #1509 (compaction-eligible resume admission) and #1517 (compaction-required resume admission); supersedes the approach in the still-open #1430, which conflicts with current
mainand reduces context without the post-reduction budget check.Summary by cubic
Resuming a session whose restored transcript is larger than the model's context window no longer fails with
ModelUsabilityBudgetError— admission now reduces the live context without a provider request before the session opens.Written for commit da117f6. Summary will update on new commits.