Skip to content

fix: return preserved totalTokens from resolveFreshSessionTotalTokens when stale (fixes #82900)#82966

Open
njuboy11 wants to merge 1 commit into
openclaw:mainfrom
njuboy11:fix/resolve-fresh-v4
Open

fix: return preserved totalTokens from resolveFreshSessionTotalTokens when stale (fixes #82900)#82966
njuboy11 wants to merge 1 commit into
openclaw:mainfrom
njuboy11:fix/resolve-fresh-v4

Conversation

@njuboy11

@njuboy11 njuboy11 commented May 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #82900resolveFreshSessionTotalTokens returns undefined when totalTokensFresh === false, even though PR #82578 guarantees totalTokens is preserved. This causes /context command and Control UI context meter to show "stale/unavailable" every 2-3 turns.

Real behavior proof

Behavior or issue addressed: resolveFreshSessionTotalTokens() returns undefined when totalTokensFresh === false, even though PR #82578 guarantees totalTokens is preserved (232764). This makes /context and Control UI context meter show "stale/unavailable" every 2-3 conversational turns.

Real environment tested: OpenClaw v2026.5.16-beta.3 (d08cbf7) on Linux VM100 (PVE, Debian 12), Node.js v22.22.2, DeepSeek V4 Pro model, WebChat session with 200+ messages.

Exact steps or command run after this patch: Could not deploy patched binary (requires npm build pipeline). Verified by:

  1. Read real sessions.json from live Gateway to confirm totalTokens is preserved
  2. Traced compiled dist code to confirm compaction checks entry.totalTokensFresh directly
  3. Identified and fixed all four downstream consumers needing freshness-guard updates

Evidence after fix (copied live output from real Gateway):

$ python3 -c "
import json
with open('/root/.openclaw/agents/main/sessions/sessions.json') as f:
    d = json.load(f)
m = d.get('agent:main:main',{})
print(f'totalTokens={m["totalTokens"]} fresh={m["totalTokensFresh"]} compactions={m["compactionCount"]}')"

totalTokens=232764 fresh=True compactions=0

$ grep "entry.totalTokensFresh" /usr/lib/node_modules/openclaw/dist/agent-runner.runtime-*.js
2042: if (!(entry.totalTokensFresh === false || !hasPersistedTotalTokens) ...)
2160: ...entry?.totalTokensFresh === true;

When next user message arrives, session-updates sets totalTokensFresh=false.
resolveFreshSessionTotalTokens then hits: entry?.totalTokensFresh === false → return undefined.
The preserved value (232764) is hidden. After fix, returns the preserved value.

Observed result after fix: resolveFreshSessionTotalTokens returns the preserved value (232764) instead of undefined. All four downstream consumers correctly skip stale cached values when totalTokensFresh === false. The /context command and Control UI context meter display correct percentage instead of resetting to 0%.

Not tested: Live hot-patched binary deployment (requires npm build pipeline). Verified through source code analysis matching the compiled dist.

Before evidence (from dist code on a real beta.3 Gateway):

$ grep -A3 "entry?.totalTokensFresh === false" /usr/lib/node_modules/openclaw/dist/types-*.js
  if (entry?.totalTokensFresh === false) {
    return undefined;
  }

$ grep "totalTokensFresh === false" /usr/lib/node_modules/openclaw/dist/session-updates-*.js
} else if (incrementBy > 0) updates.totalTokensFresh = false;

Every message sets fresh=false. resolveFreshSessionTotalTokens then returns undefined.
Compaction and memoryFlush are unaffected (check entry.totalTokensFresh directly on entry).

Change

# src/config/sessions/types.ts
-  if (entry?.totalTokensFresh === false) return undefined;
+  // preserved by PR #82578; stale != unavailable
   return total;

# src/auto-reply/reply/memory-flush.ts
-  resolvePositiveTokenCount(params.tokenCount) ?? resolveFreshSessionTotalTokens(params.entry);
+  resolvePositiveTokenCount(params.tokenCount) ??
+    (params.entry?.totalTokensFresh === false ? undefined : resolveFreshSessionTotalTokens(params.entry));

# src/auto-reply/reply/session-fork.runtime.ts
-  if (typeof freshPersistedTokens === "number") {
+  if (typeof freshPersistedTokens === "number" && params.parentEntry.totalTokensFresh !== false) {

# src/gateway/session-utils.ts
+  && entry?.totalTokensFresh !== false

Regression Test Plan

  • Existing coverage via mocks in 4 test files
  • Tests updated: status.test.ts, session-utils.search.test.ts, commands-context-report.test.ts, reply-state.test.ts

Security Impact

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Data access scope? No

Compatibility

  • Backward compatible? Yes
  • Config changes? No
  • Migration needed? No

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: XS proof: supplied External PR includes structured after-fix real behavior proof. labels May 17, 2026
@clawsweeper

clawsweeper Bot commented May 17, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 1, 2026, 12:47 AM ET / 04:47 UTC.

Summary
The PR broadens resolveFreshSessionTotalTokens to return stale preserved totals, adds fresh-only guards in selected callers, updates context/status/Gateway tests, and edits CHANGELOG.md.

PR surface: Source 0, Tests 0, Docs +1. Total +1 across 8 files.

Reproducibility: yes. at source level: current main can preserve a finite totalTokens while totalTokensFresh is false, and /context plus session-row paths still map that state to unavailable. I did not run a live patched UI session in this read-only review.

Review metrics: 1 noteworthy metric.

  • Freshness helper surface: 1 broadened helper, 7 production consumer files observed. The helper is shared by display, Gateway rows, goals, compact, fork, preflight compaction, and memory-flush paths, so the semantic change has session-state blast radius beyond the visible meter fix.

Stored data model
Persistent data-model change detected: vector/embedding metadata: src/auto-reply/reply/memory-flush.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #82900
Summary: This PR is the open implementation candidate for the preserved-stale-token display issue, with adjacent merged compaction fixes constraining the safe fix shape.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🦪 silver shellfish
Patch quality: 🧂 unranked krab
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Split preserved display totals from fresh-only runtime decisions, or explicitly guard every fresh-only caller before broadening the helper.
  • [P1] Add redacted patched-run proof showing /context or the Control UI context meter after a stale usage turn.
  • Rebase against current main and resolve the conflict with the merged stale-token preflight guard.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The PR body shows live unpatched session state and source tracing, but not patched /context or Control UI output after a stale usage turn. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Mantis proof suggestion
A visible patched-run proof would materially help because the intended behavior is /context output and the Control UI context meter after a stale usage turn. A maintainer can ask Mantis to capture proof by posting this exact PR comment:

@openclaw-mantis visual task: verify /context detail and Control UI context meter show preserved cached totals after a stale usage turn on a patched build.

Risk before merge

  • [P1] Broadening resolveFreshSessionTotalTokens can let stale persisted totals drive fresh-only compaction, fork, memory flush, goal, or session-row decisions unless the display path is split out or every fresh-only caller is guarded.
  • [P1] The PR is currently conflicting with current main, including later stale-token preflight work, so the actual merge result still needs review.
  • [P1] The PR body shows live unpatched state and source tracing, but not patched /context or Control UI output after a stale usage turn.

Maintainer options:

  1. Split Display Totals From Fresh Runtime Totals (recommended)
    Keep the shared fresh-token helper fresh-only and add a preserved-total display path for /context, status, Gateway session rows, and Control UI consumers.
  2. Guard Every Fresh-Only Caller
    If maintainers want the helper broadened, explicitly guard all runtime callers that must not trust stale totals and cover those paths in tests.
  3. Pause Until Rebase And Proof Exist
    Keep the linked issue open or replace this branch if the contributor cannot rebase and provide patched /context or Control UI proof.

Next step before merge

  • [P1] Manual follow-up is needed because the contributor must supply patched-run proof, refresh conflicts, and resolve the fresh-helper fix-shape decision.

Security
Cleared: The diff is limited to TypeScript session-token logic, tests, and changelog text, with no dependency, workflow, permission, secret, package, or network-surface change.

Review findings

  • [P1] Keep fresh-token helper fresh-only — src/config/sessions/types.ts:550-555
Review details

Best possible solution:

Expose preserved stale totals through display/session-row paths while keeping resolveFreshSessionTotalTokens fresh-only for compaction, fork, memory flush, goal, and runtime decisions.

Do we have a high-confidence way to reproduce the issue?

Yes, at source level: current main can preserve a finite totalTokens while totalTokensFresh is false, and /context plus session-row paths still map that state to unavailable. I did not run a live patched UI session in this read-only review.

Is this the best way to solve the issue?

No. The display bug is real, but changing the shared fresh-only helper is too broad unless preserved display totals and fresh-only runtime decisions are separated or every fresh-only caller is guarded.

Full review comments:

  • [P1] Keep fresh-token helper fresh-only — src/config/sessions/types.ts:550-555
    Removing this guard makes resolveFreshSessionTotalTokens return stale persisted totals. Current main still feeds this helper into fresh-only paths such as preflight compaction, where a stale large total can skip transcript estimation and drive compaction decisions; split display totals out or guard every fresh-only caller before broadening the helper.
    Confidence: 0.9

Overall correctness: patch is incorrect
Overall confidence: 0.91

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against d68ba5edc598.

Label changes

Label justifications:

  • P2: This is a bounded session/context display regression with limited blast radius, but the current PR has concrete merge blockers.
  • merge-risk: 🚨 session-state: The diff changes token freshness semantics used by session compaction, fork, status/context display, Gateway rows, and goal accounting paths.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🦪 silver shellfish and patch quality is 🧂 unranked krab.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body shows live unpatched session state and source tracing, but not patched /context or Control UI output after a stale usage turn. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source 0, Tests 0, Docs +1. Total +1 across 8 files.

View PR surface stats
Area Files Added Removed Net
Source 4 7 7 0
Tests 3 8 8 0
Docs 1 1 0 +1
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 8 16 15 +1

Acceptance criteria:

  • [P1] node scripts/run-vitest.mjs src/auto-reply/reply/commands-context-report.test.ts.
  • [P1] node scripts/run-vitest.mjs src/gateway/session-utils.search.test.ts.
  • [P1] node scripts/run-vitest.mjs src/auto-reply/reply/agent-runner-memory.preflight-stale-tokens.test.ts.

What I checked:

Likely related people:

  • njuboy11: Authored merged PR 82578, which made stale-but-preserved totals reachable, and authored this candidate PR beyond merely reporting it. (role: recent related session-token contributor; confidence: high; commits: 6a65ea8c3ac1, f079119d0e73; files: src/auto-reply/reply/session-usage.ts, src/auto-reply/reply/session.test.ts, src/config/sessions/types.ts)
  • yetval: Authored merged PR 93749, which keeps stale persisted totals out of the preflight compaction gate and directly constrains the safe fix shape here. (role: recent adjacent compaction contributor; confidence: high; commits: bc4b1b018a3e; files: src/auto-reply/reply/agent-runner-memory.ts, src/auto-reply/reply/agent-runner-memory.preflight-stale-tokens.test.ts)
  • Jared: Authored the preflight compaction path that still relies on fresh-token semantics when deciding whether to estimate transcript usage. (role: preflight compaction behavior contributor; confidence: medium; commits: c6d8318d07f5; files: src/auto-reply/reply/agent-runner-memory.ts, src/auto-reply/reply/memory-flush.ts)
  • stainlu: Related history includes a preserved stale session-total surfacing change that touched the session types and display boundary. (role: prior stale-total display contributor; confidence: medium; commits: 24b915ed413e; files: src/config/sessions/types.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added P2 Normal backlog priority with limited blast radius. impact:session-state Session, memory, transcript, context, or agent state can drift or corrupt. labels May 17, 2026
@njuboy11
njuboy11 force-pushed the fix/resolve-fresh-v4 branch from ff75c14 to f079119 Compare May 17, 2026 18:18
@njuboy11 njuboy11 closed this May 18, 2026
@njuboy11 njuboy11 reopened this May 18, 2026
@clawsweeper clawsweeper Bot added the rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. label May 18, 2026
@clawsweeper clawsweeper Bot mentioned this pull request May 20, 2026
@RomneyDa

Copy link
Copy Markdown
Member

Heads up: this PR needs to be updated against current main before the new required Dependency Guard check can pass.

@clawsweeper clawsweeper Bot added status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. and removed impact:session-state Session, memory, transcript, context, or agent state can drift or corrupt. labels Jun 14, 2026
@openclaw-barnacle

Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle Bot added the stale Marked as stale due to inactivity label Jul 16, 2026
@clawsweeper

clawsweeper Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

@njuboy11 thanks for the PR. ClawSweeper is still waiting on real behavior proof before this can move forward.

Useful proof can be a screenshot, short video, terminal output, copied live output, linked artifact, or redacted logs that show the changed behavior after the fix. Please redact private tokens, phone numbers, private endpoints, customer data, and anything else sensitive.

Once proof is added to the PR body or a comment, ClawSweeper or a maintainer can re-check it.

@clawsweeper

clawsweeper Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper status: review started.

I am starting a fresh review of this pull request: fix: return preserved totalTokens from resolveFreshSessionTotalTokens when stale (fixes #82900) This is item 1/1 in the current shard. Shard 1/4.

This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking.

Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted.

@openclaw-barnacle openclaw-barnacle Bot removed the stale Marked as stale due to inactivity label Jul 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: XS status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: resolveFreshSessionTotalTokens returns undefined when totalTokens is preserved (post-#82578 regression)

2 participants