Repository navigation
fix(v2): stop compaction usage from becoming phantom system overhead (#421) - #430
Open
ranxianglei wants to merge 2 commits into
Open
ranxianglei wants to merge 2 commits into
ranxianglei wants to merge 2 commits into
Conversation
…421) V2 native compaction projects the checkpoint as an assistant carrying the compaction REQUEST's token usage verbatim. cacheSystemPromptTokens used that assistant as its calibration anchor, storing the request size (repro: 653136) as permanent system overhead and driving hard-guard budgets negative (-285904 on a 400k model) while actual provider usage stayed small. - calibrateSystemOverhead: never anchor on summary assistants or on assistants created before state.lastCompaction; subtract the full wire-visible pre-anchor prefix (BPE-exact), excluding host-ignored user parts and ACP-owned notices. Plain-text sessions calibrate exactly as before (#255 suite unchanged). - cacheSystemPromptTokens: merge heuristic residual with a measured current-wire floor (max), record provenance in new transient SessionState.systemPromptTokensSource (heuristic|measured). - v2/context.ts: measure actual outgoing system parts + rendered ACP system prompt each transaction and pass as the floor. - Invalidation: resetOnCompaction and mid-session model switch now clear the cached estimate so post-compaction/reload recalibrates cleanly. - /acp context breakdown labels the system segment [measured]/[estimated]. Tests: tests/v2-compaction-system-overhead.test.ts (14 regression tests; verified to fail against pre-fix code, which stores the exact 653136 phantom). Full suite 1424/1425 (soft-block /tmp EACCES is environmental). Devlog: devlog/2026-09-17_v2-compaction-phantom-system/{REQ,DESIGN,WORKLOG}.md
Owner
Author
[bot] 🏷 收到,开始核验这个 PR(不重做,按 [PR] 流程:拉分支核对代码 + 确认 CI + 报告结论)。已确认 PR 基于 |
…fallback (#421) The /acp context fallback in lib/compress/status.ts already passed state.lastCompaction to the live estimator, but the sibling fallback in estimateContextComposition (lib/messages/inject/utils.ts) did not. After resetOnCompaction invalidates the cached estimate, a pre-compaction assistant could anchor calibration again and resurface the stale overhead in nudge/context-usage math. Pass state?.lastCompaction ?? 0 and add a regression test (fails against the unfixed code).
This was referenced Sep 17, 2026
This was referenced Sep 29, 2026
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.
Closes #421
Problem
V2 native compaction projects the checkpoint as an assistant carrying the compaction request's token usage verbatim (
lib/v2/projection/shared.tsmakeAssistantInfo).cacheSystemPromptTokensused that assistant as its calibration anchor, permanently storing the request size as "system + tool schemas" overhead. Repro from the issue: input 653137 → stored 653136 phantom; on a 400000-token model the hard-guard budget becomes −285904, producing negative-budget log spam and unnecessary tool clearing while real provider usage stays far smaller.Fix
lib/token-utils.ts— newcalibrateSystemOverhead(state, messages): never anchors oninfo.summary === trueassistants or assistants created beforestate.lastCompaction; subtracts the full wire-visible pre-anchor prefix with BPE-exact counts (excluding host-ignored user parts and ACP-owned notices).estimateSystemPromptTokens(messages, lastCompaction = 0)delegates to it.lib/ui/utils.ts—cacheSystemPromptTokens(state, messages, measuredSystemTokens?)merges the heuristic residual with a measured current-wire floor viamax(), recording provenance in new transient fieldSessionState.systemPromptTokensSource(heuristic|measured). The [FIX estimateSystemPromptTokens inconsistent between nudge and acp_status after compression #255] stable-cache early return is preserved.lib/v2/context.ts— measures the actual outgoing system parts (Σ countTokens(event.system[].text)+ rendered ACP system prompt) each transaction and passes it as the floor. V1 callers omit it → pure heuristic, unchanged.resetOnCompaction(lib/state/utils.ts) and the mid-session model-switch block (lib/messages/transform.ts) now clear the cached estimate, so first-request-after-compaction and after reload recalibrate cleanly instead of inheriting a stale/phantom value.lib/compress/status.ts—/acp contextbreakdown labels the system segment[measured]/[estimated], distinguishing actual wire accounting from heuristics (issue acceptance criterion).No persisted-state format change (
systemPromptTokens*were already transient), no config change, all API extensions are optional trailing parameters.Verification
tests/v2-compaction-system-overhead.test.ts— 14/14 pass: the exact V2: compaction usage becomes phantom system overhead and negative context budgets #421 repro (fresh state + reload both store no phantom), post-compaction anchor calibrates to real wire overhead with nonnegative budget at the reported 400k limit, measured-floor/provenance behavior, invalidation paths, and estimateSystemPromptTokens inconsistent between nudge and acp_status after compression #255 compatibility (plain-text sessions calibrate byte-for-byte as before).lib/reverted to pre-fix code, the originalcacheSystemPromptTokenson the repro input stores exactly 653136; fixed code storesundefined.tests/soft-block.test.tsmodule-loadEACCES /tmp— sandbox mounts/tmpread-only, pre-existing environmental issue, unrelated).npm run typecheckclean,npm run buildgreen, touched files prettier-clean.devlog/2026-09-17_v2-compaction-phantom-system/{REQ,DESIGN,WORKLOG}.md.中文摘要:修复了 V2 原生压缩后校准锚点误用 compaction 请求用量、把 653136 tokens 当成永久 system 开销导致硬护栏预算为负(-285904)的问题——排除 summary/过期锚点、按当前实际出站 system 部件做测量下限、在压缩与模型切换时失效缓存,并在 /acp context 中标注 measured/estimated 来源。