Bug: resolveFreshSessionTotalTokens returns undefined when totalTokens is preserved (post-#82578 regression)
Symptom
After every 2-3 conversational turns, the /context command shows stale/unknown context utilization, and the Control UI context meter resets to 0%. The session still works correctly and context IS being sent to the model — this is purely a display/estimation issue.
Root Cause
PR #82578 correctly fixed persistSessionUsageUpdate from overwriting totalTokens=undefined when there is no fresh context snapshot. After the fix, totalTokens is preserved across stale usage updates.
However, resolveFreshSessionTotalTokens() (in src/types.ts) still returns undefined when entry?.totalTokensFresh === false, even though totalTokens is now a valid, preserved number. This function is used by:
/context command handler → returns undefined → "context unavailable"
session-utils.ts transcript estimation → returns undefined → triggers unnecessary transcript re-read
Internal consumers unaffected
The compaction preflight check and memory flush logic check entry.totalTokensFresh directly on the entry object, not through resolveFreshSessionTotalTokens(). So they are unaffected and continue to work correctly.
Real Behavior Data
Current session (after fix):
totalTokens: 110392
totalTokensFresh: True (after agent refresh) / False (after new message)
compactionCount: 0
cacheRead: 109568
Flow trace:
- User sends message →
session-updates.ts sets totalTokensFresh = false (incrementBy > 0)
persistSessionUsageUpdate also sets totalTokensFresh = false when !hasFreshContextSnapshot
- Control UI queries status →
resolveFreshSessionTotalTokens sees totalTokensFresh === false → returns undefined
/context command shows stale/unavailable
- Agent starts preflight →
entry.totalTokensFresh === false (checked directly on entry) → reads from transcript → sets totalTokensFresh = true
- Status becomes available again... until next message
Suggested Fix
In resolveFreshSessionTotalTokens(), return the preserved totalTokens value even when totalTokensFresh === false, since the value is now guaranteed to be valid (not undefined) after PR #82578.
// Before:
if (entry?.totalTokensFresh === false) return;
return total;
// After:
// totalTokensFresh=false only means "possibly stale", not "unavailable".
// The value itself is preserved from compaction/transcript (PR #82578).
return total;
The totalTokensFresh flag continues to serve its intended purpose for compaction preflight and memory flush, which check it directly on entry.totalTokensFresh.
Bug:
resolveFreshSessionTotalTokensreturns undefined whentotalTokensis preserved (post-#82578 regression)Symptom
After every 2-3 conversational turns, the
/contextcommand shows stale/unknown context utilization, and the Control UI context meter resets to 0%. The session still works correctly and context IS being sent to the model — this is purely a display/estimation issue.Root Cause
PR #82578 correctly fixed
persistSessionUsageUpdatefrom overwritingtotalTokens=undefinedwhen there is no fresh context snapshot. After the fix,totalTokensis preserved across stale usage updates.However,
resolveFreshSessionTotalTokens()(insrc/types.ts) still returnsundefinedwhenentry?.totalTokensFresh === false, even thoughtotalTokensis now a valid, preserved number. This function is used by:/contextcommand handler → returnsundefined→ "context unavailable"session-utils.tstranscript estimation → returnsundefined→ triggers unnecessary transcript re-readInternal consumers unaffected
The compaction preflight check and memory flush logic check
entry.totalTokensFreshdirectly on the entry object, not throughresolveFreshSessionTotalTokens(). So they are unaffected and continue to work correctly.Real Behavior Data
Flow trace:
session-updates.tssetstotalTokensFresh = false(incrementBy > 0)persistSessionUsageUpdatealso setstotalTokensFresh = falsewhen!hasFreshContextSnapshotresolveFreshSessionTotalTokensseestotalTokensFresh === false→ returnsundefined/contextcommand shows stale/unavailableentry.totalTokensFresh === false(checked directly on entry) → reads from transcript → setstotalTokensFresh = trueSuggested Fix
In
resolveFreshSessionTotalTokens(), return the preservedtotalTokensvalue even whentotalTokensFresh === false, since the value is now guaranteed to be valid (notundefined) after PR #82578.The
totalTokensFreshflag continues to serve its intended purpose for compaction preflight and memory flush, which check it directly onentry.totalTokensFresh.