docs(归档): 把三轮结论与待人决策项落进仓库 —— 邮件会被压缩,这些不能只存在于往来里

归档回信可达性缺陷已修(e78888b / 2b77b17 / a3ca64b,均未 push),
但收尾全部需要人拍板。与其让结论烂在邮件线程里,不如落一份可交接的记录:
改了什么、判据是什么、哪些刻意没做、哪些仍未定位、以及四处待决。

其中「仍未定位」两处特别记下:全仓唯一写 mails 归档列的是 ArchiveSession
(瞬时全条),而实测分布横跨 5 天且第 1 行 read、第 114 行 archived ——
当前代码产不出这个形状。与其猜,不如把读数和「我查过什么」留下。
This commit is contained in:
2026-09-28 11:14:17 +08:00
parent a3ca64b744
commit b995f98077

View File

@ -0,0 +1,60 @@
# [探针] 归档会话回信可达性 —— 缺陷已修,等待人决策
**状态**:代码已改完并自验通过;**未 push、未部署、未动任何生产数据**。
下一步全部需要人拍板,故停在这里等一句话。
## 一句话结论
「归档后不可见」这条契约被 `reply_to` / `permission/request` / 平台会话 adopt 三条路绕过;
成因是 `TouchSession` 顺手把 `sessions.status` 写回 `active`,而「不可见」的两条判据
分居 `sessions.status` 与 `mails.status` 两张表。已按**不变量**收口,不是逐个堵入口。
## 三个 commit(都在本地,未 push)
| commit | 内容 |
|---|---|
| `e78888b` | `TouchSession` 只写 `updated_at`;`EnsureSessionOpen` 成为三个建邮件函数的共同前置;`reply_to` 恢复 404;`permission/request` 补参与方判据;**adopt 路径第四个入口**;不变量判据 |
| `2b77b17` | `MarkMailRead` 补 `AND status <> 'archived'`(反向洞,pi 复核时发现) |
| `a3ca64b` | `DecidePermission` 补同一处守卫(pi §五);修正我在 `e78888b` 漏落的参与方误用(会把管理员挡在决策门外) |
改动面:5 个文件、+505/-4,全部在 `/home/program/agentmail` 内。
## 判据:8 条,且都验过「去掉修复就转红」
`server/internal/repo/session_status_invariant_test.go`,核心是不变量:
> 对任意 `session_id`:`sessions.status='archived'` ⟹ 该会话全部邮件 archived
不写成「某条路径返回 404」是因为入口会变(今天三个、明天可能第四个),
而**两个能写那两张表的入口一个都不能分叉**,是由构造保证的。
每条都实测过回退修复即转红,不是「改完就绿」的装饰。
## 已确认的边界(都经生产库读数复核)
- **修好的**:不再新增分叉。四条复活路径(reply_to / permission / adopt / 反向改写两处)全堵。
- **刻意没做的**:存量数据一条没动。`reply_to` 那 9 条的成因确证,清理动作可从成因推出;
但要等**先部署**,否则旧代码会继续造新的。
- **明确不要做的**:不要按「反向破坏」去清那 424 封 `read` —— pi 的更正确认,
且我补的读数显示**主体是回填前的真实已读事实**,清了会破坏 `mail_reads`。
- **仍未定位、不猜的**:两处
① 那两条大线索(268/463 封)上零星 `archived` 邮件的**写入方** —— 全仓唯一写该列的
是 `ArchiveSession`(瞬时全条),而实测分布横跨 5 天、第 1 行是 `read` 而第 114 行
`archived`,**当前代码产不出这个形状**;
② 38 封无 `mail_reads` 的行级 `read`,同样无机制可解释。
## 需要人决定的四件事
1. **推不推**这三个 commit(我没 push)。
2. **部不部署**,以及谁执行。
3. **存量 9 条**清不清(压测垃圾整条归档;真实对话那两条只动 `sessions` 行、
碰都不碰 `mails` 行)。按 pi 与我一致的顺序:部署 → 重数签名 → 才清。
4. `docs/DEBTS.json` 里 `archive-session-filter-partial`(`FindSessionByAddress`
缺归档过滤,补上会把重复归档从 200 变 404,属行为变更)**仍未提交** ——
那文件与另一并行会话的改动混在一起,我不愿夹带。
## 顺带发现
工作区**无跨会话互斥**:本轮 `server/` 有另一并行会话同时在改 `ratelimit*.go`
及其两个新测试文件。那几处我全程未碰、未纳入我的 commit。
(DEBTS 里 `shared-workspace-unserialized-deploy` 已登记此风险。)