四处测试健康债务,只改 *_test.go,不动生产代码、不降并发: - channelbridge:stubChatter / stubSessions 的跨 goroutine 字段一律经 mu 访问 (Run/GetOrCreate 在车道 worker 上写、测试 goroutine 读,两者无 happens-before; 负向断言「等一会儿再看循环有没有被驱动」尤其如此)。读写走访问器,Messages() 返回副本;t.Parallel 与并发度不变。 - plugins/tools/io:claimProbeTimeout 2s(真实时间预算)→ 60s,并由 claimProbeWait 按 t.Deadline 收缩。探针只等 goroutine 被调度(无时间语义),放大余量把 「机器快慢」从断言里去掉,死锁仍以断言失败暴露。 - backthink:TestSelfWakeGate_WindowExpiry 窗口 120ms → 6s(给 waitFor 的 4s 上界 留 2s 余量),到期等待改为按首次受理时刻推算 window+250ms,不再盲睡 3×窗口。 另修 TestSelfWakeStatus_MatchesReceiptAndTracksPendingSlot:worker 先 take 再进 Think,卡 Think 并不占待跑槽 —— 改为「上一轮把 worker 占住再断言 Pending」。 - memory:墙钟实测用例显式给闸 5s 预算(measureGateBudget),不再因默认 150ms 超时 fail-open 打炸「每轮都真扫真判」前置断言;并把 GateFailed 纳入该断言。
裁定(已发安卓):**能修**,走**写入侧规整** —— 不指望模型输出、不动客户端。 - 新增 internal/runtime/turnreply/paragraph.go 的 NormalizeParagraphs: 把未被 <p> 包裹的段落补上 <p>(按空行分段;<action>/<narration> 段也包进 <p>, 与正确形态 <p><action>…</action>…</p> 一致) - **幂等**守门断言:已完全包裹的文本逐字不变(防二次加工) - 落点覆盖 Web 与 IM 两条落库路径(gateway/session_turn_reply.go、channelbridge/turnreply.go、 proactive.go)⇒ 两边共用同一份规整文本 ⇒ **历史一次性变好、两个客户端零改动**、渲染口径不分叉 (测试与变异详见切片报告)
根因(agent-194,文件:行): - inbound.go 的 deliverReply 对空回复直接 return(静默)⇒ 只剩 user 消息; - runInboundTurn 报错直接 return ⇒ 失败回合连说明都没有。 修法:抽共享**纯函数**包 internal/runtime/turnreply(从网关逐字搬运、零语义改动)+ channelbridge/turnreply.go 的 turnVisibleReply(与网关 persistTurnReply 同构); 取消边界在 IM 用 context.Canceled / ctx 取消表达(渠道桥无代次概念,如实登记差异)。 测试 6 条:空回复/纯空白/轮次用尽/安全网/回合报错/取消不落库/正常逐字不变。 变异:还原旧静默行为 ⇒ 4 条红(含「出站 0 条,want 1」与英文内部诊断外泄)。