fix: prevent persistSessionUsageUpdate from corrupting totalTokens (fixes #82576)#82578
Conversation
|
Codex review: needs real behavior proof before merge. Summary Reproducibility: yes. at source level: after preflight compaction stores a fresh totalTokens value, persistSessionUsageUpdate on current main can run with nonzero usage but no fresh snapshot and merge totalTokens: undefined over that value. I did not run a live Feishu/WebChat reproduction in this read-only review. Real behavior proof Next step before merge Security Review findings
Review detailsBest possible solution: Preserve the post-compaction token snapshot for stale post-preflight usage, keep the numeric guard before marking fresh snapshots fresh, and add patched-run proof plus focused regression coverage. Do we have a high-confidence way to reproduce the issue? Yes, at source level: after preflight compaction stores a fresh totalTokens value, persistSessionUsageUpdate on current main can run with nonzero usage but no fresh snapshot and merge totalTokens: undefined over that value. I did not run a live Feishu/WebChat reproduction in this read-only review. Is this the best way to solve the issue? No, not yet: preserving the post-compaction value is the right direction, but the PR should keep the numeric totalTokens guard before setting totalTokensFresh=true and needs after-fix real behavior proof. Full review comments:
Overall correctness: patch is incorrect Acceptance criteria:
What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 1bd10cfee6a4. Re-review progress:
|
417440b to
96fe4b2
Compare
When persistSessionUsageUpdate runs without a fresh context snapshot (hasFreshContextSnapshot=false), it unconditionally set totalTokens=undefined and totalTokensFresh=false. This overwrites the totalTokens that was correctly set by incrementCompactionCount after compaction. The corrupted totalTokens then caused the preflight compaction check to fall through to full transcript token estimation on every message dispatch. For models with smaller context windows (e.g., MiniMax M2.7 at 204K tokens), the re-estimation exceeded the compaction threshold, triggering a new compaction on every single message. Models with larger context windows (e.g., deepseek-v4-flash at 1M tokens) were not affected because the threshold was never exceeded. The fix only updates totalTokens/totalTokensFresh when a fresh context snapshot is available. When the snapshot is stale, the existing values (usually set by the most recent compaction) are preserved.
…tale snapshot When hasFreshContextSnapshot is false, the previous code unconditionally set totalTokens=undefined which corrupted the value set by incrementCompactionCount after compaction. Now totalTokens is preserved (only totalTokensFresh=false is set to mark the snapshot as stale), so the compaction threshold guard does not trigger false positives on every dispatch while the preflight check can still run a full re-estimation when needed.
96fe4b2 to
a3269d0
Compare
|
Verification before merge: Behavior addressed: #82576 repeated preflight compaction loop. The PR now keeps the fresh post-compaction token snapshot fresh when the later stale usage write has no current token count, so the next preflight sees the compacted total instead of compacting again. Real environment tested: local focused Vitest/lint, codex-review with Testbox check:changed, and GitHub CI on head a3269d0. Exact steps or command run after this patch:
Evidence after fix: focused test shards passed; raw channel fetch guard passed; codex-review reported no accepted/actionable findings; Testbox check:changed passed; GitHub PR checks are clean. Observed result after fix: stale usage updates no longer mark the fresh post-compaction total stale, dead main session rows are recreated without inheriting old label/transcript metadata, GitHub Copilot device-flow fetches use the SSRF guard, and the stale cron expectations now match the current runtime repair/skip behavior. What was not tested: live provider login against GitHub Copilot; the guarded fetch path is covered with the plugin's auth-refresh test seam. |
…fixes openclaw#82900) PR openclaw#82578 ensured totalTokens is preserved across stale usage updates instead of being corrupted to undefined. However, resolveFreshSessionTotalTokens still returns undefined when entry.totalTokensFresh === false, even though the value is valid. After this change: - resolveFreshSessionTotalTokens returns the preserved totalTokens value even when stale, since the value is guaranteed valid. - Internal compaction and memory flush logic check entry.totalTokensFresh directly, not through this function. - isSessionTotalTokensFresh updated to check entry.totalTokensFresh directly instead of relying on resolveFreshSessionTotalTokens. Closes openclaw#82900.
Fixes openclaw#82576. Keeps post-compaction token totals fresh across stale usage updates and adds regression coverage for the repeated auto-compaction loop. Also includes maintainer fixups needed to keep the touched CI lanes green: guarded GitHub Copilot device-flow fetches, dead-session metadata recreation, and current cron stale-data expectations. Co-authored-by: njuboy11 <njuboy11@users.noreply.github.com>
Fixes openclaw#82576. Keeps post-compaction token totals fresh across stale usage updates and adds regression coverage for the repeated auto-compaction loop. Also includes maintainer fixups needed to keep the touched CI lanes green: guarded GitHub Copilot device-flow fetches, dead-session metadata recreation, and current cron stale-data expectations. Co-authored-by: njuboy11 <njuboy11@users.noreply.github.com>
Fixes openclaw#82576. Keeps post-compaction token totals fresh across stale usage updates and adds regression coverage for the repeated auto-compaction loop. Also includes maintainer fixups needed to keep the touched CI lanes green: guarded GitHub Copilot device-flow fetches, dead-session metadata recreation, and current cron stale-data expectations. Co-authored-by: njuboy11 <njuboy11@users.noreply.github.com>
Fixes openclaw#82576. Keeps post-compaction token totals fresh across stale usage updates and adds regression coverage for the repeated auto-compaction loop. Also includes maintainer fixups needed to keep the touched CI lanes green: guarded GitHub Copilot device-flow fetches, dead-session metadata recreation, and current cron stale-data expectations. Co-authored-by: njuboy11 <njuboy11@users.noreply.github.com>
Fixes openclaw#82576. Keeps post-compaction token totals fresh across stale usage updates and adds regression coverage for the repeated auto-compaction loop. Also includes maintainer fixups needed to keep the touched CI lanes green: guarded GitHub Copilot device-flow fetches, dead-session metadata recreation, and current cron stale-data expectations. Co-authored-by: njuboy11 <njuboy11@users.noreply.github.com>
Fixes openclaw#82576. Keeps post-compaction token totals fresh across stale usage updates and adds regression coverage for the repeated auto-compaction loop. Also includes maintainer fixups needed to keep the touched CI lanes green: guarded GitHub Copilot device-flow fetches, dead-session metadata recreation, and current cron stale-data expectations. Co-authored-by: njuboy11 <njuboy11@users.noreply.github.com>
Fixes openclaw#82576. Keeps post-compaction token totals fresh across stale usage updates and adds regression coverage for the repeated auto-compaction loop. Also includes maintainer fixups needed to keep the touched CI lanes green: guarded GitHub Copilot device-flow fetches, dead-session metadata recreation, and current cron stale-data expectations. Co-authored-by: njuboy11 <njuboy11@users.noreply.github.com>
Fixes openclaw#82576. Keeps post-compaction token totals fresh across stale usage updates and adds regression coverage for the repeated auto-compaction loop. Also includes maintainer fixups needed to keep the touched CI lanes green: guarded GitHub Copilot device-flow fetches, dead-session metadata recreation, and current cron stale-data expectations. Co-authored-by: njuboy11 <njuboy11@users.noreply.github.com>
Fixes openclaw#82576. Keeps post-compaction token totals fresh across stale usage updates and adds regression coverage for the repeated auto-compaction loop. Also includes maintainer fixups needed to keep the touched CI lanes green: guarded GitHub Copilot device-flow fetches, dead-session metadata recreation, and current cron stale-data expectations. Co-authored-by: njuboy11 <njuboy11@users.noreply.github.com>
Fixes openclaw#82576. Keeps post-compaction token totals fresh across stale usage updates and adds regression coverage for the repeated auto-compaction loop. Also includes maintainer fixups needed to keep the touched CI lanes green: guarded GitHub Copilot device-flow fetches, dead-session metadata recreation, and current cron stale-data expectations. Co-authored-by: njuboy11 <njuboy11@users.noreply.github.com>
Fixes openclaw#82576. Keeps post-compaction token totals fresh across stale usage updates and adds regression coverage for the repeated auto-compaction loop. Also includes maintainer fixups needed to keep the touched CI lanes green: guarded GitHub Copilot device-flow fetches, dead-session metadata recreation, and current cron stale-data expectations. Co-authored-by: njuboy11 <njuboy11@users.noreply.github.com>
Fixes openclaw#82576. Keeps post-compaction token totals fresh across stale usage updates and adds regression coverage for the repeated auto-compaction loop. Also includes maintainer fixups needed to keep the touched CI lanes green: guarded GitHub Copilot device-flow fetches, dead-session metadata recreation, and current cron stale-data expectations. Co-authored-by: njuboy11 <njuboy11@users.noreply.github.com>
Fixes openclaw#82576. Keeps post-compaction token totals fresh across stale usage updates and adds regression coverage for the repeated auto-compaction loop. Also includes maintainer fixups needed to keep the touched CI lanes green: guarded GitHub Copilot device-flow fetches, dead-session metadata recreation, and current cron stale-data expectations. Co-authored-by: njuboy11 <njuboy11@users.noreply.github.com>
Summary
Fixes #82576 —
persistSessionUsageUpdateunconditionally overwrotetotalTokens=undefinedwhen there was no fresh context snapshot, corrupting the value set byincrementCompactionCountafter compaction.Problem
After every model call,
persistSessionUsageUpdateupdates the session store. WhenhasFreshContextSnapshotis false (nolastCallUsage, nopromptTokens, nousageIsContextSnapshot), it wrotetotalTokens=undefinedandtotalTokensFresh=false, overwriting compaction state. This causedrunPreflightCompactionIfNeededto skip its early-return guard and fall through to full transcript re-estimation, triggering repeated compactions on every message for smaller-context models.Real behavior proof
Behavior or issue addressed: Repeated auto-compaction on every feishu/webchat message dispatch for models with smaller context windows (~204K tokens). Every message triggered a new compaction because
persistSessionUsageUpdatecorruptedtotalTokenstoundefined, forcingrunPreflightCompactionIfNeededto re-estimate from scratch and always exceed the threshold.Real environment tested: OpenClaw v2026.5.16-beta.1 on Linux VM100, MiniMax M2.7-highspeed model (contextWindow: 204800), long-running feishu DM conversation with image analysis.
Exact steps or command run after this patch: The fix is a one-line logic change in
src/auto-reply/reply/session-usage.ts. Cannot deploy patched binary directly, but verified by:patch.totalTokens = undefinedis unconditionally appliedsessions.jsonshowedtotalTokens: None, totalTokensFresh: False, compactionCount: 6checks-node-auto-reply-reply-sessionpasses (see CI)Evidence after fix:
totalTokens: None(corrupted),totalTokensFresh: FalsetotalTokensfrom compaction is preserved (not set to undefined);totalTokensFresh=falsestill marks snapshot as stale for preflight re-checks.marks totalTokens as unknown when no fresh context snapshot is availableupdated to cover the new behavior.Observed result after fix: When snapshot is stale,
totalTokensvalue from the most recentincrementCompactionCountcall is preserved instead of corrupted. This prevents the preflight compaction guard from falling through to full transcript re-estimation, stopping the repeated-compaction cycle. The session test passes the updated assertion.Not tested: Models with very large context windows (behavior unchanged since threshold is never exceeded); CLI-provider compaction path (separate code path via
incrementRunCompactionCount).Change
When snapshot is stale: preserves existing totalTokens (from compaction), marks as stale with totalTokensFresh=false.