Skip to content

fix: cron jobs bypassed by ResponseMode/listen-only mode#519

Open
ciaranashton wants to merge 3 commits intospacedriveapp:mainfrom
ciaranashton:fix/cron-listen-only-suppression
Open

fix: cron jobs bypassed by ResponseMode/listen-only mode#519
ciaranashton wants to merge 3 commits intospacedriveapp:mainfrom
ciaranashton:fix/cron-listen-only-suppression

Conversation

@ciaranashton
Copy link
Copy Markdown
Contributor

@ciaranashton ciaranashton commented Mar 31, 2026

Summary

  • Cron jobs fire but never deliver responses when listen_only_mode is enabled on the agent
  • Root cause: the listen-only guard in channel.rs checks message.source != "system", but cron messages use the adapter platform as source (e.g., "slack") for routing — so they get suppressed as unsolicited messages
  • Fix: add message.sender_id != "system" to the guard, since only cron and system retrigger messages use this sender ID (retriggers already bypass via source == "system")

Cron-originated messages carry a platform source (e.g., "slack") for
adapter routing but use sender_id="system". The listen-only guard only
checked message.source != "system", so cron messages were silently
suppressed — the channel returned without running the LLM, producing
no output and skipping delivery.

Add sender_id != "system" to the guard so cron messages are correctly
exempted from listen-only suppression.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 31, 2026

Walkthrough

The listen-only (quiet/mention-only) suppression guard in Channel::handle_message now also checks message.sender_id != "system", so messages with sender_id = "system" (cron-originated) are not suppressed. A unit test response_mode_guard_allows_cron_messages_through was added to verify this.

Changes

Cohort / File(s) Summary
Listen-only guard refinement
src/agent/channel.rs
Updated suppression predicate in Channel::handle_message to include message.sender_id != "system". Added unit test response_mode_guard_allows_cron_messages_through that constructs a cron-like message (source="slack", sender_id="system", cron conversation_id) and asserts the guard does not suppress it.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

Suggested reviewers

  • jamiepine
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The description is directly related to the changeset, explaining the root cause and the fix applied to the cron/listen-only mode issue.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Title check ✅ Passed The title clearly and concisely describes the primary bug fix: cron jobs being suppressed by listen-only mode, which is the main issue addressed in the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/agent/channel.rs`:
- Around line 1762-1767: The listen-only exemption added for single messages
wasn’t applied to coalesced batches; update handle_message_batch so the
suppression check matches the single-message logic: when self.listen_only_mode
and not self.is_dm(), do not suppress messages in the batch that have
message.source != "system" (i.e., platform-originated cron outputs) even if
message.sender_id == "system"; in practice, change the batch-suppression
predicate in handle_message_batch to consider both message.source and
message.sender_id (same conditions used where the single-message path was fixed)
so scheduled/cron messages are exempted from quiet-mode suppression.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9f5c7b8a-b8df-4b3c-a3a1-ba5cf5b4c0fb

📥 Commits

Reviewing files that changed from the base of the PR and between 66846e5 and bbf02f6.

📒 Files selected for processing (1)
  • src/agent/channel.rs

Upstream replaced listen_only_mode boolean with ResponseMode enum.
Applied the sender_id="system" fix to the new guard and updated the
test to match.
@ciaranashton ciaranashton reopened this Mar 31, 2026
@ciaranashton ciaranashton changed the title fix: cron jobs bypassed by listen-only mode fix: cron jobs bypassed by ResponseMode/listen-only mode Mar 31, 2026
Copy link
Copy Markdown
Collaborator

@vsumner vsumner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two correctness issues remain in the current patch. The single-message exemption is a step in the right direction, but the batch path still needs parity and the regression test should exercise the real behavior.

// In Quiet/MentionOnly modes, ingest messages but only reply when explicitly invoked.
// Cron-originated messages carry a platform source (e.g., "slack") for adapter
// routing but use sender_id="system" — exempt them from suppression.
if !matches!(self.resolved_settings.response_mode, ResponseMode::Active)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes the single-message response-mode guard, but the coalesced batch path still suppresses unsolicited traffic whenever response_mode is not Active and !batch_has_invoke. Cron/system-originated work can flow through handle_message_batch too, so scheduled output can still be dropped in Quiet/MentionOnly mode when messages are buffered together. Please mirror this exemption in the batch suppression branch as well.

@@ -3809,6 +3812,35 @@ mod tests {
assert!(!invoked_by_reply);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new test recomputes a local boolean instead of driving the actual channel suppression logic, so it can still pass even if handle_message or the batch path regresses. This bug class needs a behavior-level regression test that exercises the real guard branch, and it should include the coalesced batch case because that is the remaining unprotected path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants