JianFeeeee
35557d4f8d
test(pi桥): 补两格判据 —— BoundedSet 淘汰使「重启才丢」的前提站不住
`markDelivered` 的注释写「标不上不该让投递失败……代价只是下次重启可能再投
一次」。opencode 独立复核指出这句话的前提站不住,我认这个判断。
「下次重启」把正确性押在「重启 ⇒ 内存全丢 ⇒ 从库里重来」上。但
`deliveredMails` 是 `BoundedSet(MAX_TRACKED_MAILS=2000)`,**运行期就主动淘汰**,
不需要重启。于是有一条更窄的重投路径:
投递 X ⇒ add(X) → POST /mail/read 失败(库里仍是 unread)
→ X 超过 2000 被淘汰(内存忘了,库没忘)
→ catchUp 按 unread 捞回 X,内存 has() 挡不住 ⇒ 重投
正是 2026-09-26 那个症状本身(重投回声),只是窗口窄得多。
两格分别锁住前提与后果,都不靠注释断言:
⑤ `deliveredMails 确实是有界的` —— 从 index.mjs 取上限常量名,回 bounded.js
取其值并断言有限。有限 ⇒ 运行期会淘汰 ⇒ 「靠重启才丢」不成立。
⑥ `淘汰只丢内存、不回写库` —— 覆盖 BoundedSet.add 的整个淘汰循环,
断言其中无 /mail/read|markDelivered|post|status|client;并对照
markDelivered 的失败分支只打日志、不重试不回滚。
将来若让淘汰也落库,这格会红,提醒改的是注释而不是加静音。
变异自测(三个变异各被对应格抓住,非自说自话):
改成无界 `new Set()` → ⑤ 红
淘汰路径里回写库 → ⑥ 红
markDelivered 失败后 setTimeout 重试 → ⑥ 红
判据自带的两个坑留在注释里(第一版「怎么变异都不判红」的原因):
必须锚在 BoundedSet 的 add 上,否则裸 /add\(value\)/ 会先命中文件前面
BoundedMap 的同形 add;淘汰循环要带尾巴({0,320}? 惰性量词会在第一个终点
就停),否则紧跟其后的落库代码永远落在窗口之外,结构上不可能判红。
全量 526 格通过。未修 —— 本提交只把已知窗口钉成可判红的判据,
不动 `markDelivered` 的行为(改行为是另一次决定,且应先决定淘汰时
要不要落库)。
Co-Authored-By: pi <pi@agentmail>
2026-09-28 09:57:41 +08:00
..
2026-09-28 09:40:15 +08:00
2026-09-28 09:40:34 +08:00
2026-09-28 09:40:15 +08:00
2026-09-28 09:57:41 +08:00
2026-09-28 09:29:26 +08:00