-
R-20.5 四条: 1. task-planning agent 提进 v1(原计划 v2 人手拆)。产出一律 draft 清单,人确认编辑后才下达 —— 那一步是唯一一道成本闸门, 拆出 5 条 task 就是 5 份 DEFAULT_TASK_BUDGET 2. 并行仍留批 4,v1 只排队(max_parallel_tasks=1,唯一索引不动) 3. manual 任务不参与自动出队:startRun(manual) 只点亮入口就停下等 /next,而 run 已经是 running 占着坑,自动拉起会堵死队头 4. 上游失败 → 下游自动推导为 blocked 并标红,给「重跑上游」和 「强制放行」两个出路。blocked 每次 tick 重算而不落死, 上游重跑成功后下游自己回 queued 定案 1 牵出一处新缺陷:task-planning 跑在 goal 层、任何 run 存在 之前,它烧的 token 没有预算池可扣 —— 正是 defaultPlanWorkGraph 注释里点名的「隐形的一半花费」在 goal 层的新实例。上一轮刚以 「零消费方」为由砍掉的 goal 级预算字段,以记账字段 planning_tokens 的形式回来(闸门仍不做)。 链路照抄 defaultPlanWorkGraph 不另造:调 agent → 校验 → errors 原样回喂,最多 3 轮;3 轮不过降级成 1 条同描述的 task,绝不能把 goal 卡在 planning。新本体必须与 _registry.json 登记同 commit, 否则 template-refs.test.js 当场把 CI 跑红(§八.21 有前科)。 验收 19-24 新增:拆分正常 / 失败降级 / 记账 / 不该花钱的路径不花钱 / 上游失败下游标红且可恢复。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
-
逐条对着代码核初稿,最要命的一条是基础事实搞错了: - createRun 在建行的事务里就按 readDefGraph 把 graph_run_nodes 全插好了。 初稿三处基于「queued run 没有节点行、进去就是空指针」的论证全部作废。 真实情况是 queued run 与 ready run 在数据上只差 run_status 一个字段, 所以「靠没有节点行自然报错」那道想象中的防线根本不存在, 唯一的闸门是 advanceOne 里 run_status !== 'running' 那一句,必须加断言钉死。 由此派生出一个既存、但被排队从毫秒窗口放大成必然事件的缺陷: 节点行在 createRun 时快照,而 getRunState 每次读都取当前定义。 排队期间点「重新规划组织」→ 新节点没有 run 行 → 出队即卡死。 补 syncRunNodesToDef,出队前对齐。 其余六处: - 出队原语写错:markRunReady 把 from 写死成 planning,复用不了; 正解是 updateRunStatus(runId,'queued','ready') 这一条条件更新 - 唯一索引冲突是 throw 不是 changes=0,初稿的错误处理只覆盖一半 - 触发点枚举本身是漏的:stopRun 与预算耗尽→blocked 两条最常见的 释放路径都不走 settleRun。改为挂在唯一漏斗 transitionRun 上, 一个钩子覆盖全部路径(枚举法在这里靠不住,而漏的症状是静默的) - report_to 只活在请求闭包里,排队后回调链路静默断掉 → 必须落库 - okr_node_id 逐 task 下发会反复覆写同一个 OKR 节点, done 会被后来的 failed 翻掉 → task 的 run 一律不带 okr_node_id - manual 任务占着 running 等人点「下一步」,会永久堵住队头 → 不参与自动出队 补漏:存量回填脚本(不做的话批 1 反而让历史任务更看不见)、 任务级 rerun 与节点级 retry 的命名撞车、queuePosition 排序口径 必须与调度器同源、砍掉没有消费方的 goals.budget_json。 错误结论留档不删(§三 ⚠️ 块 / §五.1 / §九.1 开头)—— 它们是最容易再犯一次的那类。验收从 12 条涨到 19 条。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
-
控制台走查暴露的「一个 company 只能有一个任务」,根因不是并发约束, 是「人类提的需求」和「机器执行的单元」被压在同一条 root graph_run 上。 三个实地核实的前提,让这次不是发明新概念: - 27-NAMING §四 早就定义了 goal 1 : task N 的基数 - graph_runs.goal_id / task_id 两列早就在,company.js 注释也写着 「三者基数不同不可混用」—— 但全仓库没有任何写入方,goal_id 是悬空外键 - G- 前缀已被 OKR 正名释放;/api/goals 与 /api/company/:cid/goals 这两个 OKR 向后兼容别名全仓库零调用方,可以退役后把路径要回来 设计要点: - goals / tasks 两张新表 + graph_runs 新增 run_status='queued' - queued 的唯一理由是把出队的并发临界区交给既有唯一索引兜底: idx_graph_runs_one_active_root 覆盖 ready/running/paused 而不覆盖 queued, 超发会被索引直接拒绝,不需要应用层的「先查后插」 - 排队推翻了 P3「拒绝而不排队」的定案,但那条定案的理由(没有出队 worker = 静默丢任务)今天仍成立,所以调度器的四个触发点是功能主体而非收尾 - 已下达的描述冻结:入队即写 task-goal.json 并被 describeTask 消费, 改库不改 artifact 会让两份对不上,两份都改等于篡改审计输入 - 现有 T-${Date.now().toString(36)} 在「一个 goal 批量建 N 个 task」下 同毫秒必撞,且 tasks.id 是主键 —— 改用仓库既有约定的 4hex 后缀 R-20 四条定案回记至 27-requirement.md。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>