47 · acceptance.md 结构性产不出来,itemized 子任务物化形同虚设
状态: ✅ 已修复(2026-09-02)。按下面「三、修法」实现:
maybeMaterializeItemizedSubtasks新增findGoalBenchmarkFile/parseGoalBenchmarkDimensions兜底路径,acceptance.md缺失时 改读共享artifacts/goal-benchmark.json的dimensions[]。单测见server/tests/unit/task-decomposition-materialize.test.js(5 条,2 条新增) 日期: 2026-09-02 发现场景:46 号文档 Phase 0 的真实端到端验证——新建p0verify0901公司,走一条真实itemized任务(贪吃蛇游戏,真实 Claude CLI,非 mock),全程 19 分钟零回退零报错收敛到终态,但子任务物化了 0 条 与 43/44 号文档的关系:43 号文档设计了物化机制本身,44 号文档修的是产出闸门误判goal-benchmark没产出;本文档修的是物化机制依赖的产物本身在当前常见子图形状下从来不存在——三份文档各自独立,但环环相扣:44 号文档修完之后,goal-benchmark.json才第一次被证实能稳定产出,本文档才有了一个现成的兜底数据源可用
一、现象
46 号文档 Phase 0 真实回归的结果(详见该文档「Phase 0 实现记录」):
| 检查项 | 结果 |
|---|---|
| task-planning 判定 | itemized(未诱导) |
goal-benchmark/planner-validator 是否真正跑完 |
✅ 两者都 success(44 号文档修复生效) |
acceptance.md 是否产出 |
❌ 全程未产出 |
| 子任务是否物化 | ❌ 0 条 |
| 父 task 终态 | completed(按 holistic 规则收敛,不是设计中的"全子任务 completed 才 success") |
系统自己检测到了这一点,timeline 里有一条明确记录:
{"kind":"node.output","summary":"task.acceptance_mode='itemized' 但没找到 acceptance.md,跳过子任务物化(仍按 holistic 收尾)","payload":{"degraded":"acceptance_md_missing"}}
这不是这次真跑运气差——是结构性打不通,见下面根因。
二、根因
org-planner/agent.md 硬约束第 3 条要求它交四份产物:brd.md/prd.md/sdd.md/acceptance.md。但 org 层节点全是 nodeKind='subgraph'(无一例外),org-planner 实际执行靠 workgraph-planning 现场规划出的子图。
本次真实回归里,workgraph-planning 规划出的子图是:
org-planner-prd → org-planner-sdd → org-planner-benchmark → org-planner-validator
没有 brd-planning,也没有任何一个节点的职责是写 acceptance.md。 org-planner-benchmark(本体 goal-benchmark)产出的是 goal-benchmark.json——R-19-B 契约的 benchmark 段(44 号文档处理的那套机制),是一份结构化的验收维度清单,不是 acceptance.md。这两份产物名字不同、来源不同、格式不同(一个 Markdown 表格、一个结构化 JSON),历史上就没打算是同一份东西——它们只是恰好都能回答"这个任务怎么算通过"这个问题。
server/services/graph-engine.js 的 maybeMaterializeItemizedSubtasks(findAcceptanceMdFile 全节点扫描)只认 acceptance.md 这一种产物,扫不到就静默降级为 holistic——设计上是"软失败不拖垮硬产出"(33 号文档的教训:软产物不能当硬闸门),出发点合理,但代价是:只要 workgraph-planning 现在这套子图形状(prd/sdd/benchmark/validator,没有专门写 acceptance.md 的节点)持续是常态,acceptance_mode='itemized' 这条路径就永远物化不出子任务——这正是 46 号文档记录的"生产库 itemized 零命中"现象背后的确切原因。
org-planner/agent.md、org-planner/tools.md 里"四份产物含 acceptance.md"的文档描述本身可能已经过时,没跟上 goal-benchmark.json/R-19-B 契约这套后来演进出的机制——这是本文档范围之外的一处文档陈旧,暂不处理(见「五、遗留」)。
三、修法
不改 org-planner 的产物约定(不强推它必须再产出一份 acceptance.md,那需要改 prompt/工具且不保证 workgraph-planning 每次都会规划出对应节点),改物化机制去认已经证实稳定产出的那份数据——goal-benchmark.json。
goal-benchmark.json 的 dimensions[] 天然就是一份验收条目清单,结构比 acceptance.md 的 Markdown 表格更丰富(name/weight/pass_threshold/rubric/evidence_hint),还带一份 traceability[] 把每个维度映射回原始需求条目原文(task_goal_item),物化子任务时用它当 title 比维度英文名(如 direction_control)对人更友好。
server/services/graph-engine.js 新增两个函数:
findGoalBenchmarkFile(run):查runRootDir(run)/artifacts/goal-benchmark.json(共享区,runRootDir只认root_run_id,传根 run 还是子 run 对象都能解析到同一路径,不用像findAcceptanceMdFile那样扫全部节点)。parseGoalBenchmarkDimensions(text):解析出跟parseAcceptanceMd同形状的行({seq, item, method, passCondition}),下游createTask循环不用改。
maybeMaterializeItemizedSubtasks 改成两段式:先按原逻辑找 acceptance.md(保留向后兼容——万一以后哪个模板真的规划出了写 acceptance.md 的节点,原路径优先生效),找不到再退而认 goal-benchmark.json;两者都没有才真正判定"没有可物化的数据源"。
acceptance.md 存在 → 用它(不变)
acceptance.md 不存在
goal-benchmark.json 存在 → 用它的 dimensions[](新增)
goal-benchmark.json 也不存在 → 仍按 holistic 收尾(不变,软失败)
四、验证
server/tests/unit/task-decomposition-materialize.test.js 新增 2 条用例(原 3 条 + 新 2 条 = 5 条全过):
acceptance.md不存在但goal-benchmark.json存在(共享artifacts/区)→ 按维度物化子任务,title取traceability里的原始需求条目原文,description含evidence_hint与pass_threshold。acceptance.md和goal-benchmark.json都存在时,acceptance.md优先,不走兜底(向后兼容确认)。
测试数据用 46 号文档 Phase 0 真实回归产出的 goal-benchmark.json(data/companies/p0verify0901/runs/run_d1c66d98c5bf/artifacts/goal-benchmark.json)精简后的真实形状,不是凭空编的 fixture。
全量单测:267(graph-engine + devloop)+ 1136(全量 unit)全过,唯二失败(env-example-secrets.test.js、test-id-stability.test.js)与本次改动无关,改动前即存在。
未做:没有再起一次真实(非 mock)端到端回归去确认修复在真实生产链路里也生效——单测覆盖的是"给定一份真实捕获的 goal-benchmark.json,解析和物化逻辑对不对",不是"下一次真实 itemized 任务真的会走到这条兜底路径并成功物化"。原因:一次真实回归要 20 分钟量级的真实 Claude CLI 调用,而这次修复的逻辑本身是纯函数级别的、输入数据已经是真实捕获的产物,单测的把握足够高;如果后续 46 号文档 Phase 1 及以后需要一次新的真实回归验证,可以顺带把这条也验一遍。
五、遗留
org-planner/agent.md、org-planner/tools.md里"四份产物含 acceptance.md"的描述与当前workgraph-planning常规划出的子图形状不一致,属于文档陈旧,本文档未处理。- 这个兜底修复解决的是43 号文档设计的物化机制(org-planner 收尾后物化子任务)的可用性问题。46 号文档 Phase 1 打算把"分解"提前到执行开始之前(新增独立深度规划阶段),如果那条路径落地,本文档修的这条兜底路径可能会变成"旧机制的安全网"而不是主路径——不影响本次修复的必要性(旧机制在 Phase 1-5 落地前还是唯一在跑的路径),但后续设计 Phase 1 时应该想清楚要不要保留这条兜底、还是彻底换成新机制。