Commit 91b3938816ed11128d8202b5fd34f6fc67e6924b
1 parent
6a18379a
docs(32): 标记方案 B 已实施,补实施时的具体决策
状态行从"评估完成,未实施"改成"方案 B 已实施"。§四风险/未决问题里原来的 4 条逐条补上实施时的实际决策: - SessionPool 并发复用的真实后果仍未实测,但改用了不需要知道答案的设计 (拿锁成功才调用,从设计上不会触发这个场景) - 互斥锁选型定为抽共享模块(agent-session-lock.js),不新起一把 - 失败标记定为本体目录下的哨兵文件,不碰 system_agents.status - 第 4 条(三处同构缺口)原样保留未决 新增第 5 条:实施时发现的连带效果——hire 路由第 1 步改 await 之后,第 3 步的 setTimeout(5000) 变成多余延迟,刻意没有顺手删掉,记录下来给以后处理。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Showing
1 changed file
with
31 additions
and
15 deletions
docs/todo/system-design/32-hire-body-fill-reliability.md
| 1 | -# 32. 招聘装配的时间窗 —— 修法评估(评估完成,未实施) | |
| 1 | +# 32. 招聘装配的时间窗 —— 修法评估(✅ 方案 B 已实施,2026-08-21) | |
| 2 | 2 | |
| 3 | -> **日期**: 2026-08-21 | |
| 3 | +> **日期**: 2026-08-21(评估) / 2026-08-21(实施,同一天) | |
| 4 | 4 | > **性质**: 承接 [30-task-delegation-reliability-gaps](./30-task-delegation-reliability-gaps.md) §2.1(那份是"现状调研,不代表已拍板要改")。 |
| 5 | -> 本文档做的是**具体修法评估**:比较了两条候选路径,有明确推荐,但**代码还没有改一行**。 | |
| 5 | +> 本文档原本只是**修法评估**(比较两条候选路径、给推荐),现在方案 B 已经落地—— | |
| 6 | +> `agent-session-lock.js`、`agent-body-filler.js`、`company.js`/`agent-chat.js` 的改动, | |
| 7 | +> 见提交 `6a18379`。§三"推荐方案与要点"、§3.1 对照表原样保留(描述的仍是方案本身, | |
| 8 | +> 没有过期);§四"风险/未决问题"里 1/2/3 三条已经在实施时拍板,逐条标了结论。 | |
| 6 | 9 | > **触发**:本体装配静默坑那一轮修完读侧(work 节点缺 soul/identity 等、org node 角色定义截断不可见, |
| 7 | 10 | > 见 `graph-engine.js`/`prompt-builder.js` 那次提交)之后,回头看写侧(招聘时)同一类问题,发现 |
| 8 | 11 | > 更严重——读侧顶多是"给的上下文不全",写侧是"这个角色永久卡死,没人知道"。 |
| ... | ... | @@ -153,18 +156,31 @@ if (existing?.protocol?.isConnected) { |
| 153 | 156 | |
| 154 | 157 | ## 四、风险 / 未决问题 |
| 155 | 158 | |
| 156 | -1. **`SessionPool` 并发复用同一会话的真实后果没有实测验证**——本文档的论证是读代码推出来的 | |
| 157 | - (`getOrCreate` 不检查在途状态),没有起真实两个并发请求去验证具体报错形态还是内容串台。 | |
| 158 | - 实施前应该先补一个能复现这个场景的测试(两个并发 `callAgent` 调用同一个 agentId), | |
| 159 | - 把「后果具体是什么」钉死,而不是只停留在「读代码觉得危险」。 | |
| 160 | -2. **互斥锁选型未定**:导出 `agentChatLocks` 共用,还是新建一把只给招聘装配用的锁——前者 | |
| 161 | - 避免了「系统里有两把语义相同但互相不知道对方存在的锁」,后者改动面更小。留给实施时定。 | |
| 162 | -3. **失败标记落在哪个字段/文件**:本文档故意不预设,需要先看 `company-service.js` 现有 | |
| 163 | - `status`(`training`/`draft`/`active` 等)取值域,判断是新增一个值还是叠加一个独立字段。 | |
| 164 | -4. **这只是三处同构缺口(30 号文档 §三)里的一处**:DevLoop 的 `retry_budget` 耗尽和 Graph | |
| 165 | - 执行的 `blocked` 收敛,是不是也该补同一层"失败可查询/主动喊人",本文档不展开——三处 | |
| 166 | - 要不要统一设计成一层公共机制,还是各自打各自的补丁,是比这份文档更大的一个决策, | |
| 167 | - 留给以后。 | |
| 159 | +1. ~~**`SessionPool` 并发复用同一会话的真实后果没有实测验证**~~——**实施时定了**:没有另外 | |
| 160 | + 补一个"两个并发 callAgent 撞车"的复现测试去把具体报错形态钉死,改用更省事也更稳妥的 | |
| 161 | + 做法——`agent-body-filler.js` 从设计上**保证永远不会触发**这个场景(拿锁成功才调用, | |
| 162 | + 没拿到锁就等,不会有第二个并发调用打进来)。所以"后果具体是什么"这个问题本身 | |
| 163 | + 仍然没有实测答案,只是**这条路径不需要知道答案也是安全的**。真要交代清楚,得去 | |
| 164 | + `session-pool.js` 自己的测试里补,不在这份文档范围内。 | |
| 165 | +2. ~~**互斥锁选型未定**~~——**实施时定了:抽共享模块,不新建一把**。新增 `agent-session-lock.js` | |
| 166 | + 承载原来 `agent-chat.js` 里的 `agentChatLocks` Map + 超时常量,`agent-chat.js` 与 | |
| 167 | + `agent-body-filler.js` 都从这个模块 `require`。没有导出整个 `agent-chat.js` 模块的 | |
| 168 | + 其它内部状态——只挪了这一个 Map,`agent-chat.js` 的 `module.exports` 仍然只是 `router` | |
| 169 | + (改了会破坏 `app.use('/api/agent', require('./routes/agent-chat'))` 这个挂载点)。 | |
| 170 | +3. ~~**失败标记落在哪个字段/文件**~~——**实施时定了:本体目录下的哨兵文件,不碰 | |
| 171 | + `system_agents.status`/`config.json.status`**。新增 `.body_fill_failed.json` | |
| 172 | + (`agent-body-filler.js` 的 `FAILURE_MARKER_NAME`),内容含 `attempts`/`lastError`/ | |
| 173 | + `failedAt`;成功之后自动清掉。没有动任何现有 status 字段的取值域——那两个字段还有 | |
| 174 | + `draft→active` 的毕业逻辑在读,风险和收益不对等(评估阶段就是这个理由,实施时原样照做)。 | |
| 175 | +4. **这只是三处同构缺口(30 号文档 §三)里的一处,仍然只做了这一处**:DevLoop 的 | |
| 176 | + `retry_budget` 耗尽和 Graph 执行的 `blocked` 收敛,是不是也该补同一层"失败可查询/ | |
| 177 | + 主动喊人",这次实施没有碰、也没有顺手去改公共机制——三处要不要统一设计成一层公共 | |
| 178 | + 机制,还是各自打各自的补丁,是比这次修复更大的一个决策,留给以后。 | |
| 179 | +5. **新增:这次实施顺带修正了一个原来评估没预料到的连带效果**——`company.js` hire 路由 | |
| 180 | + 第 1 步从 fire-and-forget 换成 `await` 之后,第 2 步(技能注入)/第 3 步(`setTimeout(5000)` | |
| 181 | + 触发 Innovator 训练)现在拿到的是"第 1 步真的跑完了"的保证,不再是"假设 5 秒内跑完"。 | |
| 182 | + 那个 `setTimeout(5000)` 因此变成了多余的额外延迟(无害,只是白等 5 秒),**没有顺手删掉**—— | |
| 183 | + 不在这次修复评估的范围内,属于"看到了但刻意不处理",留给以后要动第 3 步时再一起看。 | |
| 168 | 184 | |
| 169 | 185 | --- |
| 170 | 186 | ... | ... |