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