Commit 8fb378c81228400cd2078fd4601f2bf7ca6495c2
1 parent
cecce7a2
docs(task-decomposition): 46号文档 Phase 3 实现记录
记录落地清单、必须同步改的坑(settleNode 闸门收窄)、认领后复用 executor='agent' 派单闭环这处化简确认按设计落地。如实记一次意外:排查 SQL 模板字符串反引号语法错误时,一句没设 GRAPH_DB_PATH 的 node -e require 顺手对本地 data/graph.sqlite 跑了一次批 6 迁移——核实过是纯增量 ALTER ADD COLUMN,102 条既有行无损,但记下来提醒自己语法检查也该走隔离 环境。真实端到端回归(尤其认领后 org-coder 自己怎么干这一段)还没做, 留给用户后续决定。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H85SS5hVC4u1PbVhjmrhH8
Showing
1 changed file
with
24 additions
and
1 deletions
docs/todo/system-design/46-mandatory-planning-and-task-decomposition.md
| 1 | # 46 · Planning 应作为每个任务的默认前置步骤,覆盖三类信息来源 | 1 | # 46 · Planning 应作为每个任务的默认前置步骤,覆盖三类信息来源 |
| 2 | 2 | ||
| 3 | -> **状态**: 📝 设计中——四个关键决策已拍板。**Phase 0 已完成**(2026-09-01 真实回归验证):链路能收敛、44 号文档修复确认生效,发现的独立缺陷已拆到 [47 号文档](./47-itemized-subtask-materialization-goal-benchmark-fallback.md) 并修复。**Phase 1 代码已实现**(2026-09-02,见「Phase 1 实现记录」):新 agent `subtask-planning` + `enqueueTaskRun` 挂钩(收窄为显式 opt-in)+ 复用 R-9.3 任务级共享索引对接下游,单测覆盖,**但还没做真实端到端回归**(且过程中出过一次真实 CLI 子进程泄漏事故,已修复并加了测试环境防护,见该节)。**Phase 2 已实现且已做真实端到端回归(收窄版,2026-09-02,见「Phase 2 实现记录」)**:经验检索(新查询能力,扫已雇 agent 的 dream 沉淀)+ 按需 deep research(图外调用 org-hunt,默认关闭)。真实回归第一次就跑出一个真缺陷(关键词打分噪音压过信号,导致"经验库有答案"分支误触发)并已修复验证;两条真实任务的分解内容质量都好,但 deep research 分支目前更接近"多问一个角色的第二意见"而非真的做了外部检索(org-hunt 那次调用没有工具调用痕迹),如实记在实现记录里。"历史同类 goal 检索"这条来源本轮明确收窄未做。**Phase 3 设计已细化(2026-09-02,见「Phase 3 详细设计」,未实现)**:跟用户对齐了最关键的架构决定——可认领子任务复用 `tasks` 表(加 `subtask_kind` 字段区分类型,不新开表)。设计过程中发现一处必须同步改的向后兼容坑(`settleNode` 的 `SUBTASKS_INCOMPLETE` 闸门要收窄,否则会被新物化的行误伤),以及一处重要化简(认领后复用现成的 `executor='agent'` 派单闭环,不需要碰 `graph-engine.js`,比最初设想的"要给核心调度引擎加认领层"轻得多)。Phase 4(独立开发验证循环)、Phase 5(看板 UI)仍未设计,留给后续 | 3 | +> **状态**: 📝 设计中——四个关键决策已拍板。**Phase 0 已完成**(2026-09-01 真实回归验证):链路能收敛、44 号文档修复确认生效,发现的独立缺陷已拆到 [47 号文档](./47-itemized-subtask-materialization-goal-benchmark-fallback.md) 并修复。**Phase 1 代码已实现**(2026-09-02,见「Phase 1 实现记录」):新 agent `subtask-planning` + `enqueueTaskRun` 挂钩(收窄为显式 opt-in)+ 复用 R-9.3 任务级共享索引对接下游,单测覆盖,**但还没做真实端到端回归**(且过程中出过一次真实 CLI 子进程泄漏事故,已修复并加了测试环境防护,见该节)。**Phase 2 已实现且已做真实端到端回归(收窄版,2026-09-02,见「Phase 2 实现记录」)**:经验检索(新查询能力,扫已雇 agent 的 dream 沉淀)+ 按需 deep research(图外调用 org-hunt,默认关闭)。真实回归第一次就跑出一个真缺陷(关键词打分噪音压过信号,导致"经验库有答案"分支误触发)并已修复验证;两条真实任务的分解内容质量都好,但 deep research 分支目前更接近"多问一个角色的第二意见"而非真的做了外部检索(org-hunt 那次调用没有工具调用痕迹),如实记在实现记录里。"历史同类 goal 检索"这条来源本轮明确收窄未做。**Phase 3 代码已实现(2026-09-02,见「Phase 3 实现记录」)**:`tasks` 表加 `subtask_kind`/`claimed_at`,认领 CAS(`claimSubtask`/`unclaimSubtask`,全仓库第一个"认领"语义写入)+ 物化(`materializeClaimableSubtasks`)+ 两个新路由 + `settleNode` 闸门收窄(必须同步改,已用回归测试固定)。认领后复用现成的 `executor='agent'` 派单闭环,**没有碰 `graph-engine.js` 的调度逻辑**。单测覆盖(23+ 条新增),**但还没做真实端到端回归**——尤其"认领后 org-coder 自己怎么干"这一段完全没有验证质量的机制,设计阶段就写明"跑得糙"。Phase 4(独立开发验证循环)、Phase 5(看板 UI)仍未设计,留给后续 |
| 4 | > **日期**: 2026-09-01 | 4 | > **日期**: 2026-09-01 |
| 5 | > **触发场景**: 用户复盘 [43 号文档](./43-task-decomposition-granularity.md)(goal 分解粒度)时,追问"为什么本地和线上所有公司的任务看板都没有子任务分解"。核实后发现:不是巧合或配置遗漏,`acceptance_mode='itemized'` 在当前系统里**从未被真正触发并落库过一次**——追问引出了比 43 号文档更大的架构缺口:43 号文档只解决"验收要不要拆细",而用户认为**规划(把一件事拆成第一步/第二步/第三步)本身应该是每个任务默认必经的前置步骤,不是一个可选的、可以被判"不需要"的例外**。 | 5 | > **触发场景**: 用户复盘 [43 号文档](./43-task-decomposition-granularity.md)(goal 分解粒度)时,追问"为什么本地和线上所有公司的任务看板都没有子任务分解"。核实后发现:不是巧合或配置遗漏,`acceptance_mode='itemized'` 在当前系统里**从未被真正触发并落库过一次**——追问引出了比 43 号文档更大的架构缺口:43 号文档只解决"验收要不要拆细",而用户认为**规划(把一件事拆成第一步/第二步/第三步)本身应该是每个任务默认必经的前置步骤,不是一个可选的、可以被判"不需要"的例外**。 |
| 6 | > **格式对齐** `27-requirement.md`/`43-task-decomposition-granularity.md`:原话照搬 + 结构化复述,现状调研另起一节。 | 6 | > **格式对齐** `27-requirement.md`/`43-task-decomposition-granularity.md`:原话照搬 + 结构化复述,现状调研另起一节。 |
| @@ -399,6 +399,29 @@ WHERE id=? AND subtask_kind='claimable_work' AND status='claimable' | @@ -399,6 +399,29 @@ WHERE id=? AND subtask_kind='claimable_work' AND status='claimable' | ||
| 399 | 4. 认领成功后,这条行是否真的能走完 `executor='agent'` 的既有生命周期(`org-coder` 自己完成、`/task/report` 上报、状态正确落到终态)? | 399 | 4. 认领成功后,这条行是否真的能走完 `executor='agent'` 的既有生命周期(`org-coder` 自己完成、`/task/report` 上报、状态正确落到终态)? |
| 400 | 5. 非白名单角色尝试认领,是否被正确拒绝? | 400 | 5. 非白名单角色尝试认领,是否被正确拒绝? |
| 401 | 401 | ||
| 402 | +## Phase 3 实现记录(2026-09-02,代码已实现,未做真实端到端回归) | ||
| 403 | + | ||
| 404 | +### 落地清单 | ||
| 405 | + | ||
| 406 | +| 内容 | 位置 | | ||
| 407 | +|---|---| | ||
| 408 | +| schema:`subtask_kind` + `claimed_at` | `work-graph-db.js`(批 6 迁移,`ALTER TABLE ADD COLUMN`,纯增量向后兼容;`subtask_kind` 取值域 `'acceptance_item'|'claimable_work'`,只有新建库有 CHECK,存量库应用层守,跟 `acceptance_mode` 那次迁移同一套限制) | | ||
| 409 | +| `createTask` 校验 | 新增 `subtaskKind`/`status` 参数:`subtaskKind` 非法值拒、没有 `parentTaskId` 拒;`status` 只放开 `'draft'`/`'claimable'` 两个初始值,`'claimable'` 只能配 `subtaskKind='claimable_work'` | | ||
| 410 | +| 认领 CAS | `claimSubtask`/`unclaimSubtask`(`work-graph-db.js`)——全仓库第一个"认领(pull)"语义写入,照抄 `claimQueuedTask` 的 `changes` 判据。认领成功同时把 `executor` 改成 `'agent'`,复用既有 `executor='agent'` 派单闭环(`/task/report` 上报),**不碰 `graph-engine.js` 一行调度逻辑**,跟设计阶段的判断一致 | | ||
| 411 | +| 物化 | `materializeClaimableSubtasks`(`work-graph-db.js`)——两阶段建法处理 `depends_on_hint` 前向引用,幂等(按 `subtask_kind='claimable_work'` 计数),从 `subtask-planning.triggerSubtaskPlanning` 写完 artifact 后立刻调用,不等 org-planner | | ||
| 412 | +| **必须同步改的坑,已修** | `graph-engine.js` 的 `settleNode` `SUBTASKS_INCOMPLETE` 闸门查询收窄成 `AND subtask_kind = 'acceptance_item'`;`maybeMaterializeItemizedSubtasks` 的幂等判据和 `createTask` 调用同步打上 `subtask_kind='acceptance_item'`。两处都补了回归测试(见下) | | ||
| 413 | +| 路由 | `POST /:companyId/tasks/:taskId/claim`、`.../unclaim`;`taskView` 补 `subtaskKind`/`claimedAt`;`GET /:companyId/tasks` 加 `subtaskKind` 过滤(可认领池查询=`?subtaskKind=claimable_work&status=claimable`,不用专门开池子端点) | | ||
| 414 | +| 角色白名单 | 写死 `CLAIMABLE_WORK_ROLES = ['org-coder']`(`company.js`),不做能力匹配 | | ||
| 415 | +| 测试 | 新增 `task-pool-claim.test.js`(23 条:DB 层 `createTask` 校验/`materializeClaimableSubtasks`/CAS + 路由层白名单/并发/放弃);`task-decomposition-validator-gate.test.js` 补 1 条回归测试(`claimable_work` 子任务不影响 `acceptance_item` 验收判定)+ 更新既有用例显式打 `subtaskKind`(闸门收窄后这些用例如果不补 `subtaskKind: 'acceptance_item'` 会全部失效——查询看不到没打标的行,等于闸门形同虚设,真被这次改动摸到了);`task-decomposition-materialize.test.js` 补 `subtask_kind` 落库断言。全量单测 1202 条,1200 passed,唯二失败与本次改动无关、改动前即存在 | | ||
| 416 | + | ||
| 417 | +### 一次诚实的记录:本地库被顺手迁移了一次 | ||
| 418 | + | ||
| 419 | +排查一处语法错误(SQL 模板字符串里误用了反引号,把 `db.exec` 的模板字符串提前闭合——`work-graph-db.js` 建表块头部本来就有一条注释警告这件事,这次还是踩上了)时,用了一句 `node -e "require('./server/services/work-graph-db.js')"` 做语法检查——这条命令**没有设 `GRAPH_DB_PATH`**,不是测试进程(没有 `assertNotProdDbInTests` 的拦截),实际对本机 `data/graph.sqlite`(本地开发库,Phase 2 真实回归的测试公司数据也在里面)跑了一次批 6 迁移。核实过:迁移是纯增量的 `ALTER TABLE ADD COLUMN`,102 条既有 task 行原样在、`subtask_kind` 全部是 `NULL`,没有数据损坏。但这本可以用一次性临时库避免,记在这里是给自己留个教训——语法检查也该走隔离环境,不该因为"只是 require 一下"就放松。 | ||
| 420 | + | ||
| 421 | +### 还没做真实端到端回归 | ||
| 422 | + | ||
| 423 | +跟 Phase 1/2 一样,机制通不通已经用单测验证(DB 层 CAS、路由层白名单/并发、settleNode 闸门收窄的回归)。**没做的是**:用真实公司走一遍"task 入队 → subtask-planning 产出 steps → 物化出可认领子任务 → org-coder 真的调 `/claim` 认领 → 自己搞定 → `/task/report` 上报 → 状态正确落到终态"这条完整链路——尤其是最后一段(认领后 `org-coder` 自己怎么干),Phase 3 设计里已经写明"这一段完全没有验证质量的机制,跑得糙",真实回归大概率会暴露这一段的具体问题(比如 `org-coder` 会不会真的知道要去查有哪些可认领子任务、认领了之后要不要真的去写代码、写完会不会记得调 `/task/report`——这些都是提示词/流程层面的问题,不是这次数据库+路由层改动能回答的)。留给用户后续决定何时验证。 | ||
| 424 | + | ||
| 402 | ### 遗留给 Phase 4 的问题 | 425 | ### 遗留给 Phase 4 的问题 |
| 403 | 426 | ||
| 404 | - 现在"认领后怎么干"完全靠 `org-coder` 自主决定,质量没有保障——要不要给 `claimed` 状态补一段正式的"开发 + 验证"生命周期?如果要,是新起一次简化版 work-graph run,还是在现有 `executor='agent'` 闭环里加一道可选的验证钩子(成本更低,但仍然不是"独立 run")?两个方向哪个都不是这次 Phase 3 该决定的事,需要单独评估。 | 427 | - 现在"认领后怎么干"完全靠 `org-coder` 自主决定,质量没有保障——要不要给 `claimed` 状态补一段正式的"开发 + 验证"生命周期?如果要,是新起一次简化版 work-graph run,还是在现有 `executor='agent'` 闭环里加一道可选的验证钩子(成本更低,但仍然不是"独立 run")?两个方向哪个都不是这次 Phase 3 该决定的事,需要单独评估。 |