Skip to content

fix: clear delivery routing state when creating isolated cron sessions#27778

Merged
Takhoffman merged 2 commits intoopenclaw:mainfrom
delight-co:fix/cron-isolated-session-thread-leak
Feb 28, 2026
Merged

fix: clear delivery routing state when creating isolated cron sessions#27778
Takhoffman merged 2 commits intoopenclaw:mainfrom
delight-co:fix/cron-isolated-session-thread-leak

Conversation

@carrotRakko
Copy link
Contributor

Summary

  • Problem: Cron jobs with sessionTarget: "isolated" inherit lastThreadId from prior session, causing announce deliveries to post as thread replies instead of channel top-level messages.
  • Why it matters: Scheduled reports/notifications get buried in unrelated threads and are easy to miss.
  • What changed: resolveCronSession() now clears delivery routing metadata (lastThreadId, lastTo, lastChannel, lastAccountId) when creating a new session.
  • What did NOT change: Per-session overrides (modelOverride, providerOverride, thinkingLevel, etc.) are still preserved across session resets.

Change Type (select all)

  • Bug fix

Scope (select all touched areas)

  • Gateway / orchestration

Linked Issue/PR

User-visible / Behavior Changes

Cron jobs with sessionTarget: "isolated" and delivery.mode: "announce" will now correctly post to channel top-level instead of inheriting a thread target from prior conversations.

Security Impact (required)

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

Repro + Verification

Environment

  • OS: Amazon Linux 2023 (aarch64)
  • Runtime/container: Node 22, npm global install
  • Integration/channel: Slack (socket mode)

Steps

  1. Have an agent converse in a Slack thread in a channel
  2. Session store records lastThreadId from that thread
  3. A cron job fires with sessionTarget: "isolated", delivery.mode: "announce", delivery.to pointing to the same channel
  4. Observe where the result is posted

Expected

  • Cron result posted as top-level message in the channel

Actual

  • Cron result posted as thread reply to a previous conversation thread

Evidence

  • Failing test/log before + passing after

New test cases in session.test.ts:

  • clears delivery routing metadata when forceNew is true
  • clears delivery routing metadata when session is stale
  • preserves delivery routing metadata when reusing fresh session

Human Verification (required)

  • Verified scenarios: Deployed to production agent, confirmed cron jobs post to channel top-level
  • Edge cases checked: Fresh session reuse still preserves delivery metadata (test coverage)
  • What you did not verify: Matrix/Telegram channel behavior (only Slack tested)

Compatibility / Migration

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

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: Revert the single commit in session.ts
  • Files/config to restore: src/cron/isolated-agent/session.ts
  • Known bad symptoms: If delivery metadata clearing is too aggressive, fresh session reuse might lose routing context (mitigated by only clearing on isNewSession)

Risks and Mitigations

  • Risk: Clearing lastTo/lastChannel might affect non-announce delivery modes that legitimately need prior routing state in new sessions.
    • Mitigation: The clear only applies when isNewSession is true (forceNew or session expired). Fresh session reuse is unaffected. Announce mode is the primary consumer of these fields for cron, and it should always resolve targets from the explicit delivery.to config, not inherited state.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 26, 2026

Greptile Summary

Correctly fixes cron job thread leaking by clearing delivery routing metadata when creating isolated sessions. The implementation uses a conditional spread operator to set lastThreadId, lastChannel, lastTo, and lastAccountId to undefined only when isNewSession is true (either forced new or stale session). This prevents announce-mode cron deliveries from inheriting thread context from prior conversations.

Key implementation details:

  • Preserves per-session overrides (modelOverride, providerOverride, thinkingLevel, etc.) while clearing only delivery routing state
  • Fresh session reuse (when isNewSession is false) correctly preserves routing metadata for continuity
  • Spread operator order ensures proper field overriding: existing entry → core fields → conditional routing clear

Test coverage validates all three scenarios:

  • forceNew=true clears routing but preserves overrides
  • Stale sessions clear routing metadata
  • Fresh session reuse preserves routing metadata

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The fix is well-implemented with comprehensive test coverage. The change is narrowly scoped to clearing delivery routing metadata only when creating new sessions, preserving existing behavior for fresh session reuse. The spread operator usage is correct, and all edge cases are covered by tests.
  • No files require special attention

Last reviewed commit: 3dc2bc5

Copy link

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

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: 3dc2bc5284

ℹ️ 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".

Comment on lines +72 to +76
...(isNewSession && {
lastChannel: undefined,
lastTo: undefined,
lastAccountId: undefined,
lastThreadId: undefined,

Choose a reason for hiding this comment

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

P1 Badge Clear deliveryContext when resetting cron session

When isNewSession is true, this block only unsets legacy last* fields, but session writes are normalized through normalizeSessionEntryDelivery (src/config/sessions/store.ts), which can repopulate lastThreadId/lastTo/... from entry.deliveryContext; additionally, routing reads delivery metadata via deliveryContextFromSession (src/utils/delivery-context.ts). In sessions where deliveryContext.threadId is present (the common normalized shape), stale thread routing survives and announce deliveries can still go to an old thread, so the reset needs to clear deliveryContext (or at least its thread/to/channel fields) together with last*.

Useful? React with 👍 / 👎.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch — fixed in fb18e90. deliveryContext is now also cleared alongside the last* fields when isNewSession is true.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

@delight-ai-agent delight-ai-agent force-pushed the fix/cron-isolated-session-thread-leak branch from fb18e90 to 4c1b797 Compare February 27, 2026 02:57
When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
@delight-ai-agent delight-ai-agent force-pushed the fix/cron-isolated-session-thread-leak branch from 4c1b797 to 4ea8921 Compare February 27, 2026 17:19
Copy link

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

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: 4ea8921fea

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +74 to +79
...(isNewSession && {
lastChannel: undefined,
lastTo: undefined,
lastAccountId: undefined,
lastThreadId: undefined,
deliveryContext: undefined,

Choose a reason for hiding this comment

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

P1 Badge Persist cleared route before delivery target resolution

This change only clears routing fields on the in-memory sessionEntry, but runCronIsolatedAgentTurn resolves delivery via resolveDeliveryTarget before the first persistSessionEntry call, and resolveDeliveryTarget reloads the store from disk. In isolated cron runs that reuse the same sessionKey, stale persisted lastThreadId/deliveryContext can still be read for the current delivery (and then re-written), so announce deliveries can continue posting into an old thread even after this patch.

Useful? React with 👍 / 👎.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the detailed analysis. However, I believe this concern does not apply here due to session key separation.

resolveCronSession clears routing fields on the cron isolated session entry (e.g., cron:some-job:agent:main), while resolveDeliveryTarget looks up the main session entry (via resolveAgentMainSessionKey) or the job configured sessionKey — both of which are different keys from the cron isolated session entry being cleared.

Since resolveDeliveryTarget never reads the cron isolated session entry that this patch modifies, the persist ordering relative to resolveDeliveryTarget does not matter — they operate on different store entries.

Additionally, resolveDeliveryTarget has a guard at L127-131 that only uses a session-derived threadId when resolved.to === resolved.lastTo, preventing stale thread routing from leaking to different delivery targets.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

@Takhoffman Takhoffman merged commit e1df1c6 into openclaw:main Feb 28, 2026
20 of 21 checks passed
vincentkoc pushed a commit to Sid-Qin/openclaw that referenced this pull request Feb 28, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
vincentkoc pushed a commit to rylena/rylen-openclaw that referenced this pull request Feb 28, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
mrosmarin added a commit to mrosmarin/openclaw that referenced this pull request Feb 28, 2026
* main: (31 commits)
  fix(browser): resolve correct targetId in navigate response after renderer swap (openclaw#25326)
  fix: sed escaping and UID mismatch in Podman Quadlet setup (openclaw#26414)
  fix(cron): pass heartbeat target=last for main-session cron jobs (openclaw#28508) (openclaw#28583)
  fix(cron): disable messaging tool when delivery.mode is none (openclaw#21808) (openclaw#21896)
  fix: clear delivery routing state when creating isolated cron sessions (openclaw#27778)
  fix(cron): avoid marking queued announce paths as delivered (openclaw#29716)
  fix(cron): enable completion direct send for text-only announce delivery (openclaw#29151)
  fix(cron): force main-target system events onto main session (openclaw#28898)
  fix(cron): condition requireExplicitMessageTarget on resolved delivery (openclaw#28017)
  feat(cron): add --account flag for multi-account delivery routing (openclaw#26284)
  fix: schedule nextWakeAtMs for isolated sessionTarget cron jobs (openclaw#19541)
  fix: sandbox browser docker no-sandbox rollout (openclaw#29879) (thanks @Lukavyi)
  GitHub: add regression bug issue template and routing (openclaw#29864) thanks @Takhoffman
  feat(feishu): add chat info/member tool (openclaw#14674)
  feat(feishu): add markdown tables, positional insert, color_text, and table ops (openclaw#29411)
  feat(feishu): add parent/root inbound context for quote support (openclaw#18529)
  fix: land android onboarding and voice reliability updates (openclaw#29796)
  fix(android-voice): rotate playback token per assistant reply
  fix(android-voice): retry talk config after transient failures
  fix(android-voice): cancel in-flight speech when speaker muted
  ...
newtontech pushed a commit to newtontech/openclaw-fork that referenced this pull request Feb 28, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
nsd97 pushed a commit to nsd97/openclaw that referenced this pull request Feb 28, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Mar 1, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Mar 1, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
hughdidit pushed a commit to hughdidit/DAISy-Agency that referenced this pull request Mar 1, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

(cherry picked from commit e1df1c6)

# Conflicts:
#	src/cron/isolated-agent/session.test.ts
#	src/cron/isolated-agent/session.ts
@delight-ai-agent delight-ai-agent deleted the fix/cron-isolated-session-thread-leak branch March 1, 2026 10:34
zooqueen added a commit to hanzoai/bot that referenced this pull request Mar 1, 2026
openclaw#27778)

Cherry-pick from upstream openclaw/openclaw e1df1c6.
Ports full session reuse logic with freshness evaluation.
Clears lastThreadId/deliveryContext on new sessions to prevent
announce-mode deliveries from posting as thread replies.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ansh pushed a commit to vibecode/openclaw that referenced this pull request Mar 2, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
steipete pushed a commit to Sid-Qin/openclaw that referenced this pull request Mar 2, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
safzanpirani pushed a commit to safzanpirani/clawdbot that referenced this pull request Mar 2, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
steipete pushed a commit to Sid-Qin/openclaw that referenced this pull request Mar 2, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
robertchang-ga pushed a commit to robertchang-ga/openclaw that referenced this pull request Mar 2, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
execute008 pushed a commit to execute008/openclaw that referenced this pull request Mar 2, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
hughdidit pushed a commit to hughdidit/DAISy-Agency that referenced this pull request Mar 3, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

(cherry picked from commit e1df1c6)

# Conflicts:
#	src/cron/isolated-agent/session.test.ts
#	src/cron/isolated-agent/session.ts
dorgonman pushed a commit to kanohorizonia/openclaw that referenced this pull request Mar 3, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
hughdidit pushed a commit to hughdidit/DAISy-Agency that referenced this pull request Mar 3, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

(cherry picked from commit e1df1c6)

# Conflicts:
#	src/cron/isolated-agent/session.test.ts
#	src/cron/isolated-agent/session.ts
dorgonman pushed a commit to kanohorizonia/openclaw that referenced this pull request Mar 3, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
sachinkundu pushed a commit to sachinkundu/openclaw that referenced this pull request Mar 6, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
zooqueen added a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
openclaw#27778)

Cherry-pick from upstream openclaw/openclaw e1df1c6.
Ports full session reuse logic with freshness evaluation.
Clears lastThreadId/deliveryContext on new sessions to prevent
announce-mode deliveries from posting as thread replies.
zooqueen pushed a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
Mateljan1 pushed a commit to Mateljan1/openclaw that referenced this pull request Mar 7, 2026
openclaw#27778)

* fix: clear delivery routing state when creating isolated cron sessions

When `resolveCronSession()` creates a new session (forceNew / isolated),
the `...entry` spread preserves `lastThreadId`, `lastTo`, `lastChannel`,
and `lastAccountId` from the prior session. This causes announce-mode
cron deliveries to post as thread replies instead of channel top-level
messages when `delivery.to` matches the channel of a prior conversation.

Clear delivery routing metadata on new session creation so isolated
cron sessions start with a clean delivery state.

Closes openclaw#27751

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

* fix: also clear deliveryContext to prevent lastThreadId repopulation

normalizeSessionEntryDelivery (called on store writes) repopulates
lastThreadId from deliveryContext.threadId. Clearing only the last*
fields is insufficient — deliveryContext must also be cleared when
creating a new isolated session.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Cron announce delivery posts to Slack thread instead of channel top-level when session has prior thread context

2 participants