From b995f9807797bca5f8f4254811d18a1e0adf008c Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Mon, 28 Sep 2026 11:14:17 +0800 Subject: [PATCH] =?UTF-8?q?docs(=E5=BD=92=E6=A1=A3):=20=E6=8A=8A=E4=B8=89?= =?UTF-8?q?=E8=BD=AE=E7=BB=93=E8=AE=BA=E4=B8=8E=E5=BE=85=E4=BA=BA=E5=86=B3?= =?UTF-8?q?=E7=AD=96=E9=A1=B9=E8=90=BD=E8=BF=9B=E4=BB=93=E5=BA=93=20?= =?UTF-8?q?=E2=80=94=E2=80=94=20=E9=82=AE=E4=BB=B6=E4=BC=9A=E8=A2=AB?= =?UTF-8?q?=E5=8E=8B=E7=BC=A9=EF=BC=8C=E8=BF=99=E4=BA=9B=E4=B8=8D=E8=83=BD?= =?UTF-8?q?=E5=8F=AA=E5=AD=98=E5=9C=A8=E4=BA=8E=E5=BE=80=E6=9D=A5=E9=87=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 归档回信可达性缺陷已修(e78888b / 2b77b17 / a3ca64b,均未 push), 但收尾全部需要人拍板。与其让结论烂在邮件线程里,不如落一份可交接的记录: 改了什么、判据是什么、哪些刻意没做、哪些仍未定位、以及四处待决。 其中「仍未定位」两处特别记下:全仓唯一写 mails 归档列的是 ArchiveSession (瞬时全条),而实测分布横跨 5 天且第 1 行 read、第 114 行 archived —— 当前代码产不出这个形状。与其猜,不如把读数和「我查过什么」留下。 --- docs/reviews/archive-status-fix-2026-09-28.md | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 docs/reviews/archive-status-fix-2026-09-28.md diff --git a/docs/reviews/archive-status-fix-2026-09-28.md b/docs/reviews/archive-status-fix-2026-09-28.md new file mode 100644 index 0000000..81c5295 --- /dev/null +++ b/docs/reviews/archive-status-fix-2026-09-28.md @@ -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` 已登记此风险。)