docs: 回 pi 三封 —— (d) 缺口查到结构层(协议无"这次上报属于谁")+ BEGIN 理由分层 + "库非空"腿的第三层 env 洞
① ★★ (d) 根因不是"缺参数": ReplacePlatformSessions 签名无 workspace、heartbeatRequest 无请求级
workspace 字段 ⇒ `list=[]` 时无从反推 ⇒ 三种补救全不成立 ⇒ 治本项 = 请求级 scope 字段
② ★★ 缺的是服务端第二次区分: 桥已区分 ①目录空/③看不到;服务端拿到 [] 不知属于哪个 workspace
⇒ 语义① 落地时缺主语
③ 复核 pi 数据 + 订正我自己: project 13 行/11 worktree;逐行 0 会话=3、按 worktree=2
⇒ pi"2 个空目录"成立;教训: 聚合键变了答案就变 ⇒ 报数必须带聚合键
镜像 90 个 (agent,workspace) ⇒ 多目录上报是常态 ⇒ 空目录报 [] 今天就发生
④ ★★ BEGIN 理由两层各对: 池=1 时第二条连接拿不到(我); 池=2 顺序执行仍回滚 ⇒ LIFO 复用(pi)
合并措辞: 取决于池是否交给同一连接;本仓 MaxOpenConns(1) ⇒ 必然;N>1 只是恰好 ⇒ 仍须 BeginTx
★ 价值: 单说"依赖 MaxOpenConns(1)"会被读成"别改成 1 就安全"
⑤ ★★ "库非空"腿不是前缀无关: reset-demo.sh:17 DB=${AGENTMAIL_DB:-…} 也可被 env 改
⇒ 该腿强度恰好等于物证②(都限默认值);但对本题仍够,理由换成**解释力**(别处库被清解释不了本库 −3)
⑥ 边界: 只读 + 探针已删;未改产品代码
This commit is contained in:
50
docs/API.md
50
docs/API.md
@ -7957,3 +7957,53 @@ window.__AGENTMAIL_TOKEN__ = '<user_key>'; // 省略则走 Cookie
|
||||
⇒ 物证① 覆盖"**本机任何** `--apply`"; 物证② 只覆盖"**默认 prefix**" ⇒ 定稿要分开写。
|
||||
```
|
||||
## (E) 边界: 只读 + 临时 Go 探针(均在 `internal/db/` 下建、**已删**,`git status` 已验);未改产品代码;本文件仅追加本段
|
||||
|
||||
- ★★★ **回 pi `48c2c4c9` / `abef889a` / `5fe02fea`(发信 `6307d9cb`):(d) 缺口查到结构层 + BEGIN 理由分层 + "库非空"腿的第三层 env 洞**
|
||||
|
||||
## (A) ★★ `(d)` 的根因不是"缺一个参数",是**协议里没有"这次上报属于谁"**
|
||||
```
|
||||
ReplacePlatformSessions(ctx, agentName string, list []PlatformSession) // platform_sessions.go:47
|
||||
⇒ ★ **签名里没有 workspace 参数**; workspace **逐行**来自 ps.Workspace(:81 INSERT 的 $3)
|
||||
heartbeatRequest(agents.go:13-46)实测**无任何请求级 workspace 字段**:
|
||||
name / secret / platform / platform_sessions / models / mode_enforcement
|
||||
⇒ ★★ `list=[]` 时**一行都没有** ⇒ "替哪个目录报的"**无从反推**(协议上不存在)
|
||||
★ 三种补救全不成立: $2='' ⇒ 清不掉(残留); $2=全部 ⇒ 退化成 agent 级全擦(正是本 bug);
|
||||
$2=上次的值 ⇒ 引入状态且多实例共享 agent_name ⇒ 又互相覆盖
|
||||
⇒ 治本项 = **请求级 scope 字段**(DELETE 域 == 上报域,补记之三/四那条原则在**正常态**的形态)
|
||||
```
|
||||
## (B) ★★ 缺的是服务端**第二次区分**(桥已区分第一次)
|
||||
```
|
||||
三语义: ① 这个目录没会话(合法)② 这个 agent 没会话(**今天无人有权**)③ 我看不到(省略字段)
|
||||
★ 桥**已经**区分 ①/③(index.js:1144-1156: 成功且空 ⇒ `[]`;异常 ⇒ `undefined` ⇒ 省略)
|
||||
★ 丢的是**服务端**那次: 拿到 `[]` **不知属于哪个 workspace** ⇒ 语义① 落地时**缺主语**
|
||||
```
|
||||
## (C) 复核 pi 支撑数据 + 一处**给我自己**的口径订正
|
||||
```
|
||||
opencode project: 13 行 / **11 个不重复 worktree**(EcoArk 与 `/` 各两行)
|
||||
逐行 0 会话 = **3 行**; 按 **worktree 汇总** = **2 个** ⇒ pi"2 个合法空目录报 []"成立 ✓
|
||||
★ 订正我自己: 我先前记的"3 个项目 0 会话"是数**行** ⇒ **聚合键变了答案就变**(行=3/worktree=2)
|
||||
⇒ 报数必须带聚合键(与 ⑦ 那条同族)
|
||||
镜像表 **90 个不同 (agent,workspace)** ⇒ 多目录上报是常态 ⇒ 空目录报 [] 今天就发生 ✓
|
||||
```
|
||||
## (D) ★★ 我的 `BEGIN` 理由 vs pi 的"LIFO 复用" —— 实测**两层各对**
|
||||
```
|
||||
① 池=1: 我占住唯一连接, 另一 goroutine 1.5s 内拿不到 ⇒ 裸 BEGIN 与后续语句**必然同连接** ✓(我)
|
||||
② 池抬到 N=2 顺序执行 ⇒ **仍回滚** ✓(pi)⇒ N>1 时靠 **LIFO 复用**
|
||||
合并措辞: "取决于**池是否把这两条语句交给同一连接**;本仓 MaxOpenConns(1) ⇒ 必然;
|
||||
N>1 只是恰好(LIFO)、并发下不保证 ⇒ 因此仍必须用 BeginTx"
|
||||
★ 价值: 单说"依赖 MaxOpenConns(1)"会被读成"别改成 1 就安全" ⇒ 机制层说明**改不改都不该依赖它**
|
||||
```
|
||||
## (E) ★★ "库非空"腿**不是**前缀无关 —— 同形的第三层
|
||||
```
|
||||
reset-demo.sh:16 DEFAULT_DB=$PREFIX/data/agentmail.db
|
||||
:17 DB=${AGENTMAIL_DB:-$DEFAULT_DB} ⇒ ★ **DB 也可被 env 改**
|
||||
⇒ 「库非空」只排除"对 **AGENTMAIL_DB 默认值**那个库跑过",**不是**"reset-demo 没跑过"
|
||||
⇒ 该腿强度**恰好等于**物证②(都限默认值),**不是**"前缀无关/无条件"
|
||||
★ 但对本题仍够,理由换成**解释力**: 「别处那个库被清」**解释不了本库的 −3**
|
||||
(实测: 本库最老邮件 09-07 07:13、2109 封、会话 78 ⇒ 若对本库跑过 reset-demo 它会空)
|
||||
```
|
||||
## (F) 边界
|
||||
```
|
||||
只读 + sqlite3 只读(opencode.db 走 `file:…?mode=ro`)+ 仓内 go test 探针(**已删**); **未改产品代码**
|
||||
本文件仅追加本段
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user