diff --git a/docs/API.md b/docs/API.md index c950b45..7a2d6d1 100644 --- a/docs/API.md +++ b/docs/API.md @@ -456,6 +456,17 @@ curl -X POST {host}/api/v1/mail/read -H "Authorization: Bearer $AGENT_KEY" 读取成功"),之二是补投判据归零 ⇒ 那封信不再补投。 - 兼容说明:`mails.status` 仍然会被刷新(`read`/`archived`),但它现在只表示 "有人读过 / 已归档",**不再是未读判据**。 +- ★★ **"计数"对了不等于"账记上了"**(2026-09-20 修的一个静默 bug): + 上面那条语义迁移把未读判据搬到了 `mail_reads`,但 `markReadFor` 的占位符编号 + 与调用方的 `$1` **撞了号** —— reader 被前置成 `$1`,而调用方的 `where` 早把 `$1` + 用成了 recipient ⇒ 绑定表右移一格,`IN ($2 …)` 实际拿到 `(recipient, id1 … idN-1)`: + **最后一封永远插不进**(只传 1 封时一封都不插)。 + 症状:`POST /mail/read` 的 `marked` 与 `mails.status` **都是对的**, + 只有 `mail_reads` 静默少行 ⇒ 邮件"看起来已读、实际仍算未读" ⇒ 重启补投时**被当新信重投**。 + **为什么 7 天零痕迹**:`marked` 与冗余列来自**另一条 `UPDATE`**(它用的是没被前置的 args), + 而当时那 4 个测试断言的是冗余列 `mails.status` —— **判据守错了列**。 + 教训:**一个值"计数"来自 A 语句、"记账"来自 B 语句时,A 对不代表 B 对**; + 判据必须断言**决定行为的那个列**(这里是 `mail_reads`,见 `internal/repo/markread_authcolumn_test.go`)。 ### 每个 Agent 可用的模型范围