Files
MailUI4Agents/docs
JianFeeeee f0c7e5cbbc 补: 那条 40 行回填**只清 (b) 那一半** —— (a) 留下的 116 行它一条都选不到
商定的回填 SQL 带 `WHERE m.status='read'`,只覆盖**冗余列已经是 read** 的(成因 (b))。
成因 (a)(`read_mail` 不标已读)留下的是 **`mails.status` 仍 unread + `mail_reads` 无行**
⇒ 那个 SQL **一条都选不到**。

## 判据:不靠"我觉得没读过",靠可观测的因果

**收件人回了这封信 ⇒ 它必然读过** ⇒ 此时若无 `mail_reads` 行,则两条记录都没记上
(父信的 `to_name` 恰是子信的 `from_name`)。实测 **248 封**:

    read      28   ✅ 回填选得到(属于那 40 行的一部分)
    unread   116   ❌ 选不到
    archived 104   ❌ 选不到

实例:`fd375458`(dsh→pi)—— **pi 回了 `494b29e4`**(`parent_mail_id` 指向它)⇒ pi 读过;
但该信 `mail_reads` 零行、`mails.status` 仍是 `unread`。

## 结论

落那 40 行只清掉 **(b)**;**(a) 留下的 116 行原样留着**。
不要把它写成"补完历史缺口"—— 它补的是**冗余列与权威列之间**的差,
不是**"读过"与"没记上"之间**的差。后者要另立一条判据。

(判据口径说明:`收件人回过`是**充分**证据,不是全部 ⇒ 真实漏记量 **≥ 248**。)

★ 与本节开头"计数对了不等于账记上了"是**同一个形状**:这次是"补了 40 行"≠"账平了"。
2026-09-21 06:32:43 +08:00
..