Files
MailUI4Agents/docs
JianFeeeee 18f194f924 改: 判据收洞(机器回信不算"回过")+ 写清 T-12 的语义空白;★ 记我自己的量错两处
pi 指出我那条 `收件人回过 ⇒ 必然读过` 有一个洞。**逐条复核成立**,已改。

## 一★ 洞:**机器回信**也被算成了"回过"

"回"只有在**是模型的产物**时才蕴含"读过"。桥有**自动**回信路径 ——
模型一次都没跑起来时,桥代它回一封 `处理失败: <父主题>`:

    pi     src/worker.mjs:619 / :711
    zcode  src/index.mjs:300
    dsh    src/index.ts:1215 / :1719     ← dsh 侧也有,pi 只列了 3 处

⇒ **那封"回信"恰恰是"没读过"的证据。**

精确模板匹配实测(`status='unread'`):

    宽松:任意孩子(含机器回信)        114
    严格:**至少一个孩子不是**机器模板   105
    差                                  9   ← 与 pi 独立列出的 9 封**完全一致**

## 二★ 我自己在这条上先写错了量词(复核时才抓到)

我第一版写成 `NOT EXISTS(… AND ch.subject NOT LIKE '处理失败:%')` ——
**那问的是"一个真回信都没有",是反向量词**,实测只剩 **9 封**(正好是那批机器信)。
**判据从 105 翻成 9,照样返回行、照样不报错 —— 静默答错。**
正确写法是**带模板排除的存在量词**(已写进 docs 的 SQL)。
★ 又一次"先写结论、后复核",顺序反了。另记"并存"2 封(真回信+机器通知,均 `status=read`)
说明**不能用"父信含机器孩子就排除"的粗写法**。

## 三、T-12 的语义空白已写进契约(四个桥逐个量过)

`read_mail` 是否产生"已读",契约沉默。**四个桥各只有 1 处 `/mail/read`,且四处都只在 `read_inbox` 里**:

    dsh      src/index.ts:1340     read_inbox(:1302)
    pi       src/tools.mjs:188     read_inbox(:159)
    zcode    lib/tools.mjs:155     read_inbox(:120)
    opencode index.js:291          —

而 `read_mail` 实现体只有 `client.get(...)` ⇒ **"只取正文、不改状态"是各桥一致的设计意图**。
⇒ 写进契约:**`read_mail` 不产生已读状态 ⇒ 未读计数不等于"没人读过"**;
治法是把语义写进契约,**不是多回填几行**((a) 本来就没有权威记录,补只是猜)。

## 四★ 记我自己的量错两处(同一形状,连错两次)

做上面那张四桥表时,我**两次**把"grep 返回空"读成了"没有":

1. opencode:grep 了 `opencode-mail-bridge/src/` —— **该目录不存在**,源码在包根 `index.js`。
2. zcode:grep 了 `zcode-mail-bridge/src/`(存在,但标已读那行在 `lib/tools.mjs`)。

**`grep` 对不存在的目录不报错、只返回空** ⇒ "路径写错"与"真的没有"**读数完全相同**。
⇒ **数一个东西"有几处"之前,先确认搜索路径存在、且覆盖所有落点。**
(第二次之所以抓到,是因为我改完表**回去逐处 `sed -n '<n>p'` 对行号** ——
只按 `grep -c` 收工,这张表就会带着两个"0 处"进仓库。)

★ 另修一处**漂移的绝对数**:严格口径下"会话未归档"是 **74**(我先前写 83,是旧口径的残留)。
已在 docs 注明该数会随我们的往来漂移,**只当量级、不当阈值**。
2026-09-21 07:00:30 +08:00
..