fix(heartbeat): scope commitment fan-out prompts#98169
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed June 30, 2026, 10:37 PM ET / 02:37 UTC. Summary Reproducibility: yes. from source inspection: current main still uses reason-based commitment fan-out through normal heartbeat preflight, which can inspect global session events before commitment-only scoping exists. I did not run tests because this review is read-only. Review metrics: 3 noteworthy metrics.
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:
Proof guidance:
Mantis proof suggestion Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Keep the commitment-only heartbeat fix, but reset or replace this PR with a narrow heartbeat/runtime/test branch and fresh current-head Telegram proof; route dependency, release, workflow, app, docs, and UI work through separate owner-reviewed PRs. Do we have a high-confidence way to reproduce the issue? Yes, from source inspection: current main still uses reason-based commitment fan-out through normal heartbeat preflight, which can inspect global session events before commitment-only scoping exists. I did not run tests because this review is read-only. Is this the best way to solve the issue? No, this PR is not the best merge vehicle in its current form. The heartbeat-only scope design is plausible, but it should land as a narrow runtime/test change rather than mixed with release, dependency, app, docs, and UI churn. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 816038e97a5d. Label changesLabel changes:
Label justifications:
Evidence reviewedSecurity concerns:
Acceptance criteria:
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
|
Mantis Telegram Desktop ProofSummary: Mantis captured native Telegram Desktop before/after GIF evidence with Convex-leased Telegram credentials.
Motion-trimmed clips: |
|
@clawsweeper re-review Added redacted after-fix real runtime proof to the PR body under |
|
🦞🧹 I asked ClawSweeper to review this item again. |
Dependency GuardThis PR changes dependency-related files. Maintainers should confirm these changes are intentional. Changed files:
Maintainer follow-up:
|
Dependency graph changes are blockedOpenClaw does not accept dependency graph changes through PRs unless a repository admin or security explicitly authorizes the current head SHA. Dependency updates are generated internally by maintainers so external PRs cannot change the resolved graph. Detected dependency graph changes:
Auto-scrub was not attempted because this PR changes package manifest dependency graph fields:
Dependency graph changes must be reviewed by security or handled by maintainers internally. Please remove lockfile changes manually if they are not needed. To remove lockfile changes, restore them from the target branch: git fetch origin
git checkout 'origin/main' -- 'extensions/acpx/npm-shrinkwrap.json' 'extensions/amazon-bedrock-mantle/npm-shrinkwrap.json' 'extensions/amazon-bedrock/npm-shrinkwrap.json' 'extensions/anthropic-vertex/npm-shrinkwrap.json' 'extensions/arcee/npm-shrinkwrap.json' 'extensions/brave/npm-shrinkwrap.json' 'extensions/cerebras/npm-shrinkwrap.json' 'extensions/chutes/npm-shrinkwrap.json' 'extensions/clickclack/npm-shrinkwrap.json' 'extensions/cloudflare-ai-gateway/npm-shrinkwrap.json' 'extensions/codex/npm-shrinkwrap.json' 'extensions/cohere/npm-shrinkwrap.json' 'extensions/copilot/npm-shrinkwrap.json' 'extensions/deepinfra/npm-shrinkwrap.json' 'extensions/deepseek/npm-shrinkwrap.json' 'extensions/diagnostics-otel/npm-shrinkwrap.json' 'extensions/diagnostics-prometheus/npm-shrinkwrap.json' 'extensions/diffs-language-pack/npm-shrinkwrap.json' 'extensions/diffs/npm-shrinkwrap.json' 'extensions/discord/npm-shrinkwrap.json' 'extensions/exa/npm-shrinkwrap.json' 'extensions/feishu/npm-shrinkwrap.json' 'extensions/firecrawl/npm-shrinkwrap.json' 'extensions/fireworks/npm-shrinkwrap.json' 'extensions/gmi/npm-shrinkwrap.json' 'extensions/google-meet/npm-shrinkwrap.json' 'extensions/googlechat/npm-shrinkwrap.json' 'extensions/gradium/npm-shrinkwrap.json' 'extensions/groq/npm-shrinkwrap.json' 'extensions/inworld/npm-shrinkwrap.json' 'extensions/irc/npm-shrinkwrap.json' 'extensions/kilocode/npm-shrinkwrap.json' 'extensions/kimi-coding/npm-shrinkwrap.json' 'extensions/line/npm-shrinkwrap.json' 'extensions/llama-cpp/npm-shrinkwrap.json' 'extensions/lobster/npm-shrinkwrap.json' 'extensions/matrix/npm-shrinkwrap.json' 'extensions/mattermost/npm-shrinkwrap.json' 'extensions/memory-lancedb/npm-shrinkwrap.json' 'extensions/moonshot/npm-shrinkwrap.json' 'extensions/msteams/npm-shrinkwrap.json' 'extensions/nextcloud-talk/npm-shrinkwrap.json' 'extensions/nostr/npm-shrinkwrap.json' 'extensions/openshell/npm-shrinkwrap.json' 'extensions/parallel/npm-shrinkwrap.json' 'extensions/perplexity/npm-shrinkwrap.json' 'extensions/pixverse/npm-shrinkwrap.json' 'extensions/qianfan/npm-shrinkwrap.json' 'extensions/qqbot/npm-shrinkwrap.json' 'extensions/qwen/npm-shrinkwrap.json' 'extensions/raft/npm-shrinkwrap.json' 'extensions/searxng/npm-shrinkwrap.json' 'extensions/signal/npm-shrinkwrap.json' 'extensions/slack/npm-shrinkwrap.json' 'extensions/sms/npm-shrinkwrap.json' 'extensions/stepfun/npm-shrinkwrap.json' 'extensions/synology-chat/npm-shrinkwrap.json' 'extensions/tavily/npm-shrinkwrap.json' 'extensions/tencent/npm-shrinkwrap.json' 'extensions/tlon/npm-shrinkwrap.json' 'extensions/tokenjuice/npm-shrinkwrap.json' 'extensions/twitch/npm-shrinkwrap.json' 'extensions/venice/npm-shrinkwrap.json' 'extensions/vercel-ai-gateway/npm-shrinkwrap.json' 'extensions/voice-call/npm-shrinkwrap.json' 'extensions/whatsapp/npm-shrinkwrap.json' 'extensions/zai/npm-shrinkwrap.json' 'extensions/zalo/npm-shrinkwrap.json' 'extensions/zalouser/npm-shrinkwrap.json' 'npm-shrinkwrap.json' 'pnpm-lock.yaml'
git commit -m 'chore: remove dependency lockfile change'
git pushIf this PR intentionally needs a dependency graph change, ask a repository admin or member of The action will approve the current head SHA ( |
|
Land-ready proof for exact head
No known proof gaps remain. |
|
Merged via squash.
|




What Problem This Solves
Heartbeat scheduling has two related paths: the agent's normal configured heartbeat, then fan-out to other sessions with due inferred commitments. Commitment fan-out previously reused the global heartbeat preparation path and inferred its special meaning from the free-form diagnostic reason
"commitment".That let a commitment-only wake inherit unrelated global work: periodic tasks and timestamps,
HEARTBEAT.mdor default heartbeat instructions, queued system/plugin context, subagent steering, and one-shot aborted-run state. In a channel such as Telegram, the visible result could mix or redirect a room-specific follow-up with global operational work.Why This Change Was Made
The scheduler now selects a closed, private
HeartbeatRunScopeat the scheduler/runner boundary:globalremains the default for ordinary heartbeats, periodic tasks, and public/gateway callers.commitment-onlyis available only to due-commitment fan-out and carries through reply preparation plus embedded, CLI, Codex, and Copilot execution.Commitment-only runs use only the due commitment prompt. They do not advance periodic task timestamps, append global heartbeat/bootstrap prompt material, drain queued system/plugin context, lease subagent steering, or consume an aborted-run hint. Isolated session identity and delivery routing are preserved.
This removes semantic control from
reason, keeps the exceptional mode owned by the scheduler, and makes the valid run modes explicit across every supported runtime.User Impact
Due commitments are delivered to the original channel/session without unrelated global heartbeat content or state being consumed. Normal heartbeat behavior is unchanged. There is no new config, public protocol, or plugin SDK contract.
Evidence
node scripts/run-vitest.mjs src/agents/embedded-agent-runner/run/attempt.spawn-workspace.context-engine.test.ts src/auto-reply/reply/get-reply-run.media-only.test.ts src/infra/heartbeat-runner.commitments.test.ts src/agents/embedded-agent-runner/run/attempt.prompt-helpers.test.ts src/agents/harness/prompt-compaction-hook-helpers.test.ts extensions/codex/src/app-server/thread-lifecycle.test.ts extensions/codex/src/app-server/run-attempt.context-engine.test.tstbx_01kwdhq565h90s0c32a8m0tez8(jade-krill), 14 files and 728/728 tests passed across 7 shards.tbx_01kwdm4y55wxt582k3ra632hmh(brisk-lobster), Actions run 28486841407; all tsgo, oxlint, import-cycle, SDK/export, and changed guards passed.node scripts/plugin-sdk-surface-report.mjs --checkpassed at 10,400 exports / 5,219 callables.git diff --check, oxfmt checks, and a fresh autoreview passed with no actionable findings.0722a1b7ead60dac9955e494dc1507f5f9c830d2: AWS Crabbox Mantis run 28488853390, artifact 7999198366, before/after proof comment, baseline pass, candidate pass/fixed, overall pass.Direct Codex protocol/runtime inspection confirms that Codex exposes a generic turn API with no OpenClaw heartbeat field, so this scope remains internal to OpenClaw (
codex-rs/app-server-protocol/src/protocol/v2/turn.rs:68-157,codex-rs/app-server/src/request_processors/turn_processor.rs:155-173,442-540).