fix(cron): persist resolved delivery target into isolated cron session deliveryContext#92580
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 13, 2026, 11:32 AM ET / 15:32 UTC. Summary PR surface: Source +25, Tests +65, Other +45. Total +135 across 4 files. Reproducibility: Partly: the linked issue gives a concrete isolated cron announce-delivery scenario and the PR supplies a focused helper-level repro, but I did not run a live channel send. Review metrics: none identified. Stored data model Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the narrow cron session deliveryContext propagation fix after normal maintainer review and exact-head checks, keeping the linked issue open until this PR merges. Do we have a high-confidence way to reproduce the issue? Partly: the linked issue gives a concrete isolated cron announce-delivery scenario and the PR supplies a focused helper-level repro, but I did not run a live channel send. Is this the best way to solve the issue? Yes. Writing the already-resolved delivery target into the isolated cron session entry is the narrowest maintainable fix because the later sessions_send/subagent_announce path already consumes deliveryContext from session state. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 3b9494943704. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +25, Tests +65, Other +45. Total +135 across 4 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
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 re-review Updated the PR body to separate the standalone reproduction-script terminal output (real behavior evidence) from the verification checklist. The |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
@clawsweeper re-review The previous re-review failed due to a Codex transient transport error (3 retries exhausted) and a subsequent clawsweeper-state git push failure, not because of a code or proof issue. The PR body has been updated and the |
1 similar comment
|
@clawsweeper re-review The previous re-review failed due to a Codex transient transport error (3 retries exhausted) and a subsequent clawsweeper-state git push failure, not because of a code or proof issue. The PR body has been updated and the |
|
@clawsweeper re-review Branch is already rebased on latest main. The previous re-reviews failed due to Codex transient transport errors and clawsweeper-state git push failures. The |
a0b9e00 to
49a555c
Compare
|
@clawsweeper re-review\n\nRemoved the unrelated issue-91760 workspace fallback changes (agent-scope-config, memory-host-sdk resolver, their updated tests, and the issue-91760 repro script). The branch now contains only the isolated cron deliveryContext persistence fix, its regression tests, and the issue-92460 repro. Re-ran the cron/agent-scope tests and oxlint on the remaining files; both passed. |
|
🦞👀 Command router queued. I will update this comment with the next step. |
|
@clawsweeper re-review Verified via
The unrelated issue-91760 workspace fallback changes have been removed. Please re-run the review. |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
maintainer deep review confirmed the reported cron completion-routing bug, but this PR is not safe to land. Persisting the exact run requester route fixes recovery, but that route must remain available until every supported background completion settles and then be retired. Repair passes covered cron completion and subagent descendants, yet final autoreview found non-subagent ACP/media task completions have no retirement hook. Those route-only rows would accumulate per run and pressure the session-store cap. I am closing this PR rather than landing a lifecycle leak or wiring cron-specific cleanup into every task implementation. The canonical fix needs a generic requester-route lease owned by the shared background-task completion/delivery lifecycle, separate from generic session identity, with retirement after final delivery settles. Focused repair proof passed (47 tests plus format/lint), but final autoreview correctly remains blocking. |
…context Replaces the rejected approach from PR openclaw#92580 that persisted resolved delivery targets onto the session entry (which created a lifecycle leak). Instead introduces a generic in-memory delivery route lease store: - src/infra/delivery-lease-store.ts — register/lookup/retire with TTL-based cleanup (1h default) and 2000-entry cap - src/agents/subagent-announce-origin.ts — resolveAnnounceOrigin gains optional sessionKey param; falls back to lease store when session entry lacks delivery context - src/cron/isolated-agent/run.ts — create lease in prepareCronRunContext after delivery resolution; retire in finalizeCronRun after dispatch - src/agents/subagent-announce.ts — pass targetRequesterSessionKey - src/plugin-sdk/agent-harness-task-runtime.ts — pass requesterSessionKey - src/infra/delivery-lease-store.test.ts — 8 unit tests Fixes openclaw#92460 Refs openclaw#92580 Co-Authored-By: Claude <[email protected]>
Add retireDeliveryLease calls to the shared completion/delivery lifecycle in dispatchCronDelivery. This ensures delivery route leases are cleaned up immediately after final delivery settles, rather than lingering until TTL expiration or cap eviction. Retirement happens in: - deliverViaDirectAndCleanup: after direct channel delivery completes - finishSilentReplyDelivery: after silent reply delivery completes Both paths are part of the shared background-task completion lifecycle that owns the delivery route, matching the design described in PR openclaw#92580 review. Fixes the lifecycle leak where production never retired leases, leaving them to accumulate until the 52h TTL or 2000-entry cap.
…context Replaces the rejected approach from PR openclaw#92580 that persisted resolved delivery targets onto the session entry (which created a lifecycle leak). Instead introduces a generic in-memory delivery route lease store: - src/infra/delivery-lease-store.ts — register/lookup/retire with TTL-based cleanup (1h default) and 2000-entry cap - src/agents/subagent-announce-origin.ts — resolveAnnounceOrigin gains optional sessionKey param; falls back to lease store when session entry lacks delivery context - src/cron/isolated-agent/run.ts — create lease in prepareCronRunContext after delivery resolution; retire in finalizeCronRun after dispatch - src/agents/subagent-announce.ts — pass targetRequesterSessionKey - src/plugin-sdk/agent-harness-task-runtime.ts — pass requesterSessionKey - src/infra/delivery-lease-store.test.ts — 8 unit tests Fixes openclaw#92460 Refs openclaw#92580 Co-Authored-By: Claude <[email protected]>
Add retireDeliveryLease calls to the shared completion/delivery lifecycle in dispatchCronDelivery. This ensures delivery route leases are cleaned up immediately after final delivery settles, rather than lingering until TTL expiration or cap eviction. Retirement happens in: - deliverViaDirectAndCleanup: after direct channel delivery completes - finishSilentReplyDelivery: after silent reply delivery completes Both paths are part of the shared background-task completion lifecycle that owns the delivery route, matching the design described in PR openclaw#92580 review. Fixes the lifecycle leak where production never retired leases, leaving them to accumulate until the 52h TTL or 2000-entry cap.
…context Isolated cron jobs with explicit delivery.channel lose routing state because isolated session entries strip delivery context. Subagent announce completion has no fallback lookup, so the final announcement cannot reach the controller. Adds an in-memory delivery route lease store that: - Registers a lease in prepareCronRunContext keyed by runSessionKey with 52h TTL to cover the full agent run window plus safety buffer - Retires the lease from the completion/delivery lifecycle in delivery-dispatch (finishSilentReplyDelivery + deliverViaDirectAndCleanup finally block) so routes do not linger until TTL expiry or cap eviction - Falls back via resolveAnnounceOrigin sessionKey parameter when the session entry has no deliveryContext (isolated cron session) This matches the design requested in PR openclaw#92580 review (@vincentkoc): 'generic requester-route lease owned by the shared background-task completion /delivery lifecycle, separate from generic session identity, with retirement after final delivery settles.' TTL/cap (1h default, 2000-entry LRU) act as safety net only — production retirement is wired into the completion lifecycle. Tests: - src/infra/delivery-lease-store.test.ts — 8 unit tests for register/lookup/ retire/prune/cap/idempotency - src/cron/isolated-agent.delivery-lease-lifecycle.test.ts — 6 integration tests proving full lifecycle through runCronIsolatedAgentTurn (lease is registered, used for delivery, and explicitly retired after delivery settles) - scripts/repro/issue-92460-delivery-lease-store.mts — standalone reproduction - scripts/test-delivery-lease-lifecycle.mts — real-environment proof script Files: - src/infra/delivery-lease-store.ts (NEW) — lease store with TTL, cap, retirement - src/cron/isolated-agent/run.ts — register lease after delivery resolution - src/cron/isolated-agent/delivery-dispatch.ts — retire lease in completion lifecycle (finishSilentReplyDelivery + deliverViaDirectAndCleanup) - src/agents/subagent-announce-origin.ts — lease fallback in resolveAnnounceOrigin - src/agents/subagent-announce.ts — pass targetRequesterSessionKey - src/plugin-sdk/agent-harness-task-runtime.ts — pass requesterSessionKey - src/cron/isolated-agent.test-setup.ts — reset lease store for test isolation - test/scripts/ci-node-test-plan.test.ts — add delivery-lease-store test shard Fixes openclaw#92460
…context Isolated cron jobs with explicit delivery.channel lose routing state because isolated session entries strip delivery context. Subagent announce completion has no fallback lookup, so the final announcement cannot reach the controller. Adds an in-memory delivery route lease store that: - Registers a lease in prepareCronRunContext keyed by runSessionKey with 52h TTL to cover the full agent run window plus safety buffer - Retires the lease from the completion/delivery lifecycle in delivery-dispatch (finishSilentReplyDelivery + deliverViaDirectAndCleanup finally block) so routes do not linger until TTL expiry or cap eviction - Falls back via resolveAnnounceOrigin sessionKey parameter when the session entry has no deliveryContext (isolated cron session) This matches the design requested in PR openclaw#92580 review (@vincentkoc): 'generic requester-route lease owned by the shared background-task completion /delivery lifecycle, separate from generic session identity, with retirement after final delivery settles.' TTL/cap (1h default, 2000-entry LRU) act as safety net only — production retirement is wired into the completion lifecycle. Tests: - src/infra/delivery-lease-store.test.ts — 8 unit tests for register/lookup/ retire/prune/cap/idempotency - src/cron/isolated-agent.delivery-lease-lifecycle.test.ts — 6 integration tests proving full lifecycle through runCronIsolatedAgentTurn (lease is registered, used for delivery, and explicitly retired after delivery settles) - scripts/repro/issue-92460-delivery-lease-store.mts — standalone reproduction - scripts/test-delivery-lease-lifecycle.mts — real-environment proof script Files: - src/infra/delivery-lease-store.ts (NEW) — lease store with TTL, cap, retirement - src/cron/isolated-agent/run.ts — register lease after delivery resolution - src/cron/isolated-agent/delivery-dispatch.ts — retire lease in completion lifecycle (finishSilentReplyDelivery + deliverViaDirectAndCleanup) - src/agents/subagent-announce-origin.ts — lease fallback in resolveAnnounceOrigin - src/agents/subagent-announce.ts — pass targetRequesterSessionKey - src/plugin-sdk/agent-harness-task-runtime.ts — pass requesterSessionKey - src/cron/isolated-agent.test-setup.ts — reset lease store for test isolation - test/scripts/ci-node-test-plan.test.ts — add delivery-lease-store test shard Fixes openclaw#92460
…context Isolated cron jobs with explicit delivery.channel lose routing state because isolated session entries strip delivery context. Subagent announce completion has no fallback lookup, so the final announcement cannot reach the controller. Adds an in-memory delivery route lease store that: - Registers a lease in prepareCronRunContext keyed by runSessionKey with 52h TTL to cover the full agent run window plus safety buffer - Retires the lease from the completion/delivery lifecycle in delivery-dispatch (finishSilentReplyDelivery + deliverViaDirectAndCleanup finally block) so routes do not linger until TTL expiry or cap eviction - Falls back via resolveAnnounceOrigin sessionKey parameter when the session entry has no deliveryContext (isolated cron session) This matches the design requested in PR openclaw#92580 review (@vincentkoc): 'generic requester-route lease owned by the shared background-task completion /delivery lifecycle, separate from generic session identity, with retirement after final delivery settles.' TTL/cap (1h default, 2000-entry LRU) act as safety net only — production retirement is wired into the completion lifecycle. Tests: - src/infra/delivery-lease-store.test.ts — 8 unit tests for register/lookup/ retire/prune/cap/idempotency - src/cron/isolated-agent.delivery-lease-lifecycle.test.ts — 6 integration tests proving full lifecycle through runCronIsolatedAgentTurn (lease is registered, used for delivery, and explicitly retired after delivery settles) - scripts/repro/issue-92460-delivery-lease-store.mts — standalone reproduction - scripts/test-delivery-lease-lifecycle.mts — real-environment proof script Files: - src/infra/delivery-lease-store.ts (NEW) — lease store with TTL, cap, retirement - src/cron/isolated-agent/run.ts — register lease after delivery resolution - src/cron/isolated-agent/delivery-dispatch.ts — retire lease in completion lifecycle (finishSilentReplyDelivery + deliverViaDirectAndCleanup) - src/agents/subagent-announce-origin.ts — lease fallback in resolveAnnounceOrigin - src/agents/subagent-announce.ts — pass targetRequesterSessionKey - src/plugin-sdk/agent-harness-task-runtime.ts — pass requesterSessionKey - src/cron/isolated-agent.test-setup.ts — reset lease store for test isolation - test/scripts/ci-node-test-plan.test.ts — add delivery-lease-store test shard Fixes openclaw#92460
Summary
Isolated cron completion delivery can fail with
Channel is required (no configured channels detected)even when the job explicitly setsdelivery.channel, because the resolved delivery target is never written back to the isolated cron session entry'sdeliveryContext. Completion-announce paths such assessions_send/subagent_announcelater resolve the target from the session entry and see an empty context.This change persists the resolved cron delivery target onto the isolated cron session entry right after
resolveCronDeliveryContext, so explicitdelivery.channelsurvives to the final completion announcer.Fixes #92460.
Changes
src/cron/isolated-agent/run-session-state.ts: addsetCronSessionDeliveryContextFromResolvedDelivery, a focused helper that normalizes and writes a resolved delivery target into the session entry'sdeliveryContextonly when resolution succeeds and a routable target exists.src/cron/isolated-agent/run.ts: call the helper inprepareCronRunContextafterresolveCronDeliveryContextreturns.src/cron/isolated-agent/run-session-state.test.ts: add regression tests covering explicit target persistence, missing optional fields, failed-resolution no-op, and empty-target no-op.scripts/repro/issue-92460-cron-completion-delivery-context.mts: standalone reproduction script that exercises the production helper and verifies the explicit channel/to/account/thread survive.Real behavior proof
delivery.channelon an isolated cron job is now persisted onto the isolated session entry, so completion-announce target resolution no longer falls back to a channel-less main session.node --import tsx scripts/repro/issue-92460-cron-completion-delivery-context.mtsTerminal output from running the standalone reproduction script against the patched source:
Verification
node --import tsx scripts/repro/issue-92460-cron-completion-delivery-context.mtspassespnpm test src/cron/isolated-agent/run-session-state.test.ts --runpassespnpm test src/cron/isolated-agent/delivery-target.test.ts --runpassespnpm test src/cron/isolated-agent/run.session-key-isolation.test.ts --runpassesnpx oxlinton changed files passespnpm exec oxfmton changed files passespnpm buildpassespnpm tsgopasses