#21014: fix(cron): suppress main-session summary for HEARTBEAT_OK responses
size: S
Cluster:
Cron Job Enhancements
## Summary
Fixes #20941.
When an isolated cron job with `delivery.mode = "announce"` returns `HEARTBEAT_OK`, the announce delivery correctly suppresses the external message — but the gateway still injects a `Cron: HEARTBEAT_OK` summary into the main session. This triggers the heartbeat system to relay it as a spurious reminder to the user.
## Root Cause
In `src/cron/isolated-agent/run.ts`, `skipHeartbeatDelivery` gates the delivery block (preventing outbound sends and announce flow), but does **not** set `delivered = true`. The caller in `timer.ts` checks `!res.delivered` before injecting the summary into the main session — so the summary leaks through.
## Fix
One-line change: treat heartbeat-only suppression as "delivered" so the caller skips main-session summary injection:
```typescript
let delivered = skipMessagingToolDelivery || skipHeartbeatDelivery;
```
## Tests
Two new tests (175 total cron tests passing):
1. **HEARTBEAT_OK sets `delivered=true`** — verifies no announce flow fires and no outbound send occurs
2. **HEARTBEAT_OK with media still delivers** — verifies structured content (media URLs) bypasses heartbeat suppression as intended
## Checklist
- [x] One-line fix in `run.ts`
- [x] 2 new tests, 175 total cron tests passing
- [x] No breaking changes — only affects the `delivered` flag when heartbeat suppression is active
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR fixes a bug where `HEARTBEAT_OK` responses from isolated cron jobs were leaking into the main session as spurious summaries. The fix correctly treats heartbeat suppression as "delivered" so the caller in `timer.ts` skips injecting `Cron: HEARTBEAT_OK` messages that would trigger unnecessary user notifications.
The one-line change in `src/cron/isolated-agent/run.ts:594` is surgical and correct:
- Previously: `let delivered = skipMessagingToolDelivery;`
- Now: `let delivered = skipMessagingToolDelivery || skipHeartbeatDelivery;`
This ensures that when `skipHeartbeatDelivery` is true (heartbeat-only response with no real content), the `delivered` flag is set, preventing the main session summary injection in `timer.ts:541`.
Two comprehensive tests validate the behavior:
- Test 1 verifies `HEARTBEAT_OK` sets `delivered=true` and suppresses both announce flow and outbound delivery
- Test 2 verifies `HEARTBEAT_OK` with media still delivers (media bypasses heartbeat suppression via `isHeartbeatOnlyResponse`)
The fix aligns with the existing heartbeat suppression logic where `isHeartbeatOnlyResponse` already checks for media/structured content and returns false when present, ensuring those payloads still get delivered.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The fix is a minimal one-line change that correctly addresses the root cause. The logic is sound: treating heartbeat suppression as "delivered" prevents spurious main-session summaries while preserving all existing delivery behavior for real content. Two comprehensive tests validate both the fix (HEARTBEAT_OK suppression) and the edge case (media still delivers). The change is well-contained with no breaking changes or unexpected side effects.
- No files require special attention
<sub>Last reviewed commit: 8dc7837</sub>
<!-- greptile_other_comments_section -->
<sub>(5/5) You can turn off certain types of comments like style [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#6522: fix(cron): deliver original message when agent response is heartbea...
by sidmohan0 · 2026-02-01
88.3%
#11657: fix(cron): treat skipped heartbeat as ok for one-shot jobs
by DukeDeSouth · 2026-02-08
82.4%
#20521: feat(heartbeat): inject active cron job summary into heartbeat prompt
by maximalmargin · 2026-02-19
81.8%
#8418: fix: notify user after consecutive heartbeat/cron failures
by liaosvcaf · 2026-02-04
81.5%
#19745: fix(heartbeat): enforce interval check regardless of trigger source
by misterdas · 2026-02-18
81.5%
#13383: fix(cron): route text-only payloads through direct delivery
by Masha-L · 2026-02-10
81.1%
#16321: Fix #12767: suppress HEARTBEAT_OK leakage in Telegram DM replies
by tdjackey · 2026-02-14
81.0%
#19406: fix(heartbeat): filter error payloads from heartbeat reply selection
by namabile · 2026-02-17
80.4%
#19270: fix: retry event-driven heartbeats blocked by requests-in-flight
by deggertsen · 2026-02-17
80.4%
#12786: fix: drop heartbeat runs that arrive while another run is active
by mcaxtr · 2026-02-09
80.1%