JianFeeeee
d284f1f0af
feat(admin): 真实删除会话的 API —— DELETE /api/v1/admin/sessions/{id}
## 为什么要有
此前清理测试数据只能手工敲 sqlite3,而那立刻暴露了这套 schema 的两个陷阱,
两者都不是「照着表名删」能发现的:**级联在这套 schema 里不成立**。
attachments → CASCADE ✔ 唯一声明了自动的
mails → NO ACTION
mail_reads → NO ACTION
relayed_mails → NO ACTION
permission_requests→ NO ACTION
session_agent_locks→ NO ACTION
漏删任何一张都不会报错,只会在几周后的一次体检里以 `foreign_key_check`
悬空引用的形式冒出来 —— 那时已经没人记得它是怎么来的。
实现按依赖倒序删 7 张表,全在一个事务里(任何一步失败即整体回滚;
半删比不删更糟:会话没了但邮件还在,而用户以为已经删干净了)。
返回**实际删掉的行数**而不是只回 200:一个只删了 sessions 却漏了 mails 的
实现也能返回 200,而 mails 还在意味着那封对话在界面上看不到却仍在库里。
## 两个设计决定
**① 挂 `AdminOnly` 组,不挂 `UserAuth` 组。**
会话是多方的协作记录(多个 Agent + 人类的往来)。`UserAuth` 组里任何登录
用户都能看到自己的全部会话 —— 放那里等于让任何人删别人的历史。
**② 刻意不进 MCP 工具面。**
删除不可撤销,而 MCP 的调用方是**模型**:误判一次就是真丢数据。
与 `connect_to_server` 刻意不提供改坐标参数同一条原则 ——
**不可逆的运维动作不进模型可及的面**。Agent 要结束线索走归档。
## ★ 实现中测出的两件事(都改了我的判断)
**① `parent_mail_id` 那步不是必需的 —— 我一开始写错了注释和判据**
我以为「有回复链时删除会撞外键约束」。实测:
DELETE FROM mails WHERE session_id = X → 同语句内删父子,SQLite 不报错
`NO ACTION` 只在删除后**仍有行**引用被删行时才拦,同语句内删父子是合法的。
所以那步是**防御性冗余**(为「将来拆成两条语句」那件事留的),
注释已改为陈述实测,不再说它必需。真正必须先处理的是 schema 本身:
历史数据里已有 7 条悬空引用,是早于这套代码的既存违规。
**② 判据自身出了两次假绿,都是同一个原因:观察方式比语义宽**
| 变异 | 表面 | 真相 |
|---|---|---|
| 撤掉 mails 删除 | 0 红 | 变异**没应用**(按字符串匹配命中了文件头注释) |
| 撤掉 parent 断开 | 0 红 | 变异确实应用了,但判据**断言了一个 SQLite 不提供的保证** |
第二次值得记:我写了个「删除是否生效」的断言,它报「未生效」,我一度以为
删除失败 —— 实际是**全文搜 `parent_mail_id = NULL` 命中了文件头注释里
同一句话**。断言本身写错了,不是删除错了。
改用**代码行特征**(反引号包裹的 SQL / 错误文案)判定后,两个真实变异都转红:
漏删 mails → 2 格红 ✓
漏删 session_agent_locks → 1 格红 ✓
## 判据(5 格)
除上面两条,另含:删不存在的会话必须报 `ErrSessionNotFound`(幂等返回 200
会让「重试」与「成功」不可区分);不得误删别的会话;中途失败必须整体回滚
(用触发器注入失败,断言会话与邮件都还在)。
全量 14 包绿。
2026-10-03 13:41:02 +08:00
..
2026-09-08 19:16:35 +08:00
2026-09-14 08:32:22 +08:00
2026-10-01 19:41:06 +08:00
2026-10-03 13:41:02 +08:00
2026-09-08 19:16:35 +08:00
2026-10-02 16:06:00 +08:00
2026-09-26 07:44:33 +08:00
2026-09-14 15:49:45 +08:00
2026-09-30 17:30:27 +08:00
2026-09-28 09:50:24 +08:00
2026-10-03 13:41:02 +08:00
2026-09-08 19:16:35 +08:00
2026-10-02 15:37:34 +08:00
2026-09-14 11:07:03 +08:00