Skip to content

fix(acp): exempt DM channels from mentions-mode mention requirement - #4185

Open
bbrysonelite-max wants to merge 2 commits into
block:mainfrom
bbrysonelite-max:fix/acp-dm-mention-exemption
Open

fix(acp): exempt DM channels from mentions-mode mention requirement#4185
bbrysonelite-max wants to merge 2 commits into
block:mainfrom
bbrysonelite-max:fix/acp-dm-mention-exemption

Conversation

@bbrysonelite-max

Copy link
Copy Markdown

Problem

In subscribe=mentions mode (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:

  1. Wire layer: the relay subscription for every channel carries a #p filter (ChannelFilter.require_mention), so an unmentioned kind-9 DM never comes off the wire.
  2. Local layer: the built-in mentions-mode rule sets require_mention, so even a delivered event without a p tag is filtered in match_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:

  • Startup wire filters: new helper apply_dm_mention_exemption() drops the #p requirement for channels discovered as channel_type == "dm". Unknown/absent types keep the narrow filter — deliberately the opposite of is_dm_channel()'s fail-closed-to-DM, because here "treat as DM" would widen a subscription; the divergence is documented on the helper.
  • Dynamic membership path: uses async 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: new dm_mention_exempt: bool param, set only for subscribe=mentions + DM channel. Config-mode rules keep their require_mention contract everywhere — an operator who writes require_mention: true gets 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):

  • 7 in 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.
  • 7 in lib.rs (dm_mention_exemption_tests): dm flips require_mention off (count=1), stream/unknown/absent stay narrow, non-mentions modes untouched, kinds preserved.

cargo fmt / clippy --all-targets -D warnings clean. 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

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>
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.

1 participant