Bug Description
Session idle and daily resets never fire because updateLastRoute() in recordInboundSession() bumps updatedAt to Date.now() before initSessionState() evaluates session freshness.
Environment
- OpenClaw version: 2026.3.13 (61d171a)
- Platform: macOS (Darwin arm64), Node v25.6.1
- Channel: Discord (multi-agent setup, 10 agents)
- Config:
session.reset = { mode: "daily", atHour: 4, idleMinutes: 20 }
Steps to Reproduce
- Configure session reset with
idleMinutes: 20 and mode: "daily", atHour: 4
- Send a message in a Discord channel session
- Wait >20 minutes (or past the daily reset hour)
- Send another message
- Session is NOT reset; same sessionId, transcript keeps growing
Evidence
- F.R.I.D.A.Y. agent: Session ran 2.5 days (created 2026-03-15T20:50 UTC), 1084 entries, 5.2MB, 367K tokens, through 16 idle gaps >20 min (longest: 17.6 hours)
- JARVIS agent: 268K tokens, 14.1-hour and 9.1-hour gaps without reset
- All agents affected (systemic)
Root Cause
recordInboundSession() calls updateLastRoute() which writes:
updatedAt: Math.max(existing?.updatedAt ?? 0, now) // now = Date.now()
This uses mergeSessionEntry (not preserve-activity) and writes to sessions.json BEFORE initSessionState() reads it.
Sequence on every inbound message:
- Discord message arrives
recordInboundSession() → updateLastRoute() bumps updatedAt to Date.now()
sessions.json now shows fresh updatedAt
getReplyFromConfig() → initSessionState() → loadSessionStore(skipCache: true)
evaluateSessionFreshness() sees updatedAt = Date.now(), returns fresh: true
- Session reuses indefinitely
Location: Line ~33953 in dist/auth-profiles-DRjqKE3G.js (updateLastRoute function)
Relationship to #32379
The idle reset fix in #32379 (v2026.3.2) patched recordSessionMetaFromInbound to use preserve-activity, but missed updateLastRoute() in the same recordInboundSession() function. The bug is an incomplete fix.
Suggested Fix
Make updateLastRoute() use mergeSessionEntryPreserveActivity instead of mergeSessionEntry, or remove the updatedAt field from its patch object. updatedAt should only be bumped by the actual agent run completion in updateSessionStoreAfterAgentRun().
Workaround
Manual /reset in affected channels. No config-based workaround exists since the bug is in the inbound pipeline before config-based freshness evaluation.
Bug Description
Session idle and daily resets never fire because
updateLastRoute()inrecordInboundSession()bumpsupdatedAttoDate.now()beforeinitSessionState()evaluates session freshness.Environment
session.reset = { mode: "daily", atHour: 4, idleMinutes: 20 }Steps to Reproduce
idleMinutes: 20andmode: "daily", atHour: 4Evidence
Root Cause
recordInboundSession()callsupdateLastRoute()which writes:This uses
mergeSessionEntry(notpreserve-activity) and writes tosessions.jsonBEFOREinitSessionState()reads it.Sequence on every inbound message:
recordInboundSession()→updateLastRoute()bumpsupdatedAttoDate.now()sessions.jsonnow shows freshupdatedAtgetReplyFromConfig()→initSessionState()→loadSessionStore(skipCache: true)evaluateSessionFreshness()seesupdatedAt = Date.now(), returnsfresh: trueLocation: Line ~33953 in
dist/auth-profiles-DRjqKE3G.js(updateLastRoutefunction)Relationship to #32379
The idle reset fix in #32379 (v2026.3.2) patched
recordSessionMetaFromInboundto usepreserve-activity, but missedupdateLastRoute()in the samerecordInboundSession()function. The bug is an incomplete fix.Suggested Fix
Make
updateLastRoute()usemergeSessionEntryPreserveActivityinstead ofmergeSessionEntry, or remove theupdatedAtfield from its patch object.updatedAtshould only be bumped by the actual agent run completion inupdateSessionStoreAfterAgentRun().Workaround
Manual
/resetin affected channels. No config-based workaround exists since the bug is in the inbound pipeline before config-based freshness evaluation.