Files
MailUI4Agents/docs
JianFeeeee ecf98d7d36 文档: 记下 B-7.7 那条债的**实测实例** —— 每日 04:00 的 dsh 重启让重投每天复发
与契约里 2026-09-04 那个事故**同形**,只是换成了"宿主被定时重启"。链条完整量到:

1. root crontab `0 4 * * * /usr/bin/systemctl restart dsh.service`(第 6 行)
2. 每天 04:00:03 `dsh.service` Stop/Start(journalctl 逐日可见)
3. 新进程 ⇒ `deliveredMails` 空(index.ts:469,内存 BoundedSet)
4. `caughtUp` 重置 ⇒ 首个心跳后 catchUp 跑一次(:470 / :524)
5. 拉 `/mail/inbox?status=unread&limit=20`(:481)⇒ 整个未读积压当天重投一遍

实测(以 `mails` 表为判据):真邮件投递 **107 次 / 81 封**不同邮件,
04 点整点占 09-18:4 / 09-19:3 / 09-20:3 / 09-21:7;投递时刻落在
04:00:23 / 04:01:23 / 04:03:23… 的 ≤5 封批次节奏上(B-7.2)。
`session/end-seed` 也逐日落在 04:00。

★ 关键判别用**时序**:这 107 次里「投递时该读者已有已读行」= **0 次**
⇒ catchUp 从不重投已读邮件,它投的是"当时确实未读"的。"未读"有两个独立成因:
(a) `read_mail` 不标已读(T-12 对已读状态沉默);(b) `markReadFor` 占位符错位
(2026-09-20 修)。两者都让"读过了"没变成"已读"。

⚠️ 我把这里算错过两次,都写进文里当纪律:
① `agent/inbox/spliced` 里混着**非邮件**注入(后台作业完成通知、续跑提示),
   按"事件数"统计会当成邮件(我一度报 09-20 有 18 次,真值 **3**);
   ⇒ 要拿 id 去问 `mails` 表在不在,才算真邮件。**同一事件类型 ≠ 同一种载荷。**
② 判断"有没有重投已读的信"**不能看当前 `mail_reads`**:11 封现在是"已读+曾重投",
   看着像反例,其实是**先被重投、后来才补标**的。必须拿**每次投递的时刻**比 `read_at`
   —— `mail_reads` 是当前状态,"投递时是否已读"是历史事实,两者不是一回事。

dsh 桥去重仍是内存态 ⇒ B-7.7 要求的落盘账本这条债**仍未销**(已在文里写明)。
2026-09-21 04:45:52 +08:00
..