fix(bidirectional): drop messages from KNOWN mayor bots (bo-pwib)#7
Open
openclaw-dv wants to merge 1 commit into
Open
fix(bidirectional): drop messages from KNOWN mayor bots (bo-pwib)#7openclaw-dv wants to merge 1 commit into
openclaw-dv wants to merge 1 commit into
Conversation
Wesley msg 729: my outbound Slack posts via midgard mayor's bot
(user_id U0B385LBXPT) trigger 📬 + 👀 reactions on themselves
because bidirectional's bo-nb97 self-only filter only matches
THIS Worker's own bot — not the mayor bots posting THROUGH the
shared Slack workspace.
Sequence of bugs that lead here:
* bo-nb97 fixed PEER-bot delivery — Hermes can DM midgard
mayor now.
* bo-uu4i fixed the POLL-side self-echo so the mayor's own
context isn't polluted with its own writes.
* bo-xyh2 stopped the 🤔 reaction on poll-side self-echoes.
* bo-pwib (this) — the FIRST stage still routes midgard
mayor's outbound DM as a fresh inbound DM. The bidirectional
Worker treats it as a real Wesley → mayor message, fires
📬 + 👀 reactions, AND re-routes the bot's own message back
into its own gt-receiver inbox. Self-conversation loop.
Fix
---
New ``KNOWN_MAYOR_BOT_USER_IDS`` env var (comma-separated U…
ids) + ``getMayorBotUserIds(env)`` resolver that:
1. Parses the env override when set.
2. Auto-discovers via auth.test against any per-mayor
``*_MAYOR_BOT_TOKEN`` env binding present
(YGGDRASIL_MAYOR_BOT_TOKEN, MIDGARD_MAYOR_BOT_TOKEN). One
auth.test per token on cold start, cached for the isolate
lifetime. Mirrors the bo-nb97 ``getBotUserId`` shape.
3. Returns the union as a Set<string> the predicate
``isKnownMayorBot(env, userId)`` checks against.
Predicate is wired into all three event handlers — handleMessage
(thread replies), handleDm (DMs to per-mayor apps), and
handleChannelMention (@-mentions of a per-mayor app). Same shape
on each call site:
const botId = await getBotUserId(env);
if (botId && ev.user === botId) return; // bo-nb97
if (await isKnownMayorBot(env, ev.user)) return; // bo-pwib
The bo-nb97 self-only check runs first (cheap module-level cache
hit on the common path). The mayor-bot check fires after — slower
on first call (one auth.test per per-mayor token) but cached for
the isolate lifetime. Set ``KNOWN_MAYOR_BOT_USER_IDS`` via wrangler
vars to skip the auth.test round-trip entirely.
handleMessage scope extension
-----------------------------
The bead called out handleDm + handleChannelMention. I extended
the filter to handleMessage too because mayor↔mayor thread
replies in alert threads have the same loop shape — midgard's
reply to a yggdrasil-watched alert thread would otherwise be
treated as an inbound thread reply and re-routed.
If a use case for "a mayor bot writes a thread reply that
SHOULD be received by another mayor" emerges, we add an
opt-in env override (KNOWN_MAYOR_BOT_USER_IDS_EXCEPT) — but
the default-deny is the safer floor.
Effect
------
After deploy + setting ``KNOWN_MAYOR_BOT_USER_IDS`` (or just
binding the per-mayor tokens so auth.test resolves them):
* Mayor's own outbound posts (Wesley msg 729) — silent. No
📬, no 👀, no re-route into the mayor's own inbox.
* Wesley's real messages — unchanged, still routed.
* Peer bots (Hermes, future third-party Slack integrations) —
unchanged from bo-nb97, still routed.
* Mayor-to-mayor cross-talk — dropped. If this becomes a
feature, it can be re-enabled via the exception env-var
above.
## Cross-repo context
Bead bo-pwib is tracked in the boardroom rig's bd issue tracker.
The polecat that produced this PR (boardroom/polecats/dementus)
closed bo-pwib with a back-pointer to this PR. Sibling fixes in
this self-echo / bot-routing thread (chronological):
* alert-hub PR #6 (bo-nb97) — bidirectional self-only filter.
* dv-gastown-utils PR #23 (bo-uu4i) — poll-side self-filter.
* dv-gastown-utils PR #24 (bo-xyh2) — silent-ack self-echoes
so the 🤔 reaction doesn't fire on bot's own writes.
* alert-hub PR #X (this) — drop mayor-bot outbounds before
they ever reach the gt-receiver pipeline.
## Test plan
No unit tests added — the alert-hub repo has no test harness
configured in package.json scripts; verification is via live
Slack post-deploy.
- [ ] Deploy via the CI deploy workflow (Doppler-mounted CF
creds).
- [ ] Set ``KNOWN_MAYOR_BOT_USER_IDS="U0B385LBXPT"`` (midgard
mayor — known from Wesley msg 729) via ``wrangler vars`` OR
bind the per-mayor tokens so auth.test resolves them.
- [ ] Post a message via ``MIDGARD_MAYOR_BOT_TOKEN`` to Wesley's
DM channel. Confirm no 📬 / 👀 reaction fires on the bot's own
message.
- [ ] Have Wesley send a real reply in the same thread. Confirm
reactions DO fire on Wesley's message + the gt-receiver row
lands.
- [ ] Post a Hermes message in a midgard-watched channel.
Confirm reactions fire + the message routes (bo-nb97
contract preserved).
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.
Summary
Wesley msg 729: outbound Slack posts via midgard mayor's bot (user_id
U0B385LBXPT) trigger 📬 + 👀 reactions on themselves because the bo-nb97 self-only filter only matches THIS Worker's own bot — not the mayor bots posting THROUGH the shared Slack workspace.Bug chain that lead here:
The bidirectional Worker treats midgard mayor's outbound DM as a real Wesley→mayor inbound, fires 📬 + 👀 reactions, AND re-routes the bot's own message back into its own gt-receiver inbox. Self-conversation loop.
Fix
New
KNOWN_MAYOR_BOT_USER_IDSenv var (comma-separated U… ids) +getMayorBotUserIds(env)resolver that:*_MAYOR_BOT_TOKENenv binding present. Mirrors the bo-nb97getBotUserIdshape.Set<string>the predicateisKnownMayorBot(env, userId)checks against.Predicate wired into all three event handlers:
handleMessage(thread replies)handleDm(DMs to per-mayor apps)handleChannelMention(@-mentions of a per-mayor app)handleMessage scope extension
The bead called out
handleDm+handleChannelMention. I extended tohandleMessagetoo because mayor↔mayor thread replies have the same loop shape — midgard's reply in a yggdrasil-watched alert thread would otherwise be re-routed. Default-deny is the safer floor; if mayor-to-mayor cross-talk becomes a feature, add an opt-in env override.Effect
Test plan
No unit tests added — alert-hub has no test harness configured in
package.json. Verification via live Slack post-deploy:KNOWN_MAYOR_BOT_USER_IDS="U0B385LBXPT"viawrangler varsOR bind the per-mayor tokens so auth.test resolves them.MIDGARD_MAYOR_BOT_TOKENto Wesley's DM. Confirm no 📬 / 👀 reaction.Cross-repo context
Bead
bo-pwibis tracked in the boardroom rig's bd issue tracker. The polecat that produced this PR (boardroom/polecats/dementus) closedbo-pwibwith a back-pointer to this PR.🤖 Generated with Claude Code