JianFeeeee
7fe279676a
fix(pi-bridge)!: --rw 的 cwd 与 worker 实际用的 cwd 收成**一处决定**(pi 探针实测的第三例)
pi 2026-09-15 报、我用探针复核**成立**,而且它把 `99e6560` 的代价也一起说清了。
**分叉在哪**:cwd 有**两个来源**,而会话键 `keyOf(data) = data.session_id` **只看 session_id**:
```
父进程(算 --rw) cwd = resolveWorkspaceCwd(to_workspace, …) ← 来源:**这封信的地址**
子进程(真去干活) cwd = job.session.cwd || resolveWorkspaceCwd(…) ← 来源:**会话上次实际用的 cwd**
```
于是同一 session_id 下地址换个形状(`pi@/some/dir` → `pi@.<会话>`),父进程按**新地址**
算 rw,worker 却**复用会话、落在旧 cwd**。实测(真函数,`exists` 注入):
```
父进程算的 cwd = /root/.pi/mail-sessions/sess-x
worker 实际会用 = /home/program/agentmail (= 该会话的 state.cwd)
rw 含 worker 实际 cwd? = false ⇒ 界内 EACCES
```
不是假想:本线程那条会话自上线起每次启动的 rw 都是 `/home/program/agentmail`,
那就是它的 `state.cwd` —— 此时来一封 `pi@.<会话>`(不带 path)的信就会踩到。
**★ `99e6560` 在这个组合上把失败方式变坏了**(这条必须记下来,我原先只报了它的好处):
· 之前:兜底目录不存在 ⇒ 不套沙箱 ⇒ `ask`(有人应答时**写得进去**)
· 之后:目录被建出来(那次修复的效果)⇒ **套上沙箱,而 rw 是地址算的那个**
⇒ worker 在会话自己的 cwd 里写 ⇒ **EACCES,且没有"问一次"这条路**(内核拒的)
我用 `ensureCwd` 前/后各跑一次验证了这条因果,实测 `(b) 建了兜底目录: sandboxed = true,
rw 含 worker 实际 cwd? = false` —— 与 pi 报的 `sandboxed=true` 一字不差(他给了那个值,
我最初复现成 false,差别就在"兜底目录建没建",属于应用 `99e6560` 前后)。
⇒ **两处修复必须一起部署**,否则中间态是"界内也写不了"(比原先多问一次更糟)。
现在两次提交都在仓库、`drift` 报 5 处待部署,会一起上线。
**修法**:新增 `src/turn-cwd.mjs` 的纯函数 `resolveTurnCwd()` —— 输入全部来自**父进程也拿得到的
public 状态**(`sessionReused` / `storedCwd` / `toWorkspace` / `sessionKey` / 注入的解析函数),
父子两侧都从它取值;父进程再把决定**注入 job**(`session.resolvedCwd`),worker **消费**它、
不再自己推导。于是"三来源变一来源"落了第一步。
**判据(pi 要的那条等式)**:
· ★**等式**:用真 `sandboxWritePaths` 算 rw,断言"**`--rw` 里的 cwd === worker 会用的 cwd**";
并附**反面对照**:按地址算出来的 rw **不含** `state.cwd`(= 修复前的错位状态)。
· 复用/非复用/`storedCwd` 为空三种输入各一条。
· 结构:pool 必须把决定交给 `workerLaunch` **并**注入 job;worker 取 cwd 的**每一处表达式**
都必须先看 `resolvedCwd`。
★ **两处我自己的判据缺陷,都是变异测出来的,都记在测试文件里**:
1. 上一轮我在 `sandbox-launch.test.mjs` 写的 `assert.match(src, /resolveWorkspaceCwd\(/)`
**本来就不该红也不该绿** —— 它护的是**写法**(池子直接调那个函数),而引入 `resolveTurnCwd`
后池子改成"当参数传进去"(更对),它才红。**红得对**:它当初断言的是实现细节,
不是它想要的性质。已改为断言性质(解析函数必须来自共用模块、且被显式传给纯函数)。
顺带说明:它此前一直是**假绿**还是**真绿**我没法回测,但**它在引入纯函数后才红**说明它
确实绑定了写法 —— 这正是"判据的适用范围没写出来"那一类。
2. 新版 worker 侧结构判据**第一版不具区分力**:只断言"文件里出现 `resolvedCwd`",
把消费那一支删掉、退回 `job.session.cwd`,正则**仍然匹配**(别处还留着它)⇒ 变异后依旧全绿。
已改为断言**优先级**(取 cwd 的表达式必须含 `resolvedCwd`)。
★ 变异实测:修好后重做同一变异 ⇒ 判据**变红**;两次变异均 `cp` 恢复 + `cmp` 校验。
**残余(未修,已进 DEBTS)**:**接管会话**那条路 worker 用会话文件 header 里的 `info.cwd`,
父进程读不到 ⇒ 首回合仍可能错位。父进程要拿它得用 `session-scan.mjs`,而 `readHeader` 未导出、
整表 `scan()` 在父进程里代价大(worker 里实测 1431ms / 240MB)。
彻底方向即 pi 说的:把"这次用哪个 cwd"完全收成父进程一处决定,worker 只消费。现在做不做等定。
验证:pi 桥 **502/502**;另三个桥 fail 0;`check-shared-libs` exit 0;`install.sh --check` exit 0。
2026-09-15 06:47:10 +08:00
..
2026-09-11 11:32:47 +08:00
2026-09-15 06:31:18 +08:00
2026-09-15 06:47:10 +08:00
2026-09-15 06:47:10 +08:00
2026-09-14 20:00:16 +08:00