← Back to PRs

#17801: fix(heartbeat): enforce interval guard for non-interval wake reasons

by aldoeliacim open 2026-02-16 06:03 View on GitHub →
stale size: XS trusted-contributor
Fixes #17797 ## Problem Non-interval wake reasons (`exec:*:exit`, `exec-event`, `cron:*`, `hook:wake`) bypassed the `nextDueMs` guard in the heartbeat runner's `run()` function. This meant every exec tool completion or sub-agent exit triggered a full heartbeat run regardless of the configured interval, causing runaway loops (244 runs in 2.5h instead of ~5). ## Root Cause The interval check only applied when `reason === "interval"`: ```ts if (isInterval && now < agent.nextDueMs) continue; ``` All other wake reasons skipped this guard entirely. ## Fix Remove the `isInterval` condition so `nextDueMs` is respected for **all** wake reasons: ```ts if (now < agent.nextDueMs) continue; ``` `requestHeartbeatNow()` still wakes the runner immediately, but if the agent already ran within its interval window the run is correctly skipped. This is a 1-line behavioral change (plus cleanup of the now-unused `isInterval` variable). ## Testing All existing heartbeat tests pass (38/38). <!-- greptile_comment --> <h3>Greptile Summary</h3> Enforces `nextDueMs` interval guard for all wake reasons (exec-event, cron, hooks), not just `interval` wakes. Previously, non-interval wake reasons bypassed the interval check entirely, causing heartbeats to run on every exec tool completion regardless of the configured interval (244 runs in 2.5h instead of ~5). Now all wake reasons respect the `nextDueMs` guard, while `requestHeartbeatNow()` can still trigger immediate wakes that get skipped if within the interval window. <h3>Confidence Score: 5/5</h3> - Safe to merge - minimal behavioral change with clear correctness improvement - The fix is a simple, focused 1-line logic change that correctly addresses the root cause. The removal of the `isInterval` condition ensures all wake reasons respect the interval guard, preventing runaway loops. All 38 existing heartbeat tests pass, and the change aligns with the documented intent that `requestHeartbeatNow()` wakes the runner but respects the `nextDueMs` guard. - No files require special attention <sub>Last reviewed commit: f0cacca</sub> <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs