Skip to content

fix(bridge): tighten final fallback suppression coverage#114

Merged
deepcoldy merged 2 commits into
deepcoldy:masterfrom
xiongz-c:codex/refine-bridge-fallback-coverage
Jun 5, 2026
Merged

fix(bridge): tighten final fallback suppression coverage#114
deepcoldy merged 2 commits into
deepcoldy:masterfrom
xiongz-c:codex/refine-bridge-fallback-coverage

Conversation

@xiongz-c

@xiongz-c xiongz-c commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

背景 / 现象

这是 #103 的 follow-up。#103 已经修复了“同一 turn 里只要出现过 botmux send marker,就可能吞掉 Codex transcript final fallback”的主问题,但第一版 marker 覆盖判断仍然偏宽。

如果显式发送的进度消息或部分正文刚好是最终回答的前缀,单纯判断“片段出现在 finalText 中”仍可能把完整 final 误判成已送达。同时,多条无关进度消息的累计长度也不应该被当作 final 已覆盖。

修复

  • botmux send marker 不再保存明文正文片段,改为保存归一化正文的完整 hash、prefix hash、suffix hash 和长度
  • shouldSuppressBridgeEmit() 只在以下情况下抑制 transcript fallback:
    • 显式发送内容的完整 hash 与 finalText 匹配
    • 或 prefix/suffix hash 都匹配,且显式发送长度覆盖 finalText 的 95% 以上
  • 不再用“任意片段出现在 finalText 中”或“多条 marker 累计长度足够”来判断 final 已覆盖
  • 短的“已发送/已回复/sent/done”类 transcript 确认语,在已有结构化 marker 时仍保守抑制,避免重复刷确认消息
  • 旧 marker 缺少正文 hash 元数据时仍保持原来的保守行为,避免兼容期内产生重复回复
  • codex-app / Mira 的 OSC final marker 路径也复用同一个内容感知 gate,不再只按时间窗口抑制

回归覆盖

新增/更新测试覆盖:

  • 结构化 marker 内容完整匹配 transcript final 时,fallback 仍会被抑制
  • 结构化进度 marker 不覆盖较长 transcript final 时,fallback 不再被抑制
  • 只发送 final 前缀、缺少尾部内容时,不应吞掉完整 final
  • 多条无关进度 marker 即使累计长度较大,也不应吞掉完整 final
  • 短确认语在已有结构化 marker 时仍保持抑制
  • CodexBridgeQueue 集成场景:同一 turn 先有显式进度 send,随后 transcript 产生完整 final answer,最终应 emit fallback

验证

  • pnpm test -- test/bridge-fallback-gate.test.ts test/codex-bridge-queue.test.ts:52 tests 通过
  • pnpm build:通过
  • git diff --check:通过

影响范围

只收紧 bridge fallback suppression 的覆盖判定:显式 final send 仍会抑制 fallback;仅当同一 turn 的显式 send 看起来只是进度消息、部分前缀或无关中间消息、没有覆盖 transcript final 时,Codex final fallback 会继续发出。旧 marker 仍按原保守逻辑处理。

@xiongz-c xiongz-c requested a review from deepcoldy as a code owner June 4, 2026 12:45
@deepcoldy

Copy link
Copy Markdown
Owner

我的观察是,模型的输出跟botmux send不严格一致的话,这时是不是就会命中兜底,多发一条消息?
我理解是:因为botmux send后,模型认为不需要再重复一遍了,就会输出一些简短的内容。
不知道你那边测试后感受如何?会不会多很多重复的兜底?

@xiongz-c

xiongz-c commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator Author

我的观察是,模型的输出跟botmux send不严格一致的话,这时是不是就会命中兜底,多发一条消息? 我理解是:因为botmux send后,模型认为不需要再重复一遍了,就会输出一些简短的内容。 不知道你那边测试后感受如何?会不会多很多重复的兜底?

我本地测了一下,确实有这个问题。会导致一些重复的 复述/改写 被发出来。我尝试收紧一些判断,让有明显差异的final再发出来,感觉会好一些。我再改改让Codex跑我历史对话记录量化一下重复率

@xiongz-c

xiongz-c commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator Author

这个 follow-up 的目标是让 #103 之后仍被保守 suppress 的 final 多放出来一些(匹配逻辑太粗暴):如果同一轮里 botmux send 只发了进度/片段,而 transcript final 里还有完整结果,就应该有机会 fallback 发出来。

这个pr首版改动的问题是又太宽松。它用 hash/prefix/suffix 判断 send 是否覆盖 final,只要 final 和显式 botmux send 不完全覆盖,就可能再 fallback 一条。实际模型经常会在 botmux send 后输出短收尾或复述,这类内容再发到群里会比较重复。

我测试了我实际使用botmux的历史记录:

  • 首版逻辑:187 个可比较 case 里会放行 152 个,约 81%,相当于大部分 final 都会额外走 fallback,重复风险很高

新的实现改成更保守的长度阈值判断逻辑:marker 只记录 contentLength;如果 final 没有明显长于任意一条显式 botmux send,就继续 suppress;只有当 finalLength >= maxSentLength * 2finalLength - maxSentLength >= 120 时才允许 fallback。这里用单条 send 的最大长度,不累计多条 send,避免多条短进度把完整 final 吞掉。

  • 新逻辑测试结果:在252 个可比较 case 里只放行 4 个,约 1.6%。
  • 人工检查新版放行的 4 个 case,4/4 都属于“显式 send 是短进度/片段,transcript final 有更完整结果”的有价值补发;没有看到短收尾/复述型重复。基本验证放行出来的都是比较有价值的信息,是对#103的正向优化,在这批样本里没有看到短收尾/复述型重复。

这个阈值是经验值,当前取舍是优先避免重复刷屏,同时补出一些高置信的有价值 final。后续如果真实使用里发现仍然太保守或太宽松,可以继续调 ratio/delta。用一个比较简单的工程实现让飞书可以接收更多信息提高体验。

Validation:

  • pnpm test -- test/bridge-fallback-gate.test.ts test/codex-bridge-queue.test.ts
  • pnpm build
  • git diff --check

@deepcoldy deepcoldy merged commit c9fddf5 into deepcoldy:master Jun 5, 2026
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.

2 participants