# 30-task-delegation-reliability-gaps. 任务委派可靠性现状 —— 已确认的鸿沟清单 > **日期**: 2026-08-21 > **性质**: 现状调研记录,不是设计方案。列的是「代码现在长什么样、缺什么」,不是「该怎么补」—— > 要不要补、按什么优先级补,留给后面拍板。 --- ## 起因 用户问:「自动跑一个任务,能保证成功吗?」分别对 DevLoop(`runUnit`)和 Company/OKR(Agent 招聘 + 任务委派) 两条链路查了代码。结论是同一个:**全系统没有任何一处能"保证自动跑到底"**,统一是 「重试到预算/时间窗耗尽 → 停下等人工」的模式,区别只在于兜底的**粒度**和**可见性**。 --- ## 一、DevLoop `runUnit`(Coder→Tester 循环) **文件**: `server/src/core/devloop/loop-controller.js`(`runUnit`,394-479 行)、 `server/services/devloop/unit-registry.js`(FSM) - `retry_budget` 默认 5 次,每次失败把上一轮 `coder.log` 摘要 + Tester 失败原因打包成 retry context 喂回 Coder,带着"上次为什么挂"重跑(reflection)。 - 5 次全挂 → `unitRegistry.block(...)`,状态机进 `blocked`(`unit-registry.js:36`)。 **没有自动退出路径**,`blocked → pending` 只能靠人工干预。 - **当前默认走 mock 模式**(`opts.mock !== false` 默认 true),走 `ClaudeCliProtocol({mock:true})` 回放 `fixtures/devloop-mock/*.json` 固定结果, 不是真起 Claude CLI + 跑测试。所以"能不能保证成功"这个问题在默认配置下基本没有实际意义—— mock 场景下结果是脚本编排好的,真实 CLI 下的成功率目前**没有实证数据**。要测真实场景 得显式传 `mock: false`。 - 阶段现状:DevLoop 目前在 P2(单 Unit 循环),跨 Unit 的 `runProject`(P3)代码已经存在 (同文件 556 行往下),但官方状态仍是"正朝 P3 推进",还未收口。 --- ## 二、Company/OKR Agent 任务委派 ### 2.1 招聘装配的时间窗(`org-coder-has-no-shared-body` 记忆已同步更新) **文件**: `server/services/company-service.js`(430、500-511 行) - `hire()` 现在会现场校验一次角色定义是否就绪,用 `body_not_ready` 网关挡住别家公司在 定义写完前重复招同一角色——比早前"静默退化成通用 Base Agent 且无报错"的状态好。 - 但 agent-creator 写 `agent.md`/`soul.md` 依旧是**异步触发 + 单会话锁**,校验和填充之间 仍有时间窗,**没有完成回执/超时告警**。卡在这个窗口只能靠人工发现(比如逐个 `head -3 data/companies/<公司>/agents/<本体>/agent.md` 看是不是还是 Base Agent 空壳)。 ### 2.2 会话回收只有一层兜底 **文件**: `server/routes/agent-chat.js`(818-828 行,`CALL_KINDS` 表) - `CALL_KINDS` 精确覆盖心跳/pipeline/日程/告警/日报五类,跑完即回收。 - 未标 `kind` 的调用退化成普通 `chat` 类型,靠 30 分钟空闲 TTL 兜底,**没有第二道防线** (例如全局会话数硬顶)。漏标的后台调用不报错,只在内存曲线上体现—— 与 `docs/done/claude-cli-session-leak.md` 记录的那次"2h43m 漏出 82 个进程/17.5GB"是 同一类风险,这次风险面在 Company/OKR 委派路径上同样存在,不只是 agent-chat 原生场景。 守卫 `agent-chat-session-reclaim.test.js` 已覆盖 `CALL_KINDS` 标注本身,但不覆盖 "该标而没标"这类新增调用点的遗漏。 ### 2.3 Graph 执行失败无自动恢复,与 DevLoop 同构 **文件**: `server/services/graph-engine.js`(`LOOP_HARD_CAP_EDGE` + fail 边路由) - 有兜底边就转兜底节点,没有就直接进 `blocked` 停等人工,不会自愈。 - 这是委派链路的通用终态,不是 Company 独有问题——和 DevLoop 的 `retry_budget` 耗尽 → `blocked` 是同一种设计选择(失败预算 + 人工兜底, 不追求自动恢复),只是目前**分散在两套系统里各自实现,没有统一的"完成回执/超时告警"层**。 --- ## 三、共性模式(值得记住,不代表已拍板要改) 三条链路(DevLoop unit、Company 招聘装配、Graph 执行)共享同一个设计现状: **有失败预算 + 人工兜底,没有"卡住了主动通知人"这一层**。 失败之后系统会停在一个确定状态(`blocked` / `training` 卡住 / 会话挂着不回收), 但**不会主动喊人**——都是被动的,靠人去翻状态或者翻内存曲线才发现。 这是三处鸿沟共同的根因形状,不是三个独立问题。 --- ## 四、2026-08-23 追加:`infra_flake` 原地重跑没有熔断,真撞上过一次无限循环 **背景**:36 号文档阶段二把训练出的 PRD 方法论手工套进 `prd-planning` 后,起了一条新的 e2e-demo 端到端回归验证效果,跑到 `org-coder` 子图时撞见:`org-coder-test`(`unit-tester`) 被 `org-coder-validator` 的 `missing_required_input` 失败反向打回后,没有走"重测实现"这条 常规路径,而是自己产出了一份 `validator-triager/v1` schema 的诊断文件(判断被测站点本身没问题, 问题出在 `org-coder-validator` 那次运行自身的输入解析,建议"只重跑 org-coder-validator")—— 这份诊断文件里带着 `fail_reason: "infra_flake"` 字段,**被引擎当成了 `org-coder-test` 这个节点 自己的执行结果**,触发 `routeFailure` 里 `infra_flake` 的"原地重跑,不烧 attempt、不烧 backward_count"分支。因为每次重跑产出的诊断内容都一样(同样的真实检查、同样的结论), 陷入了确定性死循环:`unit-tester` 被反复调用产出同一份"该重跑 validator"的建议,但引擎 从不读它 `target_node` 字段、只会一遍遍重跑产出诊断的那个节点本身——`org-coder-validator` 真正在等的那次重跑永远不会发生。观测到时已经循环 4 次以上,`spent.agent_calls` 涨到 35/100, `wallclock` 逼近预算上限。 **跟本节 §三"共性模式"的关系**:`infra_flake` 这条自愈路径本身是为"基础设施抖动"设计的 (§四.D.2.1),特意**不计入**失败预算/backward_count,理由是"这不是节点自己的错,不该烧 它的重试额度"——但这也意味着它是**唯一一条没有熔断线的失败路径**:`LOOP_HARD_CAP_RUN`/ `LOOP_HARD_CAP_EDGE` 管不到它,只有任务级总预算(agent_calls/tokens/wallclock)能兜底, 而这次真实撞到的循环恰好会一直产生"看起来正常"的诊断内容,不会被识别为异常,直到把 预算耗光——是本节"卡住了没人主动通知"这条共性模式里最隐蔽的一种:连"卡住" 本身都不容易从节点状态一眼看出来(`ready`↔`fail`↔`ready` 快速循环,轮询间隔稍长就会 误判成"在正常推进")。 **2026-08-23 已修(① 熔断线,不是 ② 路由)**:新增 `graph_run_nodes.infra_flake_count` 列, `routeFailure` 的 infra_flake 分支每次原地重跑前先加计数,连续超过硬顶(3,与 `LOOP_HARD_CAP_EDGE` 同量级)就不再重跑、改判 `blocked` 交给人工;真正发起新一轮真实派发 (`bumpNodeAttempt`)时清零,不会误伤"这次真是基础设施抖动、之前刚好也抖过"的正常场景。 **刻意没做**②(让 `routeFailure` 认得 `target_node` 真的路由过去)——`org-coder-test` 临时 客串"triager"这个用法本身该不该存在,需要先搞清楚这条 backward 边的设计意图是"重测"还是 "诊断转发",没查清楚之前不改选边的语义,只堵住"没有熔断线"这个不管设计意图是什么都算 缺陷的口子。新增回归测试锁死"永不恢复的 infra_flake 在硬顶后停止重跑",见 `server/tests/unit/graph-engine.test.js`。 ## 参考 - DevLoop 阶段现状:[27-graph-agent-architecture.md](./27-graph-agent-architecture.md) - 会话泄漏排查手册:[claude-cli-session-leak.md](../../done/claude-cli-session-leak.md) - `body_not_ready` 网关所在的招聘流程背景:[28-followups.md](./28-followups.md)