Skip to content

feat: disable automatic session resets by default#111140

Merged
steipete merged 5 commits into
mainfrom
claude/no-auto-reset-default
Jul 19, 2026
Merged

feat: disable automatic session resets by default#111140
steipete merged 5 commits into
mainfrom
claude/no-auto-reset-default

Conversation

@steipete

Copy link
Copy Markdown
Contributor

What Problem This Solves

OpenClaw currently rolls unconfigured sessions to a new session every day at 04:00 local time. That automatic boundary discards rolling session continuity even though session state persists in SQLite, compaction already bounds the active model context, and memory layers carry durable continuity.

This is an owner-approved, compatibility-sensitive default change: compaction becomes the natural context boundary, while automatic session rollover becomes opt-in.

Why This Change Was Made

The default reset mode is now none. Explicit daily and idle policies, resetByType, resetByChannel, legacy idleMinutes, and manual /new and /reset remain available and retain their existing behavior. Explicit reset objects that omit mode preserve their previous daily fallback.

The consumer sweep also found Discord thread close depended on the old timestamp-based freshness behavior. It now uses a guarded lifecycle deletion so closing a thread still archives its transcript and guarantees a fresh session on the next message under every reset mode. Pending updatedAt: 0 reset tombstones written by older releases remain honored after upgrade.

User Impact

Users without a configured reset policy keep one rolling session across idle gaps and calendar boundaries, with compaction managing context growth. Operators who want automatic rollover can opt into session.reset.mode: "daily" or "idle"; existing explicit schedules and compatibility settings continue to work.

Cron isolated-agent runs still receive a fresh session identity per run. That behavior is driven by run-scoped cron session creation, not the session reset default. Heartbeat and other system-event writes still do not extend explicit daily or idle freshness.

Release-note context: call out that unconfigured sessions no longer reset daily. Operators who want the former behavior should configure session.reset: { mode: "daily", atHour: 4 }. No changelog file is included in this contributor PR.

AI-assisted: yes. I understand and reviewed the implementation and its compatibility boundaries.

Evidence

  • node scripts/run-vitest.mjs src/config/sessions/reset-policy.test.ts src/config/sessions/sessions.test.ts src/config/sessions/store.session-lifecycle-mutation.test.ts src/auto-reply/reply/session.test.ts src/auto-reply/reply/session.heartbeat-no-reset.test.ts src/cron/isolated-agent.session-identity.test.ts extensions/discord/src/monitor/thread-session-close.test.ts src/plugin-sdk/session-store-runtime.test.ts — 261 tests passed on the final rebased head in Blacksmith Testbox.
  • pnpm tsgo:core — passed.
  • pnpm tsgo:extensions — passed.
  • pnpm plugin-sdk:surface:check — passed.
  • Targeted pnpm format:check for all touched files — passed.
  • git diff --check — passed.
  • Autoreview branch mode against current origin/main — clean, no accepted/actionable findings.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: discord Channel integration: discord gateway Gateway runtime plugin: file-transfer size: M maintainer Maintainer-authored PR labels Jul 19, 2026
@steipete
steipete marked this pull request as ready for review July 19, 2026 02:41

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 267c6e95df

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


/** Deletes one session entry by agent/session identity. */
export async function deleteSessionEntry(params: DeleteSessionEntryParams): Promise<boolean> {
const agentId = params.agentId ?? resolveAgentIdFromSessionKey(params.sessionKey);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the caller's explicit session-store scope

When storePath was resolved for one scope but contains keys for another agent—as closeDiscordThreadSessions explicitly expects with its main/work multi-key test—deriving agentId from each key changes the SQLite target after listSessionEntries({ storePath }) read it. A canonical path owned by the original account throws an agent mismatch, while a custom path resolves to another agent-suffixed database, so the listed entry is not deleted. Keep the supplied store's resolved ownership instead of overriding it from sessionKey (extensions/discord/src/monitor/thread-session-close.test.ts:99-121).

Useful? React with 👍 / 👎.

Comment on lines +51 to +54
const deleted = await deleteSessionEntry({
archiveTranscript: true,
expectedSessionId: entry.sessionId ?? null,
expectedUpdatedAt: entry.updatedAt,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid archiving sessions when the deletion guard fails

If a matching thread session changes between listSessionEntries and this guarded delete, the real SQLite lifecycle writes the .deleted.* transcript archive before checking expectedSessionId/expectedUpdatedAt, then returns without deleting when the guard fails (src/config/sessions/session-accessor.sqlite-lifecycle.ts:208-230). This leaves a false archive of a still-active session on every such race; the new concurrent-update test uses a mock and therefore misses the filesystem side effect. Validate the snapshot before requesting archive materialization, or clean up the materialized archive on rejection.

Useful? React with 👍 / 👎.

@steipete steipete self-assigned this Jul 19, 2026
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. labels Jul 19, 2026
@clawsweeper

clawsweeper Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

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

Summary
This PR changes unconfigured sessions from implicit daily rollover to no automatic reset, adds the none reset mode, and changes Discord thread close to guarded lifecycle deletion with accompanying docs and tests.

PR surface: Source +17, Tests +237, Docs +4. Total +258 across 27 files.

Reproducibility: yes. from source: resolve an explicit store path containing an entry whose session key resolves to another agent, then call guarded deletion; the derived agent scope can diverge from the already-read store. The archive-on-rejected-guard race is also source-reproducible through a concurrent entry replacement between listing and delete.

Review metrics: 1 noteworthy metric.

  • Session-default surface: 1 default changed; 1 reset mode added. Changing the unconfigured policy from daily to none changes existing-session continuity on upgrade, while none expands the public configuration contract.

Stored data model
Persistent data-model change detected: migration/backfill/repair: docs/plugins/sdk-runtime.md, serialized state: src/agents/command/session.provider-owned-reset.test.ts, serialized state: src/auto-reply/reply/session.test.ts, serialized state: src/config/sessions/reset-policy.test.ts, serialized state: src/config/sessions/reset-policy.ts, serialized state: src/config/sessions/session-accessor.sqlite-contract.ts, and 9 more. Migration or upgrade compatibility proof is recorded; maintainers should verify it before merge.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🧂 unranked krab
Patch quality: 🦐 gold shrimp
Result: blocked until 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:

  • [P1] Fix both guarded-deletion defects with focused regression coverage.
  • [P1] Add redacted after-fix runtime evidence for the three user-visible session paths.
  • Obtain explicit maintainer confirmation of the upgrade-default policy.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body provides tests and checks but no after-fix live runtime artifact; add redacted terminal output, logs, or a recording that demonstrates default continuity, explicit rollover, and Discord thread-close behavior, then update the PR body for re-review.

Risk before merge

  • [P1] Changing the default from daily rollover to indefinite rolling continuity changes upgrade behavior for every unconfigured session; maintainers should explicitly confirm that this is the intended default while preserving clear opt-in daily and idle policies.

Maintainer options:

  1. Repair lifecycle safety before merge (recommended)
    Preserve a caller-supplied store scope during deletion and validate the guarded snapshot before materializing transcript archival side effects.
  2. Pause the default-policy change
    Do not merge the new default if maintainers do not want existing unconfigured sessions to retain continuity across the former daily boundary.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Preserve explicit store ownership in deleteSessionEntry, ensure rejected optimistic deletes cannot archive an active transcript, add focused lifecycle regression coverage, and keep the configured session-reset direction unchanged.

Next step before merge

  • [P1] The maintainer label and global session-default policy require explicit human handling; the contributor must also provide real behavior proof before merge.

Maintainer decision needed

  • Question: Should OpenClaw adopt session.reset.mode: "none" as the upgrade default for all previously unconfigured sessions after the lifecycle defects are corrected?
  • Rationale: This is a deliberate global compatibility and session-continuity policy change; tests can verify mechanics but cannot choose the desired default for existing operators.
  • Likely owner: steipete — The PR states the direction is owner-approved and steipete authored the current session-reset implementation changes.
  • Options:
    • Adopt rolling continuity by default (recommended): Keep the none default after the two lifecycle fixes and after real runtime evidence shows explicit daily and idle policies continue to roll sessions correctly.
    • Retain daily rollover as the default: Keep current unconfigured-session behavior and offer rolling continuity only through an explicit configuration choice.

Security
Cleared: The reviewed diff changes session policy and lifecycle handling but does not add dependency, workflow, permissions, secret, artifact-download, or supply-chain execution surfaces.

Review findings

  • [P2] Preserve the caller-resolved session-store scope — src/plugin-sdk/session-store-runtime.ts:498-508
  • [P2] Validate deletion guards before archiving transcripts — extensions/discord/src/monitor/thread-session-close.ts:50-57
Review details

Best possible solution:

Keep the new default only after preserving caller-supplied store ownership, making guarded thread-close deletion side-effect-free on rejection, and adding redacted real-runtime proof for default continuity, explicit reset modes, and Discord thread close.

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

Yes, from source: resolve an explicit store path containing an entry whose session key resolves to another agent, then call guarded deletion; the derived agent scope can diverge from the already-read store. The archive-on-rejected-guard race is also source-reproducible through a concurrent entry replacement between listing and delete.

Is this the best way to solve the issue?

No. The session-default direction may be viable, but the current deletion helper must honor caller-resolved storage scope and make optimistic guard rejection free of archival side effects before it is a safe implementation.

Full review comments:

  • [P2] Preserve the caller-resolved session-store scope — src/plugin-sdk/session-store-runtime.ts:498-508
    When storePath is supplied, deriving agentId from each session key and forwarding it to the lifecycle accessor overrides the scope that was used to list entries. A store containing entries from another agent can therefore fail ownership validation or delete from a different target. Only infer an agent id when resolving the store path, or otherwise retain the caller-provided scope.
    Confidence: 0.97
  • [P2] Validate deletion guards before archiving transcripts — extensions/discord/src/monitor/thread-session-close.ts:50-57
    closeDiscordThreadSessions asks for transcript archival while relying on expectedSessionId and expectedUpdatedAt to reject concurrent replacements. The lifecycle implementation can materialize archival output before those guards reject the delete, leaving a false archive for a still-active session. Check the snapshot before archival materialization or clean up the artifact on rejection.
    Confidence: 0.93

Overall correctness: patch is incorrect
Overall confidence: 0.92

AGENTS.md: found and applied where relevant.

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

Label changes

Label justifications:

  • P2: The PR changes broad session behavior and has two concrete lifecycle defects, but the evidence does not show an emergency outage or data-loss incident.
  • merge-risk: 🚨 compatibility: Previously unconfigured users change from daily rollover to persistent rolling sessions after upgrade.
  • merge-risk: 🚨 session-state: The Discord lifecycle path can target the wrong store scope or archive a session that remains active after a guarded deletion rejection.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🧂 unranked krab and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body provides tests and checks but no after-fix live runtime artifact; add redacted terminal output, logs, or a recording that demonstrates default continuity, explicit rollover, and Discord thread-close behavior, then update the PR body for re-review.
Evidence reviewed

PR surface:

Source +17, Tests +237, Docs +4. Total +258 across 27 files.

View PR surface stats
Area Files Added Removed Net
Source 10 63 46 +17
Tests 10 316 79 +237
Docs 7 22 18 +4
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 27 401 143 +258

What I checked:

  • Caller-resolved store scope is still overridden: The current implementation derives an agent id from every session key and passes it to the lifecycle delete even when the caller already supplied a resolved storePath; cross-agent entries read from that store can therefore target a different SQLite scope or fail ownership validation instead of being deleted. (src/plugin-sdk/session-store-runtime.ts:498, 4cd755c347a1)
  • Archive side effect remains ahead of deletion rejection: The Discord close path requests transcript archiving together with optimistic deletion guards, while the prior review identified that the SQLite lifecycle path materializes the archive before guard rejection. The current PR changes guard values but does not show a pre-archive validation or rejected-archive cleanup path. (extensions/discord/src/monitor/thread-session-close.ts:50, 4cd755c347a1)
  • Prior review findings remain applicable: Both current concerns match the two review comments on the earlier reviewed head: preserve caller-resolved store scope and avoid archiving a concurrently replaced active session. The supplied current diff still forwards a derived agent id and still requests archiveTranscript: true with snapshot guards. (src/plugin-sdk/session-store-runtime.ts:498, 4cd755c347a1)
  • Real behavior evidence is not in the PR body: The PR body reports focused tests, typechecks, SDK checks, formatting, and CI, but it does not contain a redacted live terminal capture, runtime log, recording, or linked artifact demonstrating rolling continuity, opt-in rollover, and Discord thread-close behavior after the change. (4cd755c347a1)
  • Configuration default changes are deliberate and documented: The diff changes DEFAULT_RESET_MODE to none, documents daily and idle policies as opt-in, and expands the public session-reset mode union; this is a user-visible upgrade behavior change rather than a test-only refactor. (src/config/sessions/reset-policy.ts:24, 4cd755c347a1)

Likely related people:

  • steipete: Authored all five commits on this PR, including the reset-default, tombstone, fallback, and partial-override changes; the PR body also presents the direction as owner-approved. (role: current session-policy change author; confidence: medium; commits: af289bc3ec2c, ec71a36286a7, fcd3a4f12b44; files: src/config/sessions/reset-policy.ts, src/plugin-sdk/session-store-runtime.ts, extensions/discord/src/monitor/thread-session-close.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.
Review history (1 earlier review cycle)
  • reviewed 2026-07-19T03:28:17.887Z sha 267c6e9 :: needs real behavior proof before merge. :: [P2] Preserve the caller-resolved session-store scope | [P2] Check deletion guards before archiving the transcript

@steipete
steipete force-pushed the claude/no-auto-reset-default branch from 267c6e9 to 4cd755c Compare July 19, 2026 04:41
@openclaw-barnacle openclaw-barnacle Bot added commands Command implementations agents Agent runtime and tooling size: L and removed size: M labels Jul 19, 2026
@steipete
steipete merged commit e23dde3 into main Jul 19, 2026
140 of 143 checks passed
@steipete
steipete deleted the claude/no-auto-reset-default branch July 19, 2026 04:50
@steipete

Copy link
Copy Markdown
Contributor Author

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 19, 2026
* feat(config): disable automatic session resets by default

* fix(sessions): honor pending reset tombstones

* test(sessions): align reset coverage with disabled default

* fix(sessions): preserve explicit reset override fallback

* fix(sessions): inherit active mode in partial type resets
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling channel: discord Channel integration: discord commands Command implementations docs Improvements or additions to documentation gateway Gateway runtime maintainer Maintainer-authored PR merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. plugin: file-transfer rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: L 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.

1 participant