Skip to content

fix(listen): trust backend mentions array instead of content regex#31

Merged
madtank merged 1 commit intomainfrom
orion/listen-trust-mentions-array
Apr 9, 2026
Merged

fix(listen): trust backend mentions array instead of content regex#31
madtank merged 1 commit intomainfrom
orion/listen-trust-mentions-array

Conversation

@madtank
Copy link
Copy Markdown
Member

@madtank madtank commented Apr 9, 2026

Summary

Removes a latent bug in `ax listen` where `_should_respond` matched @mentions via content regex instead of trusting the event payload's `mentions` array. That bug had no consequence until ax-backend started filtering disabled agents out of the mentions list at broadcast time (see ax-backend `d6fb390` "feat(notifications): enforce kill switch at mention broadcast boundary"). Now the regex path bypasses the server-side filter and lets `ax listen` respond to messages the backend has explicitly excluded.

This is not a kill switch implementation. It removes client-side re-inference in favor of trusting the backend's authoritative list. Enforcement still lives at the API (ax-backend `broadcast_sse` → `AgentControlService`). This change stops the client from disagreeing with it.

What changed

`_should_respond(data, agent_name, agent_id)`:

  • Primary path: read `mentions` from event data. If present (even as an empty list), trust it absolutely. An empty list means "no active mentions" — do not fall back to regex.
  • Fallback: only if `mentions` is completely absent (legacy / non-standard event shapes), use content regex so we don't regress on payloads predating the current mentions contract.
  • Self-filter preserved: sender check runs before mentions lookup.
  • Handles both string and dict entries in the mentions array, strips leading `@`, case-insensitive.

Test plan

  • 8 unit tests covering: filtered empty mentions, list with us, list without us, legacy fallback, self-mention, mention-event shape, dict entries, `@` prefix stripping — all pass
  • Live E2E after merge: restart `ping_bot` with this code, click Break in UI, send `@ping_bot test`, verify `ping_bot` does NOT reply and backend log shows `KILL SWITCH FILTER` line. Then re-enable, send again, verify `pong` reply.

Context

This is the second half of the kill-switch-enforcement-at-the-API fix. First half is ax-backend `d6fb390` which makes the backend filter disabled agents out of the mentions list universally. Second half (this PR) is the client trusting that list. Together: one enforcement point at the API, all clients that trust the mentions contract respect it automatically.

Reverted PR #29 added a client-side kill switch check to `ax listen`. That was the wrong shape. This PR is the correct shape: fix a client bug that was bypassing the server's authoritative routing.

`_should_respond` previously matched mentions via `f"@{agent_name}" in
content`, which ignored the backend's authoritative `mentions` array
in the event payload. That was a latent bug with a real consequence:
when the backend filters disabled agents out of the mentions list
(kill switch enforcement in ax-backend messages_notifications.
broadcast_sse), `ax listen` would still match on the raw content text
and queue the mention — bypassing the server-side filter.

This patch flips the logic: trust the `mentions` array if the event
payload includes one, falling back to content regex only for legacy
or non-standard events that don't carry `mentions`. An empty
`mentions: []` is meaningful — it means "no active mentions for this
message" — and the function correctly returns False in that case
instead of falling through to the regex.

Enforcement still lives at the API (ax-backend
broadcast_sse → AgentControlService). This change simply stops
duplicating the decision client-side with a stale, content-based
check. The client becomes a pure consumer of the backend's
authoritative routing list.

Unit-tested against 8 cases:
1. Filtered empty mentions (backend removed us) → False ✓
2. Mentions list has us → True ✓
3. Mentions list has other agent → False ✓
4. Legacy event without mentions field → True (content regex) ✓
5. Self-mention → False (self-filter preserved) ✓
6. Mention-event payload shape → True ✓
7. Dict mentions entries → True ✓
8. @ prefix in mentions strings → True ✓

Context: pairs with ax-backend d6fb390 (kill switch filter at
broadcast boundary). The two together give universal enforcement with
no client-side kill switch re-implementation. Supersedes reverted PR
#29 architectural direction.
@madtank madtank merged commit f1be831 into main Apr 9, 2026
4 checks passed
@madtank madtank deleted the orion/listen-trust-mentions-array branch April 9, 2026 20:43
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