@@ -218,6 +218,16 @@ describe('resolveMentionGate', () => {
218218 it ( 'allows non-group chat types without @mention' , async ( ) => {
219219 expect ( await resolveMentionGate ( { ...baseInput , chatType : 'supergroup' } ) ) . toBe ( 'non_group' ) ;
220220 } ) ;
221+
222+ it ( 'blocks thread bypass when another (separate-service) bot is @mentioned' , async ( ) => {
223+ // 单 bot 模式:DevBot 是话题创建者,但用户 @ 了群里另一个独立服务的 bot。
224+ // 旧逻辑单 bot 路径无 mention 闸 → bypass 放行抢答;修复后 @非自己 → 不 bypass。
225+ mockGetThreadSession . mockReturnValue ( { userId : 'ou_user_1' , createdAt : new Date ( ) . toISOString ( ) } ) ;
226+ const otherBotMention = { id : { open_id : 'ou_separate_service_bot' } } ;
227+ expect ( await resolveMentionGate ( {
228+ ...baseInput , threadId : 'omt_123' , mentions : [ otherBotMention ] ,
229+ } ) ) . toBeUndefined ( ) ;
230+ } ) ;
221231 } ) ;
222232
223233 // ── 多 bot 模式 ──
@@ -321,6 +331,24 @@ describe('resolveMentionGate', () => {
321331 ...baseInput , mentions : [ otherBotMention ] , threadId : 'omt_existing_topic' ,
322332 } ) ) . toBeUndefined ( ) ;
323333 } ) ;
334+
335+ it ( 'blocks thread_bypass when @mentioned party is unrecognized as bot (cross-app open_id)' , async ( ) => {
336+ // 真实 bug 复现:本 bot(dev) 是话题创建者,用户在话题里 @ 了另一个 bot。
337+ // 飞书 open_id 按 app 隔离,被 @ 的 bot 在本 app 视角下的 open_id 不在 knownBotIds 里,
338+ // 旧逻辑 anyBotMentioned=false → 命中 thread_bypass 抢答。
339+ // 修复后:只要 @ 了"非自己",就不 bypass。
340+ mockGetThreadSession . mockImplementation ( ( _ : string , agentId ?: string ) => {
341+ if ( agentId === 'dev' ) return { userId : 'ou_user_1' , createdAt : '2026-01-01T00:00:00Z' } ;
342+ return undefined ;
343+ } ) ;
344+ const foreignBotMention = { id : { open_id : 'ou_other_bot_foreign_scope' } } ;
345+ expect ( await resolveMentionGate ( {
346+ ...baseInput ,
347+ mentions : [ foreignBotMention ] ,
348+ threadId : 'omt_existing_topic' ,
349+ text : '@张全栈 接下来做啥' ,
350+ } ) ) . toBeUndefined ( ) ;
351+ } ) ;
324352 } ) ;
325353
326354 // ── 边界情况 ──
0 commit comments