diff --git a/docs/DSH-0.1.5-MAIL-CHANNEL-ROOTCAUSE.md b/docs/DSH-0.1.5-MAIL-CHANNEL-ROOTCAUSE.md index 8cc1243..a958f73 100644 --- a/docs/DSH-0.1.5-MAIL-CHANNEL-ROOTCAUSE.md +++ b/docs/DSH-0.1.5-MAIL-CHANNEL-ROOTCAUSE.md @@ -178,7 +178,7 @@ pi 的「其它 34/28」也复现了,且能解释:28 个读不了的里 | 事件数 | 逐文件解压行数比对 | **40/40 一致**,零丢失 | | 大小变化 | 例 `mail-d042cc4c` 25.2MB → 12.5MB | **纯重压缩**(单帧改 500 行/帧),非丢数据 | | v3 修复 | `repair-v3-usermessage-ids.mjs --apply` | **2 个写入成功** | -| 真 mail-* 会话 | 最终验收 | **41/41 可读** | +| 真 mail-* 会话 | 最终验收(`--prefix mail-`) | **43/43 可读** | 反例留档:`~/.dsh/sessions/**` 仍有 3 个非邮件会话读不了,根因是 `subagent/descriptor ... unsupported descriptor version 2`,**与本问题无关**, @@ -265,3 +265,20 @@ dsh 观察到 `readSession()` 成功、`JsonlSessionPersistence.open()` 失败 2. **判定磁盘健康只认 `open()`**:`readSession()` 走 live 内存快照,会掩盖磁盘损坏。 3. **校验与落盘不能共用同一批对象**:验证器会原地改写,dry-run/apply 会因此给出 相反结论。 + +## 16. 度量口径的一个坑:`--only` 是子串匹配 + +第一版验收用 `--only mail-`,得到「47 可读 / 3 不可读」。那 3 个**不是邮件会话**—— +它们的目录名是普通 UUID,只是父目录是 `--home-program-agentmail--`, +而 `agentmail-` 里含子串 `mail-`,被误匹配进来。它们的错因是另一个独立缺陷 +(`subagent/descriptor 0 uses unsupported descriptor version 2`)。 + +换成严格前缀 `--prefix mail-` 后的真实数字: + +``` +候选: 43 可读: 43 不可读: 0 +``` + +⇒ **「真 mail-* 会话 43/43 可读,0 不可读」**。 +度量口径本身也会制造假结论,所以脚本现在两个开关都提供: +`--only`(子串,跑路径片段)与 `--prefix`(目录名严格前缀,点名某类会话时用后者)。 diff --git a/scripts/verify-mail-sessions-readable.mjs b/scripts/verify-mail-sessions-readable.mjs index 1b7d12a..e0265f2 100644 --- a/scripts/verify-mail-sessions-readable.mjs +++ b/scripts/verify-mail-sessions-readable.mjs @@ -27,7 +27,12 @@ const argOf = (flag, dflt) => { return i >= 0 && argv[i + 1] ? argv[i + 1] : dflt; }; const ROOT = argOf("--root", "/root/.dsh/sessions"); -const ONLY = argOf("--only", "mail-"); +// `--only` 是**子串**匹配(保留原语义,便于按路径片段过滤)。 +// 但它会把 `--only mail-` 误匹配到 `--home-program-agentmail--/` 下的普通会话 +// (`agentmail-` 里含 `mail-`),从而把「其他缺陷」报成「邮件会话仍不可读」。 +// 需要「只统计真 mail-* 会话」时用 `--prefix mail-`(目录名严格前缀)。 +const ONLY = argOf("--only", ""); +const PREFIX = argOf("--prefix", ""); const { Context } = await import(join(NM, "cordis/lib/index.js")); @@ -52,6 +57,7 @@ const targets = []; for (const p of walk(ROOT)) { if (ONLY && !p.includes(ONLY)) continue; const id = p.split("/").at(-2); + if (PREFIX && !id.startsWith(PREFIX)) continue; targets.push({ id, path: p }); }