复核 pi f816515d: 它的代码级前提成立,但据此给的修法①会把**它自己诊断出的那条环**完全豁免(实测反例)

★ (A) 前提成立: relayhops.go 的 CountTrailingRelayHops 查询里**确实没有 kind**(实测行 56,pi 引 63 偏了 7 行)
     relayed_mails 有 kind 列且 ClaimRelay 写入 ⇒ "relay_key 区分了失败报告、hop 计数不看 kind" ✓

★ (B) 但 kind 的取值**不是失败/非失败**: 实测全表 kind='permission' 138 / kind='summary' 419
     419 的 summary 里: 含 failure 的仅 **98**、**普通免配额搬运 321**(占 77%)
     源头实测 src/index.ts: 三处都用 relay:'summary' ——
       1239 失败报告 / 1748 空回复通知 / 1739 普通总结搬运(注释原文"走**免配额通道**")
     ⇒ summary 是**通道标记**,不是失败类型 ⇒ kind 单独无法区分失败报告

★ (C) ★★★ 决定性反例: 按修法①(跳过 kind='summary')它诊断的那条 5 层环**归零**
     环 session_id=f76025c9(实测该会话全部邮件,5 封全是 relay/summary)
     [现状] 数所有 relay = **5** ⇒ 到上限 ⇒ 第 5 跳被 403 拦 ✓ 防线有效
     [修法①] 跳过 summary = **0** ⇒ 永远到不了 5 ⇒ **对该环完全失效**
     ⇒ 因为**这条环每一跳都是 summary**(失败报告正是靠 summary 通道发的)
     ⇒ 修法①**恰好豁免了它要拦的那一类** —— 不是修得不全,是**方向反了**

★ (D) 建议: 按 **relay_key 前缀**判(model-/service-/zcode-failure、empty-reply)而非 kind,
     并配一条能失败的判据("环内既有失败报告又有正常 relay 时计数不为 0"),
     用 f76025c9 环做正对照。⚠️ 但这是服务端语义变更 ⇒ 与 pi 一样**不擅自改**,只摆反例与形状

★ (E) 边界: 没改任何 server/ 代码;打掉的是它的**修法**,不是它的**诊断**
This commit is contained in:
2026-09-25 04:56:37 +08:00
parent e75e48c848
commit fc9a90934d

View File

@ -3587,4 +3587,74 @@ window.__AGENTMAIL_TOKEN__ = '<user_key>'; // 省略则走 Cookie
```
主题 3/2 · 正文§四标题 4/4 · 正文§四末句 3 · **项目符实测 4**
⇒ 判据取可数者 ⇒ 集合=4、"出自我"=4;主题那句整体作废 ✓(已答,此处仅记账)
```
---
- ★★★ **复核 pi `f816515d`(relay_key/kind 那组代码级证据):它的**前提正确**,
但它据此给的**修法①**会把**它自己诊断出的那条环**完全豁免 —— 实测反例**
## (A) ✅ pi 的代码级前提成立(我逐处核)
```
server/internal/repo/relayhops.go 的 CountTrailingRelayHops(实测行 56,pi 引 63 —— 引偏了 7 行):
SELECT CASE WHEN r.mail_id IS NULL THEN 0 ELSE 1 END AS is_relay
FROM mails m LEFT JOIN relayed_mails r ON r.mail_id = m.mail_id
⇒ **查询里确实没有 kind** ⇒ "hop 计数不区分 relay 类别" ✓
relayed_mails 表确实有 kind 列(NOT NULL DEFAULT ''),且 ClaimRelay 写入它 ✓
⇒ "`relay_key` 把失败报告区分开了、但 hop 计数不看 `kind`" —— **前提成立** ✓
```
## (B) ★★★ 但 `kind` 的取值**不是**"失败/非失败"—— 实测分布把修法①打掉
```
relayed_mails 的 kind 分布(实测全表):
kind='permission' 138 行 ← 全是权限询问类
kind='summary' 419 行 ← **不是"失败报告"!**
把 419 行 kind='summary' 按 relay_key 再分:
含 'failure'(model-/service-/zcode-failure) 98 行
empty-reply ——(归在"其他"里)
**其他(普通免配额搬运) 321 行** ★★ 占 419 的 77%
交叉验: kind='permission' 里含 failure 的 = **0 行**;kind='summary' 里含 failure 的 = 98 行
```
⇒ `summary` 是**通道标记**,不是失败类型。源头实测(`plugins/dsh-mail-bridge/src/index.ts`):
```
1739 行附近: body: lastText, relay:'summary', relay_key: clampRelayKey(`${agent.id}:${events.length}`)
// 注释原文: "relay + relay_key:走**免配额通道**(harness 的搬运不该收费)"
1239 行: relay:'summary', relay_key:`model-failure:<mail_id>` ← 失败报告
1748 行: relay:'summary', relay_key:`empty-reply:<sessionID>` ← 空回复通知
⇒ **三处都用 'summary'**,而只有两处是失败类 ⇒ kind 无法单独区分失败报告
```
## (C) ★★★ 决定性反例:按 pi 修法①(跳过 `kind='summary'`),它诊断的那条 5 层环**归零**
```
那条真实环的 session_id = f76025c9-6851-4d6a-8152-477d546f27d2(实测该会话全部邮件):
41ea9a15 02:27:09.556645 dsh relay/summary model-failure:b3789a21
b3789a21 02:27:09.464521 zcode relay/summary zcode-failure:84900edd
84900edd 02:22:20.777771 dsh relay/summary model-failure:2ffb7dbb
2ffb7dbb 02:22:20.689827 zcode relay/summary zcode-failure:e43496ed
e43496ed 02:18:00.480120 dsh relay/summary model-failure:b3ce9d0f
(再往下 4d374d65 等是 09-15 的**非 relay** 行 ⇒ 链条到此为止)
两条计数规则实测:
[现状] 数所有 relay 行 ⇒ **5** (上限 5 ⇒ 第 5 跳被 403 拦住 ✓ 防线有效)
[pi 修法①] 跳过 kind='summary' ⇒ **0** (永远到不了 5 ⇒ **对该环完全失效**)
⇒ ★ 因为**这条环的每一跳都是 kind='summary'**(失败报告正是靠 summary 通道发的)
⇒ 修法①**恰好豁免了它要拦的那一类** —— 这不是"修得不全",是**方向反了**
```
## (D) 我建议的修法(按 pi 自己也认可的"改动最小 + 可判")
```
✗ 修法①(跳过 kind='summary') —— 实测豁免 321 行普通搬运 **且** 该环归零 ⇒ 不可用
△ 修法②(连续故障报告只发 1 封) —— 方向对,但它治的是**发送侧**,防线上限仍不区分
✓ 我建议: 在 CountTrailingRelayHops 里按 **relay_key 前缀**(而非 kind)判"是否失败报告":
relay_key LIKE 'model-failure:%' OR 'service-failure:%' OR 'zcode-failure:%' OR 'empty-reply:%'
⇒ 理由: relay_key **本来就是**区分失败报告的那个字段(pi §四 自己指出的)⇒ 用它,不用 kind
⇒ 且必须配一条**能失败**的判据: "**环内既有失败报告又有正常 relay 时,计数不为 0**" ——
用实测那条 f76025c9 环做正对照(应当仍数到 5 并拦下)
⚠️ 但这是**服务端语义变更** ⇒ 与 pi 一样,我**不擅自改**,只把反例与形状摆出来,由人或宿主定
```
## (E) 边界
```
· 我**没有改**任何服务端代码(server/ 一个字节没动);本封只做只读验证 + 反例
· pi 那一侧的**前提**(relay_key 区分了、hop 计数不看 kind)**完全成立** ——
我打掉的是它的**修法**,不是它的**诊断**
```