Files
Cyrene_v2/internal/services/channelbridge/judge_reason.go
T
AskaEth 76263d42ed fix(upstream): M51 复审 p2 三条 —— light.go 同形出口 / MCP SDK 日志面 / ErrorToken 口径
① light.go 的 2 处 "light judge: " + d.Reason 与 engage.go 同形(model reason →
返回值 → coalesce_prepare 的 Debug)。把上一轮的 engageReason 提成包内共用的
judgeReason(judge_reason.go,RedactTextLimited + strings.Fields,60 rune),
engage.go 7 处 + light.go 2 处 + notice.go 的 "notice review failed: "+err.Error()
统一走它。控制流零改动:只换「进去的那份文本」,判定条件与返回值拼接结构未动。

② MCP 的 Logger 面先探针后修:go-sdk v1.8.0 的 keepalive 会把对端 JSON-RPC error
原样打进日志(实测泄漏,见 sdklog_probe_test.go 的输出),tools/call 路径不打日志。
新增 sdklog.go:redactingLogger 交给 SDK,wire 错误(链上有 *jsonrpc.Error)只留
code + message_bytes(复用 upstreamError),本地错误保留原因,消息/属性压平+打码+300 rune。

③ errortoken.go 的口径注释纠正:从「包外不得调用」改为按字段类别判定(协议枚举可守、
自由文本默认不带),并把 cdp.go 这条 M51 用法作为例子写进去。
2026-10-26 20:00:57 +08:00

44 lines
2.5 KiB
Go

package channelbridge
// 本文件是「判定模型/上游回来的自由文本怎么写进返回值与日志」的唯一收敛点。
//
// 它的三个使用者都是同一类出口:模型(或上游)给一句 reason,我们把它拼进返回值、
// 再被上层落进日志 ——
// - engage.go 的参与度判定(5 处 Debug + 2 处返回值);
// - light.go 的旧轻量判定(2 处返回值,落到 coalesce_prepare.go 的 Debug);
// - notice.go 的系统通知剔噪失败原因(拼进 noticeOutcome.Reason,落到事件 Debug)。
//
// 这类文本的两种病害都真实存在:模型可以把 Authorization / sk-… 回显进 reason(凭据),
// 也可以塞一个换行(在按行聚合的日志里伪造出「另一条记录」)。因此出镜前必须
// 「压平 + 打码 + 截断」,而且**只有这一份实现** —— 三处各写一份必然漂移,漂移的方向
// 总是「其中一处为了多带点诊断把原文留下来」。
import (
"strings"
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/trace"
)
// judgeReasonRunes 是这类 reason 允许出镜的 rune 上限。
//
// 取 60 的理由:这些 reason 由「只输出 JSON 对象」的轻量判定器给出,实际值是一句短语
// (「群里在聊周末安排,与角色无关」≈ 16 字),60 rune 容得下三四句这样的短语;一旦
// 超过 60 rune,说明它在**复述群聊原文** —— 那部分对排障没有价值(要的是「判定方向 +
// 方向词」),却正是最不该进日志的那段话。
const judgeReasonRunes = 60
// judgeReason 把一段判定/上游 reason 整理成可以出镜的短句(返回值与日志共用这同一份,
// 口径不会分叉):
//
// - 压平空白:一个换行就能在按行聚合的日志里伪造出「另一条记录」;返回值也会流进
// 日志(coalesce_prepare 的 Debug),所以同样要压;
// - 凭据清洗走 trace.RedactTextLimited(与 trace.RedactText 同一实现,不是第二套
// 脱敏路径):模型可能把 Authorization / sk-… 之类原样回显进 reason;
// - 截到 judgeReasonRunes(见上)。
//
// 🔴 本函数只决定「进去的那份文本」,不参与任何判定:调用点的分支条件、状态迁移与
// 返回值拼接结构一个字都不动(2026-10-26 塔口径)。
func judgeReason(raw string) string {
return trace.RedactTextLimited(strings.Join(strings.Fields(raw), " "), judgeReasonRunes)
}