#7353: fix: prevent silent message drops after config.patch restart
channel: imessage
agents
Cluster:
Messaging Platform Improvements
- Add channel readiness check in deliverOutboundPayloads before message delivery
- Add heartbeat.checkReady method to iMessage channel plugin
- Throw error with clear message when channel is not ready instead of silently dropping
- Prevents replies from being lost after restart when channels have startup latency
Fixes issue where replies generated immediately after config.patch restart were silently dropped for channels like iMessage. The reply appeared in Control UI (WebSocket reconnects quickly) but was lost for channels with more startup latency.
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR adds a channel-level readiness preflight to outbound delivery. `deliverOutboundPayloads` now calls `plugin.heartbeat.checkReady()` (if provided) before sending; if the channel reports not ready, it throws (default) or, in `bestEffort` mode, routes the failure through `onError` and returns without attempting delivery.
To support this, the iMessage extension plugin now implements `heartbeat.checkReady` by verifying the account is enabled/configured and probing the iMessage runtime with a 2s timeout, returning a structured `{ ok, reason }` response. This prevents the previous silent drop behavior for channels with slower startup after a `config.patch` restart.
<h3>Confidence Score: 4/5</h3>
- This PR is likely safe to merge, with one notable integration risk around heartbeat dependency typing.
- The behavior change is localized and gated on `heartbeat.checkReady` existing, but `deliverOutboundPayloads` currently passes outbound-send deps cast as `ChannelHeartbeatDeps`, which may cause incorrect readiness results for plugins that depend on heartbeat-specific deps. iMessage’s readiness probe itself looks straightforward.
- src/infra/outbound/deliver.ts
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
**Context used:**
- Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8))
- Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13))
<!-- /greptile_comment -->
Most Similar PRs
#2799: fix(imessage): prevent self-chat and outbound echo loops (#2585)
by Tfh-Yqf · 2026-01-27
80.7%
#11898: Fix for issue #11895
by rerickardjr · 2026-02-08
80.2%
#4878: fix: string/type handling and API fixes (#4537, #4380, #4373, #4547...
by lailoo · 2026-01-30
78.8%
#13881: fix: Address Greptile feedback - test isolation and channel resolution
by trevorgordon981 · 2026-02-11
78.8%
#10109: feat(plugins): invoke message_received and message_sent hooks
by nezovskii · 2026-02-06
78.7%
#3300: changed chat session selection logic in iMessage
by KimEJ · 2026-01-28
78.5%
#10470: Fix: iMessage real-time delivery via imsg watch
by saurav470 · 2026-02-06
77.9%
#15864: feat: add deliverOnlyToolMessages config for clean messaging channe...
by gandalf-the-engineer · 2026-02-14
77.7%
#15853: feat: add option to suppress media placeholder text
by MisterGuy420 · 2026-02-14
77.6%
#7218: fix(telegram): skip empty text messages in threaded mode
by ArsalanShakil · 2026-02-02
77.4%