fix(heartbeat): bound pending final delivery replay#85770
Conversation
|
Codex review: needs changes before merge. Reviewed June 24, 2026, 7:48 AM ET / 11:48 UTC. Summary PR surface: Source +43, Tests +80. Total +123 across 2 files. Reproducibility: yes. at source level. Current source and tests show non-ack heartbeat pending-final state is preserved without a cutoff, while the PR head can return cached replay text before the cutoff. Review metrics: 1 noteworthy metric.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. 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:
Copy recommended automerge instructionNext step before merge
Security Review findings
Review detailsBest possible solution: Land a current-main-compatible cutoff that clears stale over-bound pending-final state, never directly replays cached user-facing final text from heartbeat, and clears every current pending-final field together. Do we have a high-confidence way to reproduce the issue? Yes at source level. Current source and tests show non-ack heartbeat pending-final state is preserved without a cutoff, while the PR head can return cached replay text before the cutoff. Is this the best way to solve the issue? No, not as submitted. The cutoff direction matches the canonical issue, but the implementation must preserve current no-direct-replay behavior and clear the full pending-final state shape. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 1069c60e1e25. Label changesLabel justifications:
Evidence reviewedPR surface: Source +43, Tests +80. Total +123 across 2 files. View PR surface stats
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
|
|
ClawSweeper PR egg ✨ Hatched: 🥚 common Velvet Diff Drake Hatch commandComment Hatchability rules:
Rarity: 🥚 common. What is this egg doing here?
|
Summary
pendingFinalDeliveryTextforever because the replay branch had no terminal retry or age bound.src/auto-reply/reply/get-reply.tsnow shares one clear helper, logsretry-limit/expirygive-up reasons, and skips replay once the bound trips;src/auto-reply/reply/get-reply.fast-path.test.tsnow locks both bounds in with regression coverage.Motivation
send-successcleanup andtarget:none) but left the generic fail-safe missing.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Real behavior proof (required for external PRs)
node --import tsx, realsessions.jsonpersistence under a temp directory.and the persisted session record printed with
pendingFinalDelivery,pendingFinalDeliveryText, andpendingFinalDeliveryAttemptCountcleared.shortagain.pnpm check:changedrun is still blocked in this environment because no usablecrabboxbinary is installed locally; only focused local tests and the local persisted-session proof above were run.pendingFinalDeliveryAttemptCount, rewrote the replay text, and returned the cached replay payload without any retry-limit or TTL gate.Root Cause (if applicable)
src/auto-reply/reply/get-reply.tsincrementedpendingFinalDeliveryAttemptCountand returned the replay text every tick, but never checked whether the replay had already been retried too many times or had gone stale by age.retry-limit/expirygive-up vocabulary already used by the subagent pending-final-delivery lifecycle.c240e718e91and later replay cleanups only handled ack-only stripping and adjacent narrower causes, not this general orphan-session fail-safe.Regression Test Plan (if applicable)
src/auto-reply/reply/get-reply.fast-path.test.tsgetReplyFromConfigtest exercises the exact persisted-session mutation without needing a broader dispatcher harness.User-visible / Behavior Changes
Heartbeat sessions no longer replay stale pending final delivery forever. Once a pending heartbeat replay exceeds 10 attempts or stays pending for more than 24 hours, OpenClaw drops the stale replay state and proceeds instead of re-sending the same cached alert on every heartbeat tick.
Diagram (if applicable)
Security Impact (required)
Yes/No) NoYes/No) NoYes/No) NoYes/No) NoYes/No) NoYes, explain risk + mitigation:Repro + Verification
Environment
agents.defaults.model=openai/gpt-5.5,agents.defaults.heartbeat.ackMaxChars=0, tempsession.storeSteps
sessions.jsonwith a main-session entry whosependingFinalDeliveryistrue,pendingFinalDeliveryTextis substantive (HEARTBEAT_OK short), andpendingFinalDeliveryAttemptCountis already 10 or whosependingFinalDeliveryCreatedAtis older than 24 hours.getReplyFromConfig(..., { isHeartbeat: true }, cfg)against that store-backed session.Expected
Actual
retry-limitorexpirywarning, clears the stale pending-final-delivery fields, and does not return the stale replay text.Evidence
Attach at least one:
Human Verification (required)
crabboxbinary in this environment.Review Conversations
Compatibility / Migration
Yes/No) YesYes/No) NoYes/No) NoRisks and Mitigations