fix(slack): bypass mention gate for app_mention events#53161
fix(slack): bypass mention gate for app_mention events#53161adk47 wants to merge 1 commit intoopenclaw:mainfrom
Conversation
When requireMention is true, the mention gate checks message text for bot mentions. However, Slack delivers both `message` and `app_mention` events for @mentions, with no guaranteed order. When the `message` event arrives first and is processed (or deduped), the subsequent `app_mention` event can be incorrectly dropped by the mention gate even though Slack has confirmed the bot was explicitly mentioned. This fix skips the mention gate when opts.source is "app_mention", since Slack's app_mention event is only delivered to the mentioned bot's app — the mention is already confirmed at the platform level. The existing dedup + retry mechanism (rememberAppMentionRetryKey / consumeAppMentionRetryKey) addresses part of this issue but doesn't cover the case where the mention gate itself blocks the app_mention event after it passes dedup. Fixes openclaw#34833 Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Greptile SummaryThis PR fixes a silent message-drop bug in the Slack integration where Key points:
Confidence Score: 4/5
Prompt To Fix All With AIThis is a comment left during a code review.
Path: extensions/slack/src/monitor/message-handler/prepare.ts
Line: 496
Comment:
**Missing unit test for the prepare.ts change**
The fix bypasses the mention gate when `opts.source === "app_mention"`, but `prepare.test.ts` has no test for `requireMention: true` scenarios at all, and no test exercising the new `opts.source === "app_mention"` branch.
This matters because `opts.wasMentioned: true` is always set in `messages.ts` for `app_mention` events, which means `effectiveWasMentioned` is already `true` and `mentionGate.shouldSkip` would already be `false` in the typical flow — making it hard to verify from tests alone when the gate was previously wrong.
A targeted unit test in `prepare.test.ts` along these lines would lock in the intended behavior:
```ts
it("skips mention gate when source is app_mention even if text-based detection fails", async () => {
// ctx.botUserId set, mention text absent, requireMention: true, source: "app_mention"
const prepared = await prepareSlackMessage({
ctx: buildCtx({ requireMention: true, botUserId: "U_BOT" }),
account,
message: buildMessage({ channel: "C1", text: "hello" }), // no <@U_BOT>
opts: { source: "app_mention", wasMentioned: false }, // simulate text-detection failure
});
expect(prepared).not.toBeNull();
});
```
Without this, the fix is hard to verify in isolation and a future refactor of `opts.wasMentioned` propagation could silently reintroduce the bug without a test catching it.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(slack): bypass mention gate for app_..." | Re-trigger Greptile |
| // app_mention, sets dedup key, then app_mention is either deduped or the text-based | ||
| // mention check fails because the message was already processed without wasMentioned). | ||
| // See: https://github.com/openclaw/openclaw/issues/34833 | ||
| if (isRoom && shouldRequireMention && mentionGate.shouldSkip && opts.source !== "app_mention") { |
There was a problem hiding this comment.
Missing unit test for the prepare.ts change
The fix bypasses the mention gate when opts.source === "app_mention", but prepare.test.ts has no test for requireMention: true scenarios at all, and no test exercising the new opts.source === "app_mention" branch.
This matters because opts.wasMentioned: true is always set in messages.ts for app_mention events, which means effectiveWasMentioned is already true and mentionGate.shouldSkip would already be false in the typical flow — making it hard to verify from tests alone when the gate was previously wrong.
A targeted unit test in prepare.test.ts along these lines would lock in the intended behavior:
it("skips mention gate when source is app_mention even if text-based detection fails", async () => {
// ctx.botUserId set, mention text absent, requireMention: true, source: "app_mention"
const prepared = await prepareSlackMessage({
ctx: buildCtx({ requireMention: true, botUserId: "U_BOT" }),
account,
message: buildMessage({ channel: "C1", text: "hello" }), // no <@U_BOT>
opts: { source: "app_mention", wasMentioned: false }, // simulate text-detection failure
});
expect(prepared).not.toBeNull();
});Without this, the fix is hard to verify in isolation and a future refactor of opts.wasMentioned propagation could silently reintroduce the bug without a test catching it.
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/slack/src/monitor/message-handler/prepare.ts
Line: 496
Comment:
**Missing unit test for the prepare.ts change**
The fix bypasses the mention gate when `opts.source === "app_mention"`, but `prepare.test.ts` has no test for `requireMention: true` scenarios at all, and no test exercising the new `opts.source === "app_mention"` branch.
This matters because `opts.wasMentioned: true` is always set in `messages.ts` for `app_mention` events, which means `effectiveWasMentioned` is already `true` and `mentionGate.shouldSkip` would already be `false` in the typical flow — making it hard to verify from tests alone when the gate was previously wrong.
A targeted unit test in `prepare.test.ts` along these lines would lock in the intended behavior:
```ts
it("skips mention gate when source is app_mention even if text-based detection fails", async () => {
// ctx.botUserId set, mention text absent, requireMention: true, source: "app_mention"
const prepared = await prepareSlackMessage({
ctx: buildCtx({ requireMention: true, botUserId: "U_BOT" }),
account,
message: buildMessage({ channel: "C1", text: "hello" }), // no <@U_BOT>
opts: { source: "app_mention", wasMentioned: false }, // simulate text-detection failure
});
expect(prepared).not.toBeNull();
});
```
Without this, the fix is hard to verify in isolation and a future refactor of `opts.wasMentioned` propagation could silently reintroduce the bug without a test catching it.
How can I resolve this? If you propose a fix, please make it concise.|
I don't think this fixes the reported bug.
So by the time execution reaches this guard in If the symptom in #34833 is real, I suspect the bug is earlier in the dedup/race path in Could you add a failing test that reproduces the actual drop? I think the right place is probably |
Summary
When
requireMention: trueis set,app_mentionevents from Slack are incorrectly dropped by the mention gate inprepareSlackMessage. This causes ~50-100% of @mentions in channels to be silently ignored in multi-bot setups.Root Cause
The mention gate at
prepare.ts:490checksmentionGate.shouldSkipwithout considering the event source. Whenopts.source === "app_mention", Slack has already confirmed the bot was explicitly mentioned -- the text-based mention detection is redundant and can fail due to:messageevent arrives first, sets dedup key,app_mentionpasses dedup via retry but still hits the mention gatemessagehandler processes the event independently -- the mention text check can intermittently fail depending on timingFix
Skip the mention gate when
opts.source === "app_mention". Slack'sapp_mentionevent is only delivered to the mentioned bot's app, so the mention is already confirmed at the platform level.Testing
requireMention: truereason: "no-mention"Fixes #34833