openclaw - ✅(Solved) Fix Isolated cron jobs with explicit sessionKey overwrite parent session's updatedAt, preventing daily reset [3 pull requests, 6 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#51000Fetched 2026-04-08 01:05:42
View on GitHub
Comments
6
Participants
3
Timeline
12
Reactions
0
Timeline (top)
commented ×6referenced ×4cross-referenced ×2

Root Cause

In src/cron/isolated-agent/session.ts, persistSessionEntry does a raw write:

store[agentSessionKey] = cronSession.sessionEntry;

When agentSessionKey resolves to the same key as the main session (e.g., agent:main:main), the cron run's session entry replaces the main session's entry entirely — including updatedAt, sessionId, model, and all other fields.

Fix Action

Workaround

Set each isolated cron's sessionKey to a unique value (e.g., agent:main:cron:<job-name>) instead of agent:main:main. This prevents the cron from writing to the main session's store entry.

PR fix notes

PR #51026: fix(cron): preserve parent session updatedAt for isolated cron jobs

Description (problem / solution / changelog)

Problem

Isolated cron jobs with sessionKey matching the main session key were overwriting the parent session's updatedAt, preventing daily session reset from triggering. This caused users to get previous day's session with stale context instead of a fresh start.

Solution

Use mergeSessionEntryPreserveActivity when writing to the agent session key to preserve the parent session's activity timestamp. This prevents isolated cron jobs from bumping the updatedAt past the daily reset boundary.

Changes

  • Import mergeSessionEntryPreserveActivity from sessions module
  • Update persistSessionEntry to merge entries preserving activity
  • Add comment explaining the fix and referencing issue #51000

Testing

Manual testing needed: Configure an isolated cron job with sessionKey: "agent:main:main" that runs after the daily reset hour, then verify that the daily reset still triggers correctly.

Fixes #51000

Changed files

  • src/cron/isolated-agent/run.ts (modified, +12/-2)

PR #53014: fix(heartbeat): skip heartbeat when main session is stale to allow daily reset

Description (problem / solution / changelog)

Fixes #51000 (heartbeat vector)

Problem

The heartbeat runner resolves the main session via its own resolveHeartbeatSession() function, which does not call evaluateSessionFreshness(). When a heartbeat fires after session.reset.atHour (e.g., 4 AM) but before the user's first message, the heartbeat touches the session entry, preventing the lazy daily reset from ever firing.

This is the same root cause as #51000 (cron jobs overwriting updatedAt), but through the heartbeat code path. The cron fix (unique session keys) addressed one vector; this PR addresses the remaining one.

Fix

Added a session freshness check in resolveHeartbeatPreflight() that mirrors the logic in resolveSession():

  1. Resolves reset policy (mode, atHour, channel overrides)
  2. Evaluates session freshness via evaluateSessionFreshness()
  3. If the session is stale (past the daily reset window), skips the heartbeat with skipReason: "session-stale"

The session's updatedAt remains untouched, so the next real user message triggers the reset naturally through the existing resolveSession() path.

Scope

  • Only affects non-isolated heartbeats (isolated heartbeats create their own session and don't interfere with the main session)
  • Only skips when there is an existing session entry to evaluate
  • Uses the exact same freshness evaluation chain as resolveSession() in src/agents/command/session.ts

Changes

  • src/infra/heartbeat-runner.ts - Added freshness check in resolveHeartbeatPreflight(), extended HeartbeatSkipReason type with "session-stale"

Testing

  • Manually confirmed: with this change, heartbeats after 4 AM on a stale session would be skipped, allowing the daily reset to fire on the next user message
  • Formatting verified with oxfmt --check

Changed files

  • src/infra/heartbeat-runner.ts (modified, +37/-1)

PR #63801: fix(session): preserve updatedAt for system events to keep daily reset working (#63732)

Description (problem / solution / changelog)

Summary

Fixes #63732

AI-assisted PR — built with Claude (Anthropic). Degree of testing: fully tested (existing test suite passes; relevant test files verified). The fix was authored and reviewed by an AI agent team and cross-reviewed by another team member before submission.

Root Cause

When a heartbeat, cron-event, or exec-event run saves the session entry, the code at src/auto-reply/reply/session.ts:521 unconditionally wrote updatedAt: Date.now().

This caused evaluateSessionFreshness to always see the session as fresh (since updatedAt was refreshed on every heartbeat tick), effectively disabling the daily reset policy. The daily atHour reset never fired.

Bisected to commit 6c3eea3 (v2026.4.1) by @martingarramon. Related prior reports: #51000, #46539.

Fix

System events (heartbeat/cron-event/exec-event) now preserve the existing updatedAt value from the base entry instead of advancing it to the current time. Only real user interactions should advance updatedAt and reset the freshness clock.

A follow-up commit (f5e3bc7) adds a typeof + Number.isFinite guard to reject non-numeric or non-finite persisted values before reusing them, addressing security bot feedback about potentially corrupted JSON values.

Testing

  • Existing tests in src/config/sessions/reset.test.ts and src/auto-reply/reply/agent-runner-session-reset.test.ts pass (4/4).
  • pnpm check passes on the modified files.
  • No new tests were required as the fix is a conditional one-liner on an existing code path with existing test coverage.

AI-assisted Checklist

  • Marked as AI-assisted in the PR description
  • Degree of testing noted: existing tests pass, relevant paths covered
  • Fix reviewed and understood by the submitting agent before submission
  • Bot review conversations addressed (aisle-research-bot: replied with rationale and scope boundary)

Changed files

  • src/auto-reply/reply/session.ts (modified, +14/-1)

Code Example

store[agentSessionKey] = cronSession.sessionEntry;
RAW_BUFFERClick to expand / collapse

Bug

Isolated cron jobs (sessionTarget: "isolated") that specify a sessionKey matching the main session key (e.g., agent:main:main) overwrite the parent session entry in the session store, including updatedAt. This prevents the daily session reset from triggering.

Root Cause

In src/cron/isolated-agent/session.ts, persistSessionEntry does a raw write:

store[agentSessionKey] = cronSession.sessionEntry;

When agentSessionKey resolves to the same key as the main session (e.g., agent:main:main), the cron run's session entry replaces the main session's entry entirely — including updatedAt, sessionId, model, and all other fields.

Impact

evaluateSessionFreshness checks updatedAt < dailyResetAtMs to determine staleness. When an isolated cron completes after the daily reset hour (default 4 AM), it bumps updatedAt past the reset boundary, making the session appear "fresh" on the next inbound message.

Result: The daily session reset silently fails. The user gets the previous day's session with stale context instead of a fresh start.

Reproduction

  1. Configure session.reset.mode: "daily" with atHour: 4
  2. Create an isolated cron with sessionKey: "agent:main:main" that runs after 4 AM (e.g., hourly, or scheduled at 5/6/7 AM)
  3. Wait for the cron to complete after 4 AM
  4. Send a message to the main session
  5. Expected: New session (daily reset triggered)
  6. Actual: Same session continues — updatedAt was bumped by the cron run

Suggested Fix

Either:

  • Option A: Use mergeSessionEntryPreserveActivity (already exists in codebase) when persisting isolated cron session entries to parent keys, so updatedAt is not bumped
  • Option B: Isolated cron runs should always write to a namespaced key (e.g., agent:main:cron:<jobId>:run:<runId>) and never to the parent session key directly
  • Option C: evaluateSessionFreshness should ignore updatedAt changes from cron-originated writes (e.g., by tracking lastUserActivityAt separately from updatedAt)

Workaround

Set each isolated cron's sessionKey to a unique value (e.g., agent:main:cron:<job-name>) instead of agent:main:main. This prevents the cron from writing to the main session's store entry.

Environment

  • OpenClaw version: 2026.3.13
  • OS: macOS 26.2 (arm64)
  • Config: session.reset.mode: "daily", atHour: 4
  • Affected cron: any isolated job with sessionKey matching the main session key

extent analysis

Fix Plan

To fix the issue, we will implement Option A: Use mergeSessionEntryPreserveActivity when persisting isolated cron session entries to parent keys. This will prevent updatedAt from being bumped.

Here are the steps:

  • Locate the persistSessionEntry function in src/cron/isolated-agent/session.ts.
  • Replace the raw write with a call to mergeSessionEntryPreserveActivity:
import { mergeSessionEntryPreserveActivity } from './session-utils';

// ...

mergeSessionEntryPreserveActivity(store, agentSessionKey, cronSession.sessionEntry);
  • Verify that mergeSessionEntryPreserveActivity correctly merges the session entries without updating updatedAt.

Verification

To verify the fix, follow these steps:

  • Configure session.reset.mode: "daily" with atHour: 4.
  • Create an isolated cron with sessionKey: "agent:main:main" that runs after 4 AM.
  • Wait for the cron to complete after 4 AM.
  • Send a message to the main session.
  • Check that a new session is created (daily reset triggered).

Extra Tips

  • Make sure to test the fix thoroughly to ensure that it does not introduce any regressions.
  • Consider implementing Option B or Option C as an alternative solution.
  • Review the codebase to ensure that similar issues do not exist in other areas.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix Isolated cron jobs with explicit sessionKey overwrite parent session's updatedAt, preventing daily reset [3 pull requests, 6 comments, 3 participants]