-
## 上一版漏了什么 预算行挂在 root run,我就只在 root 的转换上结算。而**活动发生在树里任何一层**: 人工重试一个 work 层节点动的是子 run(blocked → running),root 全程 blocked。 后果:子 run 跑整场、墙钟一次都没开始计,旧锚点还留着 —— 第一次 checkBudget 立刻判耗尽。单测当时全绿,因为它们只喂了 root。 **是真起服务、真点重试才撞出来的**:那条卡住的 run 重试后子 run 起来了, root 的 started_at 仍是 08-18。 ## 改 · 任何一层进 running 都开始计时(预算行仍写 root,readBudget 自动上溯)。 · 离开 running 时先查树里还有没有 running 的 run —— 有就不结算, 否则一层停了会把整段计时提前掐断。 · 树里已经有 run 在跑时,另一条进 running 不重锚,否则前一段被抹掉。 ## 存量重锚必须在开库时做 钩子只在「进 / 出 running」时触发,而升级那一刻正停在 running 的 run 不会再进一次 running —— 旧锚点一直挂着,下一次 checkBudget 直接判耗尽。 ⚠️ 第一版把这段迁移写进了 graph-db.js 的 migrate(),而 graph_runs 是 work-graph-db 建的表、graph-db 的迁移块跑在它之前 —— 新库上直接 `no such table: graph_runs`,getDb() 起不来。已挪到建这张表的模块里。 和 §16.2 那次「加索引写进建表块」是同一类顺序问题,这是第二次。 守卫 budget-wallclock-migration.test.js 走的是**存量库重启**那条路 (照抄 tasks-executor-migration 的 freshDb 写法):老锚点归零、running 的续上、 其余断开、没配 wallclock_ms 的不许被塞字段、坏 json 不许把开库卡死、幂等。 ## 真跑验证 重启服务 → 迁移在真库上跑到(run_9168bd24f46c 的 started_at 归 null、active_ms=0) → 重试 org-planner-sdd → POST /next → **节点 success,attempt 2**, 预算 8/100 次调用、78,858/5,000,000 tokens,org-planner-benchmark 已转 ready。 这条 run 从 2026-08-18 16:19 卡到现在,是 27-p3c-batch3-handover §五 「还没解决的原始问题」。 全量:138 文件 / 1289 测试全绿。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>