fix(acp): exempt DM channels from mentions-mode mention requirement - #4185
Open
bbrysonelite-max wants to merge 2 commits into
Open
fix(acp): exempt DM channels from mentions-mode mention requirement#4185bbrysonelite-max wants to merge 2 commits into
bbrysonelite-max wants to merge 2 commits into
Conversation
In mentions mode, plain DM text (kind 9, no p tag) was silently dropped at two layers: the relay subscription carried a #p filter so the event never came off the wire, and the local match_event rule required a mention. A DM is already addressed to the agent, so requiring an explicit @mention there made agent DMs unusable. Exempt DM channels from both gates, mentions mode only: - startup wire filters: apply_dm_mention_exemption() drops the #p requirement for channels discovered as type dm; unknown types stay narrow (deliberate divergence from is_dm_channel's fail-closed-to-DM, documented on the helper) - dynamic membership path: uses is_dm_channel for agent-initiated DMs that have no startup metadata; the author gate still runs per-event as the backstop - match_event: new dm_mention_exempt param, set only for subscribe=mentions + DM channel; config-mode rules keep their require_mention contract everywhere 14 tests across both layers, sabotage-verified (feature revert turns them red). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Brent Bryson <bbrysonelite@gmail.com>
The harness never publishes agent replies itself — agents post their own via 'buzz messages send', driven entirely by the prompt. For DM turns that are not thread replies, format_context_hints appended no send instruction at all (it was gated behind root_event_id), so weaker-instruction agents (goose) read context and ended the turn without posting anything — a silent no-reply. - append_dm_send_instruction(): unthreaded DM prompts now carry an explicit MUST-send directive with the channel uuid, plus guidance not to @mention in DMs (mentions trigger a CLI preflight that can abort the send) - threaded DM and channel prompts unchanged - agent_returned log line now includes the ACP StopReason so refusals and turn-limit stops are distinguishable from clean end_turn 3 new prompt tests; suite 677 passed / 1 pre-existing flake. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: Brent Bryson <bbrysonelite@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
In
subscribe=mentionsmode (the default), plain DM text sent to an agent is silently dropped — the agent never responds and nothing is logged at INFO. Two layers filter it:#pfilter (ChannelFilter.require_mention), so an unmentioned kind-9 DM never comes off the wire.require_mention, so even a delivered event without aptag is filtered inmatch_event.A DM is already addressed to the agent — requiring an explicit @mention inside it makes agent DMs effectively unusable (users type plain text, see the agent stay silent, and have no feedback why).
Change
Exempt DM channels from both gates, mentions mode only:
apply_dm_mention_exemption()drops the#prequirement for channels discovered aschannel_type == "dm". Unknown/absent types keep the narrow filter — deliberately the opposite ofis_dm_channel()'s fail-closed-to-DM, because here "treat as DM" would widen a subscription; the divergence is documented on the helper.is_dm_channel()(agent-initiated DMs have no startup metadata). Widening on unresolved type is safe here because the inbound author gate still runs per-event.match_event: newdm_mention_exempt: boolparam, set only forsubscribe=mentions+ DM channel. Config-mode rules keep theirrequire_mentioncontract everywhere — an operator who writesrequire_mention: truegets exactly that, in every channel.Author gate, channel scope, kind filters, and evalexpr filters are unchanged.
Tests
14 new tests across both layers, sabotage-verified (reverting the feature turns them red):
filter.rs: exemption dispatches unmentioned DM events; exempt=false preserves old behavior; exemption does not leak into kind/evalexpr/channel-scope gates or rule ordering.lib.rs(dm_mention_exemption_tests): dm flipsrequire_mentionoff (count=1), stream/unknown/absent stay narrow, non-mentions modes untouched, kinds preserved.cargo fmt/clippy --all-targets -D warningsclean. Verified live against a hosted relay: pre-patch an unmentioned DM produced zero harness activity; post-patch it reaches the author gate (is_dm=true) and owner DMs dispatch normally.🤖 Generated with Claude Code