Skip to content

fix(cron): refuse keyless implicit isolated cron delivery inherited from shared agent-main bucket#91685

Merged
clawsweeper[bot] merged 5 commits into
openclaw:mainfrom
nxmxbbd:fix/91613-isolated-cron-delivery-identity
Jun 19, 2026
Merged

fix(cron): refuse keyless implicit isolated cron delivery inherited from shared agent-main bucket#91685
clawsweeper[bot] merged 5 commits into
openclaw:mainfrom
nxmxbbd:fix/91613-isolated-cron-delivery-identity

Conversation

@nxmxbbd

@nxmxbbd nxmxbbd commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Summary

A keyless / implicit isolated cron — no sessionKey, no sessionTarget, delivery.channel=last, no delivery.to — resolves its delivery target from the shared agent:<id>:main session bucket's lastTo. That value is last-writer-wins across every conversation the agent handles, so the cron's reply is delivered to whichever room last wrote main, and the durable delivery queue replays it there after a restart (#91613).

This change makes resolveDeliveryTarget return ok:false for that case instead of returning the inherited target.

Root cause

  1. For a keyless implicit cron, resolveDeliveryTarget (src/cron/isolated-agent/delivery-target.ts) finds no per-job target and no own session/delivery context, and falls back to the shared agent:<id>:main entry, returning that bucket's lastTo. The condition is main === mainEntry with no stored or thread context (usedSharedMainFallback).
  2. Durable recovery (recoverPendingDeliveries) replays a stored entry's to verbatim with no staleness, boot-id, or room gate, so the resolved target survives a restart.
  3. The Matrix send is faithful to the to it is given; the divergence is at resolution.

A keyless cron carries no turn-source and no persisted creator-session, so there is no provenance to anchor the inherited target against.

Change

resolveDeliveryTarget returns ok:false for the keyless-inherited case. Its four consumers — delivery dispatch, the failure-notification path (src/cron/delivery.ts), the run delivery context, and the delivery preview — already branch on ok:false, so each refuses uniformly. The dispatch !ok gate refuses the send before the durable enqueue, so recovery has no entry to replay.

Predicate, evaluated after the allowFrom reroute:

!rawSessionKey            // keyless only
&& mode === "implicit"
&& !explicitTo
&& usedSharedMainFallback // target came only from the shared agent-main bucket
&& toCandidate === resolved.lastTo

resolveCronDeliveryContext resolves the job's session identity through resolveCronDeliverySessionKey (sessionTarget then sessionKey), matching the existing delivery-preview and failure-notification callers, so a sessionTarget-scoped cron resolves through its own session rather than the keyless path.

Prior art in this repo

  • Wrong-target / cross-conversation routing is fixed elsewhere by matching a candidate against turn or session provenance: fix(telegram): forum topic replies route to root chat + ACP spawn fails from forum topics #56060 restored forum-topic routing via turnToMatchesSession, and fix(reply): preserve sessions_send external routes #88803 preserved sessions_send routes via inter-session provenance. A timer-fired keyless cron has no inbound turn and no persisted creator-session to match against, so this change fails closed on the ambiguity instead of matching.
  • resolveDeliveryTarget already returns ok:false for other unresolvable targets; this adds one case to that existing contract rather than a new field or mechanism.
  • Persisted creator provenance already exists for other job types: tasks and subagents store requesterSessionKey / requesterOrigin. A keyless cron stores no equivalent, so the same match-on-provenance approach is not available without adding that field and a migration; this change does not add them.
  • Related open work: fix(cron): keep no-channel implicit cron runs successful instead of failing delivery (#56078) #91399 changes the same dispatch !ok branch so an implicit announce-to-last cron with no resolvable channel finishes as a silent success, while keeping a hard failure when a channel resolved but its target did not. The keyless-inherited refusal added here fires only after a channel has resolved, so it always returns ok:false with the channel populated and only the target withheld — it falls into that branch's channel-resolved-but-failed case and stays a hard failure under either merge order. The separate no-resolvable-channel case (a different ok:false return in resolveDeliveryTarget, channel undefined) is not reached by this predicate and is the silent path fix(cron): keep no-channel implicit cron runs successful instead of failing delivery (#56078) #91399 governs.

Behavior change

A keyless cron that previously delivered to the shared bucket's last room is now refused, including in a single-conversation deployment where that room was the intended target. Such a cron must set delivery.channel and delivery.to, or run from a session that carries its own delivery context; the error names the cause. A channel-only keyless cron ({channel, to:undefined}) whose to still resolves from the bucket is also refused. A keyed cron whose thread entry is missing is unaffected — the predicate is keyless-only.

Real behavior proof

  • Behavior or issue addressed: a keyless implicit isolated cron no longer delivers to the shared-bucket's last room, and no entry is enqueued to replay after a restart.
  • Real environment tested: an isolated throwaway Matrix homeserver (Synapse in Docker, RFC-reserved server_name, loopback bind only, federation disabled). Two rooms: A (intended) and B (wrong). The shared agent-main bucket's lastTo is set to room B.
  • Exact steps or command run after this patch: (1) primary reply — drive the patched resolveDeliveryTarget for a keyless implicit cron against the poisoned bucket; enqueue only if it returns ok:true; run recoverPendingDeliveries over the on-disk queue against the live homeserver; read both rooms over the Matrix client-server API. (2) failure notice — drive the patched sendFailureNotificationAnnounce (src/cron/delivery.ts) for the same keyless target with the leaf send primitive (sendDurableMessageBatch) wired to perform a real send to whatever room it is handed; read room B over the client-server API.
  • Evidence after fix:
resolveDeliveryTarget(keyless, inherited) -> ok:false
pending delivery queue                    -> 0 entries
recoverPendingDeliveries                  -> recovered:0 (deliver callback never fired)
room B (wrong) over C-S API               -> this run's marker absent
room A (intended) over C-S API            -> unchanged

Before this change, the same harness drained a queued reply to room B: a per-run marker appeared in room B and never in room A.

  • Evidence after fix (failure notice):
resolveDeliveryTarget(keyless, inherited) -> ok:false
sendFailureNotificationAnnounce            -> returns without calling the send primitive
room B (wrong) over C-S API                -> this run's failure-notice marker absent

The send primitive was wired to perform a real send to whatever room it received, so a send would have reached room B; it was never called.

  • Observed result after fix: the keyless cron is refused at the dispatch !ok gate; no message reaches the wrong room and no durable entry is written. The failure notice for the same cron resolves ok:false and is logged rather than delivered, so the wrong room receives neither the reply nor the failure notice.
  • What was not tested: a federation / multi-homeserver path (the defect is at resolution, before transport); the persisted-provenance approach above.

Regression tests

  • Resolver: keyless-inherited → ok:false; explicit to, keyed cron, and allowFrom-rerouted-to-allowed-peer still deliver; channel-only-keyless → refused.
  • Run layer: resolveCronDeliveryContext passes ok:false through and resolves sessionTarget into the resolver's session key.
  • Integration: a real cron turn for a keyless implicit cron returns status error (errorKind: delivery-target), does not deliver, and queues no main-session awareness event.
  • Two resolver tests that asserted delivery to the inherited room are updated to ok:false; the awareness-suppression path they also exercised remains covered by an existing dispatch test.
  • Dispatch cleanup: a refused (ok:false) keyless cron with deleteAfterRun retires its session via sessions.delete before returning, in both the non-best-effort (status error) and best-effort (status ok) paths, so a one-shot cron does not leak its session or transcript on the fail-closed path.
  • Full src/cron suite after this conflict repair: 106 files / 1075 tests pass.

Security and compatibility

  • Closes a cross-conversation delivery of a cron's reply and, through the same resolver, its failure notice, and the restart replay of both.
  • No schema, config, or public-type change. The ok:false resolver result variant already existed.
  • Behavior change for keyless crons as described above.

Notes

  • A refused keyless cron still runs its agent turn before delivery is refused at the dispatch gate, matching the current handling of other unresolvable cron targets. The failure notice for such a cron is logged rather than delivered.

AI-assisted; the contributor reviewed the change and is responsible for it.

@openclaw-barnacle openclaw-barnacle Bot added size: M proof: supplied External PR includes structured after-fix real behavior proof. labels Jun 9, 2026
@clawsweeper

clawsweeper Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Codex review: passed. Reviewed June 19, 2026, 2:31 AM ET / 06:31 UTC.

Summary
The PR changes isolated cron delivery resolution to reject keyless implicit delivery inherited from the shared agent-main bucket, carries derived session targets into delivery context resolution, and cleans up direct cron sessions on unresolved delivery exits.

PR surface: Source +57, Tests +496. Total +553 across 8 files.

Reproducibility: yes. from source inspection: current resolver can inherit the shared agent-main last target for keyless implicit cron delivery, and dispatch hard-fails or sends based on that resolved target; I did not run live Matrix reproduction in this read-only review.

Review metrics: 2 noteworthy metrics.

  • Implicit cron fallback behavior: 1 fail-closed resolver path added. This is the concrete upgrade-sensitive behavior change maintainers need to accept before merge.
  • Patch surface: 2 production files changed, 6 test files changed. The runtime change is narrow, but the test footprint covers resolver, run-layer, dispatch cleanup, and delivery-awareness outcomes.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #91613
Summary: this PR is a candidate fix for the keyless implicit cron delivery slice of #91613, while broader restart queue replay hardening remains on the canonical issue.

Members:

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

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

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

Risk before merge

Maintainer options:

  1. Accept Fail-Closed Keyless Cron Delivery (recommended)
    Merge the resolver guard as the narrow high-risk leak mitigation and track broader restart queue hardening on [Bug] Gateway reply-queue state not flushed on restart — stale queued replies drain to wrong Matrix room after restart #91613.
  2. Require Explicit Upgrade Guidance
    Before merge, add maintainer-visible release-note or docs guidance for operators whose keyless cron jobs must now specify an explicit delivery target or session context.
  3. Pause For Broader Queue Design
    Defer this PR if maintainers want startup queue flushing, TTL, or transport-layer room checks to be designed before changing resolver behavior.

Next step before merge

  • [P1] Maintainers need to explicitly accept the fail-closed upgrade behavior; there is no concrete code repair finding for ClawSweeper to make.

Security
Cleared: The diff does not add dependencies, CI, scripts, secret handling, or broader code execution paths, and it narrows a security-relevant wrong-room delivery mode.

Review details

Best possible solution:

Land this only if maintainers intentionally accept fail-closed keyless implicit cron delivery, while keeping #91613 open for the broader restart replay hardening.

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

Yes from source inspection: current resolver can inherit the shared agent-main last target for keyless implicit cron delivery, and dispatch hard-fails or sends based on that resolved target; I did not run live Matrix reproduction in this read-only review.

Is this the best way to solve the issue?

Mostly yes: the patch is the narrowest resolver-level guard for the demonstrated keyless inherited path, but the broader #91613 restart queue problem still needs maintainer-owned follow-up.

AGENTS.md: found and applied where relevant.

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

Label changes

Label changes:

  • add rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • add status: 🚀 automerge armed: This PR is in ClawSweeper's automerge lane. Sufficient (live_output): The PR body includes structured after-fix Matrix/Synapse proof for the keyless shared-main cron route, including observed refusal and absence of queued recovery delivery.
  • remove rating: 🐚 platinum hermit: Current PR rating is rating: 🦞 diamond lobster, so this older rating label is no longer current.
  • remove status: 👀 ready for maintainer look: Current PR status label is status: 🚀 automerge armed.

Label justifications:

  • P1: The PR targets a wrong-room cron delivery path that can expose agent output across conversations and affects real channel workflows.
  • merge-risk: 🚨 compatibility: Failing closed changes behavior for existing keyless or channel-only cron jobs that previously inherited a shared main target.
  • merge-risk: 🚨 message-delivery: The change intentionally suppresses delivery in one implicit fallback case to prevent wrong-room sends, so maintainers must accept the delivery tradeoff.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 🚀 automerge armed: This PR is in ClawSweeper's automerge lane. Sufficient (live_output): The PR body includes structured after-fix Matrix/Synapse proof for the keyless shared-main cron route, including observed refusal and absence of queued recovery delivery.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes structured after-fix Matrix/Synapse proof for the keyless shared-main cron route, including observed refusal and absence of queued recovery delivery.
Evidence reviewed

PR surface:

Source +57, Tests +496. Total +553 across 8 files.

View PR surface stats
Area Files Added Removed Net
Source 3 59 2 +57
Tests 5 502 6 +496
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 8 561 8 +553

Acceptance criteria:

What I checked:

  • PR status and maintainer signal: Live PR metadata showed this PR is open, cleanly mergeable, maintainer-can-modify, labeled with supplied/sufficient proof and automerge signals after a maintainer posted an automerge command. (f129375dd77d)
  • Current resolver fallback: On current main, delivery-target resolution falls back through stored delivery, thread entry, and the shared main entry, so an implicit cron without a raw session key can inherit a shared main last target. (src/cron/isolated-agent/delivery-target.ts:135, 928b5932a386)
  • PR resolver guard: The PR adds a shared-main fallback detector and returns an unresolved delivery error only for keyless implicit delivery without an explicit target when the resolved target came from the shared agent-main bucket. (src/cron/isolated-agent/delivery-target.ts:303, f129375dd77d)
  • Current hard-fail behavior: Current dispatch treats unresolved non-best-effort delivery as a hard delivery-target failure, so the new resolver refusal intentionally changes delivery outcome rather than silently preserving previous inheritance. (src/cron/isolated-agent/delivery-dispatch.ts:1220, 928b5932a386)
  • PR cleanup and run-context changes: The PR exports the cron delivery context helper, passes the derived cron delivery session key, and adds cleanup before unresolved delivery returns so direct delete-after-run sessions do not leak. (src/cron/isolated-agent/run.ts:370, f129375dd77d)
  • Sibling surfaces inspected: Delivery preview and failure-announcement paths also call resolveDeliveryTarget, while outbound target resolution inherits lastTo when no explicit target exists, so the guard is on the shared resolver path rather than only the run path. (src/cron/delivery-preview.ts:54, 928b5932a386)

Likely related people:

  • steipete: Peter Steinberger appears on major cron delivery target history including delivery target unification and hardening work that shaped the current resolver path. (role: feature-history owner; confidence: high; commits: ccea3a0615e5, bf373eeb439e, 7a40d99b1d4d; files: src/cron/isolated-agent/delivery-target.ts, src/cron/isolated-agent/delivery-dispatch.ts)
  • vincentkoc: Current-line blame and recent cron delivery maintenance point to Vincent Koc as a recent contributor around the affected main branch code. (role: recent area contributor; confidence: high; commits: a619518ebe, 28787985, 8f3e2296; files: src/cron/isolated-agent/delivery-target.ts, src/cron/isolated-agent/run.ts)
  • shakkernerd: Shakker is tied to delivery target runtime seam refactors adjacent to the resolver and dispatch surfaces touched by the PR. (role: adjacent refactor contributor; confidence: medium; commits: 24edb82e, 1a23627e, de952c03; files: src/cron/isolated-agent/delivery-target.ts)
  • Takhoffman: Tak Hoffman is linked to allowFrom implicit routing behavior that the PR intentionally preserves as a sibling case. (role: adjacent behavior contributor; confidence: medium; commits: d9e46028, 50d996a; files: src/cron/isolated-agent/delivery-target.ts)
  • tyler6204: Tyler Yust appears in the isolated cron delivery mode and flow history that established the surrounding delivery behavior. (role: early isolated cron delivery contributor; confidence: medium; commits: 511c656c, 8fae55e8; files: src/cron/isolated-agent/delivery-target.ts, src/cron/isolated-agent/run.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 proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P1 High-priority user-facing bug, regression, or broken workflow. labels Jun 9, 2026
…rom shared agent-main bucket

A keyless/implicit isolated cron (no sessionKey/sessionTarget, delivery.channel=last,
no delivery.to) resolved its target from the SHARED agent:<id>:main bucket's lastTo, a
last-writer-wins value across every conversation the agent handles. Its reply drained to
whichever room last wrote main (the wrong room), and the durable delivery queue replayed
it there after a restart.

resolveDeliveryTarget now returns ok:false for the narrowed keyless-inherited case
(keyless only; compared after the allowFrom reroute), so the delivery dispatch !ok gate,
the failure-notification path, and the delivery preview all honor the refusal through one
canonical path instead of a flag each caller must remember to check. The dispatch gate
refuses the send without reaching the durable enqueue, so recovery has nothing to replay.
resolveCronDeliveryContext resolves the job's own session identity (sessionTarget over
sessionKey, matching delivery preview and the failure-notification path) so a
session-scoped cron is not misread as keyless.

Adds resolver refusal plus negative (allowFrom-rerouted / keyed / channel-only) tests and
an integration test proving the keyless case is refused with no main-session awareness leak.

This refuses a keyless cron that previously delivered to main's last room even in a
single-conversation deployment; such crons must now pin delivery.channel/delivery.to or run
from a session that carries its own delivery context. The agent turn still runs and its
reply is then dropped with a logged delivery-target error (consistent with how other
unresolvable cron targets are handled today). Surfaced for the needs-product-decision.
@nxmxbbd nxmxbbd force-pushed the fix/91613-isolated-cron-delivery-identity branch from 83dfb00 to 88b6412 Compare June 9, 2026 11:42
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 9, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 9, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 9, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 9, 2026
… is refused

The keyless-implicit refusal path (resolveDeliveryTarget -> ok:false) returns
from dispatchCronDelivery before reaching the direct/silent delivery paths that
retire a deleteAfterRun cron session, so a one-shot cron hitting the fail-closed
branch left its session and transcript behind.

Call cleanupDirectCronSessionIfNeeded() before both returns in the !ok branch;
it is a no-op for non-deleteAfterRun and non-cron sessions. Add regression tests
covering the non-best-effort (status error) and best-effort (status ok) refusal
paths.
@nxmxbbd nxmxbbd force-pushed the fix/91613-isolated-cron-delivery-identity branch from 8ee9b65 to 44214d2 Compare June 9, 2026 13:04
@openclaw-barnacle openclaw-barnacle Bot added size: L and removed size: M proof: sufficient ClawSweeper judged the real behavior proof convincing. labels Jun 9, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 9, 2026
…cron-delivery-identity

# Conflicts:
#	src/cron/isolated-agent/delivery-target.test.ts
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 14, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 14, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 15, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 15, 2026
@vincentkoc

Copy link
Copy Markdown
Member

/clownfish automerge

@openclaw-clownfish openclaw-clownfish Bot added clownfish:automerge Maintainer opted this Clownfish PR into bounded ClawSweeper-reviewed automerge clawsweeper:automerge Maintainer opted this PR into bounded ClawSweeper-reviewed automerge labels Jun 19, 2026
@openclaw-clownfish

Copy link
Copy Markdown
Contributor

Clownfish is on the reef for this PR. 🐠

I tagged clownfish:automerge and sent ClawSweeper over this exact head. If the sweep finds rough coral, failing checks, or needs-human, I will take another bounded repair lap and ask for a fresh review.

A maintainer can call /clownfish stop any time and I will drift this back to human review.

@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 🚀 automerge armed This PR is in ClawSweeper's automerge lane. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 19, 2026
@clawsweeper clawsweeper Bot merged commit d4833e2 into openclaw:main Jun 19, 2026
209 of 216 checks passed
@clawsweeper

clawsweeper Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper automerge is enabled.

  • Head: f129375dd77d
  • Label: clawsweeper:automerge
  • Action: exact-head review queued (workflow sweep.yml, event repository_dispatch).
  • Flow: review this head, repair/rebase only if needed, then re-review the exact repaired head before merge.

Draft PRs stay fix-only until GitHub marks them ready for review. Pause with /clawsweeper stop.

Automerge progress:

  • 2026-06-19 06:32:17 UTC review passed f129375dd77d (structured ClawSweeper verdict: pass (sha=f129375dd77d6b53533034836393f2706f20a...)
  • 2026-06-19 10:05:11 UTC merged f129375dd77d (merged by ClawSweeper automerge)
  • 2026-06-19 10:05:20 UTC review queued f129375dd77d (queued)

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 20, 2026
…rom shared agent-main bucket (openclaw#91685)

Summary:
- The PR changes isolated cron delivery resolution to reject keyless implicit delivery inherited from the shar ...  targets into delivery context resolution, and cleans up direct cron sessions on unresolved delivery exits.
- PR surface: Source +57, Tests +496. Total +553 across 8 files.
- Reproducibility: yes. from source inspection: current resolver can inherit the shared agent-main last target ... ls or sends based on that resolved target; I did not run live Matrix reproduction in this read-only review.

Automerge notes:
- PR branch already contained follow-up commit before automerge: fix(cron): clean up deleteAfterRun session when keyless cron delivery…
- PR branch already contained follow-up commit before automerge: Merge remote-tracking branch 'upstream/main' into fix/91613-isolated-…
- PR branch already contained follow-up commit before automerge: Merge upstream main into fix/91613-isolated-cron-delivery-identity
- PR branch already contained follow-up commit before automerge: chore: retrigger PR CI after upstream base fix

Validation:
- ClawSweeper review passed for head f129375.
- Required merge gates passed before the squash merge.

Prepared head SHA: f129375
Review: openclaw#91685 (comment)

Co-authored-by: nxmxbbd <32288+nxmxbbd@users.noreply.github.com>
openperf added a commit to openperf/moltbot that referenced this pull request Jun 25, 2026
…ion id

Isolated cron runs carry a per-run :run:<id> session scope (openclaw#91685) rendered
verbatim into the cached system-prompt Runtime line, re-busting byte-exact
prefix caching for the tool catalog after it every run (openclaw#96677, openclaw#43148 class).
buildRuntimeLine now renders the stable base session key and drops the per-run
id the run scope duplicates; parseCronRunScopeSuffix is gated to the
isolated-cron key shape so a :run: segment in any other session key is never
truncated.
jiahjian added a commit to jiahjian/openclaw that referenced this pull request Jun 28, 2026
…enclaw#96677)

Isolated cron and heartbeat runs include a per-run UUID in the
session key (e.g. :run:e3f4a5b6-...). Since buildRuntimeLine embeds
the full sessionKey verbatim into the cached system prefix, every
invocation produces a different Runtime line — breaking prompt
prefix caching for all content after it, including the tool catalog.

Strip :run:<uuid> segments from the session key at render time so
the Runtime line is byte-stable across cron/heartbeat invocations.
This restores prefix caching and avoids ~10x cost increase on
metered providers.

Regression: openclaw#91685 added per-run session key isolation which
correctly prevents cross-run delivery leakage, but rendered the
sessionKey into the cached prompt without cache-aware stripping.

Fixes openclaw#96677.

Co-Authored-By: Claude <noreply@anthropic.com>
jiahjian added a commit to jiahjian/openclaw that referenced this pull request Jun 28, 2026
…enclaw#96677)

Isolated cron and heartbeat runs include a per-run UUID in the
session key (e.g. :run:e3f4a5b6-...). Since buildRuntimeLine embeds
the full sessionKey verbatim into the cached system prefix, every
invocation produces a different Runtime line — breaking prompt
prefix caching for all content after it, including the tool catalog.

Strip :run:<uuid> segments from the session key at render time so
the Runtime line is byte-stable across cron/heartbeat invocations.
This restores prefix caching and avoids ~10x cost increase on
metered providers.

Regression: openclaw#91685 added per-run session key isolation which
correctly prevents cross-run delivery leakage, but rendered the
sessionKey into the cached prompt without cache-aware stripping.

Fixes openclaw#96677.

Co-Authored-By: Claude <noreply@anthropic.com>
steipete pushed a commit to openperf/moltbot that referenced this pull request Jul 9, 2026
…ion id

Isolated cron runs carry a per-run :run:<id> session scope (openclaw#91685) rendered
verbatim into the cached system-prompt Runtime line, re-busting byte-exact
prefix caching for the tool catalog after it every run (openclaw#96677, openclaw#43148 class).
buildRuntimeLine now renders the stable base session key and drops the per-run
id the run scope duplicates; parseCronRunScopeSuffix is gated to the
isolated-cron key shape so a :run: segment in any other session key is never
truncated.
steipete added a commit that referenced this pull request Jul 9, 2026
…ion id (#96686)

* fix(agents): isolated cron busts prompt prefix cache via per-run session id

Isolated cron runs carry a per-run :run:<id> session scope (#91685) rendered
verbatim into the cached system-prompt Runtime line, re-busting byte-exact
prefix caching for the tool catalog after it every run (#96677, #43148 class).
buildRuntimeLine now renders the stable base session key and drops the per-run
id the run scope duplicates; parseCronRunScopeSuffix is gated to the
isolated-cron key shape so a :run: segment in any other session key is never
truncated.

* fix(agents): preserve mixed-case cron run markers

* test(agents): cover rotated cron session identity

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Simon-XYDT pushed a commit to Simon-XYDT/openclaw that referenced this pull request Jul 9, 2026
…ion id (openclaw#96686)

* fix(agents): isolated cron busts prompt prefix cache via per-run session id

Isolated cron runs carry a per-run :run:<id> session scope (openclaw#91685) rendered
verbatim into the cached system-prompt Runtime line, re-busting byte-exact
prefix caching for the tool catalog after it every run (openclaw#96677, openclaw#43148 class).
buildRuntimeLine now renders the stable base session key and drops the per-run
id the run scope duplicates; parseCronRunScopeSuffix is gated to the
isolated-cron key shape so a :run: segment in any other session key is never
truncated.

* fix(agents): preserve mixed-case cron run markers

* test(agents): cover rotated cron session identity

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 10, 2026
…ion id (openclaw#96686)

* fix(agents): isolated cron busts prompt prefix cache via per-run session id

Isolated cron runs carry a per-run :run:<id> session scope (openclaw#91685) rendered
verbatim into the cached system-prompt Runtime line, re-busting byte-exact
prefix caching for the tool catalog after it every run (openclaw#96677, openclaw#43148 class).
buildRuntimeLine now renders the stable base session key and drops the per-run
id the run scope duplicates; parseCronRunScopeSuffix is gated to the
isolated-cron key shape so a :run: segment in any other session key is never
truncated.

* fix(agents): preserve mixed-case cron run markers

* test(agents): cover rotated cron session identity

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clawsweeper:automerge Maintainer opted this PR into bounded ClawSweeper-reviewed automerge clownfish:automerge Maintainer opted this Clownfish PR into bounded ClawSweeper-reviewed automerge merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. size: L status: 🚀 automerge armed This PR is in ClawSweeper's automerge lane.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants