文档: API.md 记一条 —— **"计数"对了不代表"账记上了"**(已读权威列静默少行)

接在「已读按调用者记录」那节后面(同一段语义迁移的下游后果)。

`markReadFor` 把 reader 前置成 `$1`,而调用方 `where` 早把 `$1` 用成 recipient
⇒ 绑定表右移一格 ⇒ 最后一封永远插不进(单封一封都不插)。
`marked` 与 `mails.status` 都对,只有权威列 `mail_reads` 静默少行
⇒ 邮件"看起来已读、实际仍算未读" ⇒ 重启补投时被当新信重投。

**为什么 7 天零痕迹**:`marked` 来自**另一条 UPDATE**,而当时那 4 个测试断言的
是冗余列 `mails.status` —— **判据守错了列**。

教训(写成可复用的):**一个值的"计数"来自 A 语句、"记账"来自 B 语句时,
A 对不代表 B 对;判据必须断言决定行为的那个列。**
修在 `17908c1`,回归判据 `internal/repo/markread_authcolumn_test.go`。
This commit is contained in:
2026-09-21 04:26:49 +08:00
parent 17908c1623
commit 63d430f423

View File

@ -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 可用的模型范围