Commit 54ee14eb497a8b2a9acf8a8f854db3373650f58a

Authored by yibo
1 parent edeff2ec

docs(27): P3C 收口归档 + §十七 清尾记录 + 各文档状态校准

## 移进 done/

· 27-p3c-goal-task-model.md —— 五批实施完毕,§15.5 / §16.8 的后续项也全部收掉。
  新增 **§十七**:欠账清单对账、边界守卫从「乱扣帽子」改成「留证据不判罚」、
  测试污染生产图库(第四次踩同一族,但换了个方向进来)、那条卡了两天的 run,
  以及 **§17.5 真跑验收** —— org-planner-sdd/benchmark/validator 全 success、
  work run completed、父节点自动拉回、org-coder 起实现层子图、
  org-coder-validator 判 fail 走回退边打回 impl(loopCount 1)。
  **返工闭环第一次由真 agent(不是注入的假 executor)走通。**

· 27-p3c-batch3-handover.md —— 四条复核结论全修完、§五 那条 run 已解开,
  §七 待办全部打勾。从待办转为**事故记录归档**:§六 那几条多会话协作规则是真踩出来的。

两份的相对链接都已重指(done/ ↔ todo/ 跨目录),no-dead-path-references 守卫通过。

## 留在 todo/ 的,状态说清楚

· 27-graph-agent-architecture.md —— 状态行校准。那一行是别人判断「能不能搬 done」的依据。
· 27-p3b-real-run-runway.md —— 加状态行:验收 7 ⛔ 真跑不成立(readme-writer 混进
  org graph,**未修**)、2/4/8/9 未在干净环境验。缺陷② 的**根因**今天修了,
  但特意写明「**根因修了不等于验收点验了**」—— 不然下一个人会照着状态行当成验过。
· 27-p3-p4-work-graph-console.md —— 在索引里写明留 todo 的原因:
  §十 那笔「真实路径 smoke 进 CI」的欠账未还。
· 28-followups.md —— §3.3 标已修(含「GET /info 的 404 闸门仍没修,别当成修过」);
  §五 守卫表加两行(graph-db-prod-guard / heartbeat-company-scoped),
  并补第七条的来历。

## docs/README.md

索引补上新增的 done 条目与 P3B / 28-followups 行,主线说明改成
「当前未完成的是哪几件」——原来只说完成了什么,读的人得自己推。

全量:138 文件 / 1292 测试全绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
docs/README.md
... ... @@ -8,7 +8,9 @@
8 8  
9 9 判断依据:文档正文的显式「状态」标记(✅ 已完成 / 已实现 vs 📝 设计中 / 未实现)、未勾选的 checklist,以及与代码库实际实现的交叉核对(见各条目备注)。
10 10  
11   -> **当前主线**:Graph Agent 架构重构([27-graph-agent-architecture.md](./todo/system-design/27-graph-agent-architecture.md))。该系列已完成的阶段文档(P1/P2)移入 `done/`,其余非主线待办在 `todo/future/`。
  11 +> **当前主线**:Graph Agent 架构重构([27-graph-agent-architecture.md](./todo/system-design/27-graph-agent-architecture.md))。
  12 +> 该系列已完成的阶段文档(P1 / P2 / **P3 收尾 P3C**)移入 `done/`,其余非主线待办在 `todo/future/`。
  13 +> **当前未完成的是**:P3B 真跑跑道的几条验收、P3/P4 那笔「真实路径 smoke 进 CI」的欠账、P4(未实现)、28-followups。
12 14  
13 15 ## done/
14 16  
... ... @@ -24,6 +26,8 @@
24 26 | [user-guides/08-base-agent-4-phase-guide.md](./done/user-guides/08-base-agent-4-phase-guide.md) | Base Agent 四阶段使用指南 |
25 27 | [system-design/27-p1-virtual-reference.md](./done/system-design/27-p1-virtual-reference.md) | P1 虚拟引用寻址 — ✅ 已实现(commit `226489d`,`server/services/graph-service.js`):`agent.md` 不再逐公司拷贝,改为 `config.json.systemAgentRef` 引用 + `company-context.md` 承载公司语境 |
26 28 | [system-design/27-p2-org-graph.md](./done/system-design/27-p2-org-graph.md) | P2 Org Graph — ✅ 已实现(`70a4727` + `f20d0d8`):org graph 定位为 company 级 workflow(执行流边),`orggraph-planning` agent 建公司时自动规划并招聘。真实建公司端到端验证通过 |
  29 +| [system-design/27-p3c-goal-task-model.md](./done/system-design/27-p3c-goal-task-model.md) | **P3 收尾** goal / task 两级模型 + 控制台任务列表 — ✅ 已完成(2026-08-20):五批实施 + §十七 清尾。含队列 / 并行槽位、`task-planning`、两套任务体系统一、墙钟预算改「只算活跃时长」。**§17.5 是真跑验收** —— 返工闭环第一次由真 agent(不是注入的假 executor)走通 |
  30 +| [system-design/27-p3c-batch3-handover.md](./done/system-design/27-p3c-batch3-handover.md) | 批 3 交接 —— ✅ 已收口(2026-08-20)。**事故记录归档**:一份未经复核的代码被第三方会话提交进 main。留着是因为 §六 那几条多会话协作规则是真踩出来的 |
27 31 | [system-design/01-26](./done/system-design/) | 系统设计正文 01~26 章(14、25-harness-engineering-improvements 例外,见 todo/future/;27 例外,见 todo/),各章节状态见文内「状态」标记 |
28 32  
29 33 ## todo/(当前主线)
... ... @@ -37,9 +41,11 @@ Graph Agent 架构重构(27 系列)。**已完成的阶段文档已移入 `d
37 41 | [27-naming-conventions.md](./todo/system-design/27-naming-conventions.md) | **命名规范**。`{作用域}-{职能}`;图节点按层级轴命名;节点名 ≠ 本体名;三种 benchmark 消歧;OKR 正名。新增 agent id / 表名 / 字段名前必读 |
38 42 | [27-e2e-task-execution-flow.md](./todo/system-design/27-e2e-task-execution-flow.md) | 端到端流程总览:建公司 → 下达任务 → org graph 逐节点执行 → work graph 规划与循环 → 验收收敛。含与 DevLoop 既有实现的对应关系分析 |
39 43 | [27-example-dev-company-walkthrough.md](./todo/system-design/27-example-dev-company-walkthrough.md) | 参考场景走查(虚构的「配图工厂」),把架构跑一遍具体的数:各阶段 JSON 形态、成本估算、断点清单 |
40   -| [27-p3-p4-work-graph-console.md](./todo/system-design/27-p3-p4-work-graph-console.md) | P3+P4(原 P4 回退+Loop-Validator 已并入)图执行引擎与执行控制台 — ✅ 已实现(`c3abf4a`),文档仍在补充中 |
  44 +| [27-p3-p4-work-graph-console.md](./todo/system-design/27-p3-p4-work-graph-console.md) | P3+P4(原 P4 回退+Loop-Validator 已并入)图执行引擎与执行控制台 — ✅ 已实现(`c3abf4a`)。**仍留 todo 的原因**:§十 末「四条硬规矩」第 2 条那笔欠账未还 —— 引擎用例一律注入假 executor / 假 planner,**没有一条真实路径的 smoke 进 CI** |
  45 +| [27-p3b-real-run-runway.md](./todo/system-design/27-p3b-real-run-runway.md) | P3 收尾之真跑跑道(从 mock 走到真 Claude CLI)— 📝 **仍在推进**。验收 7 ⛔ 真跑不成立(`readme-writer` 混进 org graph,未修);2/4/8/9 未在干净环境验。缺陷② 的根因(边界守卫误判并行会话)已于 2026-08-20 修掉,但**根因修了不等于验收点验了** |
41 46 | [27-goal-contract-format.md](./todo/system-design/27-goal-contract-format.md) | 验收契约格式(`goal-benchmark` / `goal-test-data` / `goal-test-script` 的产物形态与跨节点传递) |
42   -| [27-p4-parallel-and-artifacts.md](./todo/system-design/27-p4-parallel-and-artifacts.md) | **P4(回收编号)并行执行与产物索引** — 📝 设计中。fan-out 真并发 + 同 agent 多实例隔离 + `files.json` 产物索引。三个 Phase,C 可插队 |
  47 +| [27-p4-parallel-and-artifacts.md](./todo/system-design/27-p4-parallel-and-artifacts.md) | **P4(回收编号)并行执行与产物索引** — 📝 设计中,未实现。fan-out 真并发 + 同 agent 多实例隔离 + `files.json` 产物索引。三个 Phase,C 可插队 |
  48 +| [28-followups.md](./todo/system-design/28-followups.md) | 28 号(Agent 注册表统一)的遗留清单 — 主文档已在 `done/`,这份装没做完的:dream 机制(只有口述、无设计)、任务态清理(源码树无限增长)、`source_kind`/`legacy_path` 删列、三项「已实施未验证」。§五 是**已立起来的守卫清单**(别重复造,也别删) |
43 49  
44 50 ## todo/future/(暂缓,非当前重心)
45 51  
... ...
docs/todo/system-design/27-p3c-batch3-handover.md renamed to docs/done/system-design/27-p3c-batch3-handover.md
... ... @@ -2,7 +2,10 @@
2 2  
3 3 > 记录时间:2026-08-19 17:1x
4 4 > 记录人:Claude ä¼šè¯ `lemonboss-8x`ï¼ˆæœ¬æ–‡æ¡£çš„ä½œè€…ï¼Œä¹Ÿæ˜¯ä¸‹é¢ 87b776c / b0b2b62 两笔æäº¤çš„æ‰§è¡Œè€…)
5   -> 状æ€ï¼š**未收å£**。等 lemonboss-78 的批 3 ä¿®å¤å®ŒæˆåŽä¸€èµ·å¤„ç†ã€‚
  5 +> 状æ€ï¼šâœ… **已收å£**(2026-08-20)。四æ¡å¤æ ¸ç»“论全部修完(记在
  6 +> [27-P3C §15.3](./27-p3c-goal-task-model.md)),§五 é‚£æ¡å¡ä½çš„ run 也已解开并真跑推进
  7 +> (§17.4 / §17.5)。本文档从待办转为**事故记录归档**ï¼Œç•™ç€æ˜¯å› ä¸º §六 那几æ¡å作规则
  8 +> 是真踩出æ¥çš„ï¼Œä¸æ˜¯çº¸ä¸Šè°ˆå…µã€‚
6 9  
7 10 ## 一å¥è¯
8 11  
... ... @@ -167,16 +170,22 @@ task ç¿» queued åŽ `hasStartedRun()` 返回 false → `GraphConsole.vue:248` æŠ
167 170  
168 171 ---
169 172  
170   -## 七ã€ä¸‹ä¸€æ­¥
  173 +## 七ã€ä¸‹ä¸€æ­¥ —— 全部完æˆï¼ˆ2026-08-20 回填)
171 174  
172 175 - [x] ~~lemonboss-78 è¡¥é½ Â§äºŒ 里缺的 3 æ¡å¤æ ¸ç»“论~~ —— 已补é½å¹¶æäº¤ï¼ˆ`5a31d00`),4 æ¡å‡å¸¦ç‹¬ç«‹æŽ¢é’ˆå®žè·‘è¯æ®
173   -- [ ] 定 `87b776c` çš„å¤„ç†æ–¹å¼ï¼ˆå»ºè®®ä¿®å¤å‰æŽ¨ï¼‰
174   -- [ ] **N1** ä¿®æŽ‰å­¤å„¿å­ runï¼ˆå–æ¶ˆæŽ’队时还在烧 token)—— å”¯ä¸€æœ‰ç›´æŽ¥é‡‘é’±æˆæœ¬çš„一æ¡ï¼Œä¼˜å…ˆ
175   -- [ ] **L1** æ¢å¤è·¯å¾„对 manual 任务补一æ¡å‡ºè·¯ï¼ˆçŽ°åœ¨é€€å›žé˜Ÿåˆ—åŽæ²¡äººæŽ¥ï¼Œsweep 空转)
176   -- [ ] **N2** 「退回队列ã€é€å‡ºåˆ°ç•Œé¢ï¼ˆ`requeued` 字段全å‰ç«¯é›¶è¯»å–ï¼›æŒ‰é’®å…¨ç° + 图消失 + å‡æç¤ºè¯­ï¼‰
177   -- [ ] **N3** `isSlotRaceError` 第三æ¡åˆ¤æ®æŒ‰æŽ¢é’ˆç»“论改写,别å†åžçœŸé”™è¯¯
178   -- [ ] 工作区收敛干净åŽï¼Œé‡è·‘ `T-msyu6u9b-939c`ï¼ˆè§ Â§äº”ï¼‰
179   -- [ ] 考虑给边界守å«åŠ ã€Œå¤šå†™å…¥è€… → 放弃判罚ã€çš„å£å­ï¼ˆÂ§äº” 末尾)
  176 +- [x] 定 `87b776c` çš„å¤„ç†æ–¹å¼ —— **ä¿®å¤å‰æŽ¨**,4 æ¡ä½œä¸ºåŽç»­æäº¤è§£å†³
  177 +- [x] **N1** å­¤å„¿å­ run —— 改为无æ¡ä»¶èµ° `engine.stopRun`([27-P3C §15.3](./27-p3c-goal-task-model.md))
  178 +- [x] **L1** manual çš„æ¢å¤å‡ºè·¯ —— 判æ®ç”¨ `attempt > 0` 而**䏿˜¯** `started_at`(åŽè€…çœ‹ç€æ›´è´´åˆ‡ï¼Œä½† `requeueBlockedRootRun` é€€å›žé˜Ÿåˆ—æ—¶ä¼šæŠŠå®ƒæ¸…æˆ NULL,æ°å¥½åœ¨éœ€è¦å®ƒçš„那一刻是空的,实测踩过)
  179 +- [x] **N2** 「退回队列ã€é€å‡ºåˆ°ç•Œé¢ —— 加 `notice` 一行明说「已退回队列排队,å‘一空会自动接ç€è·‘ã€
  180 +- [x] **N3** `isSlotRaceError` —— 探针è¯ä¼ªåŽ**删掉该分支**(被推走时æ¡ä»¶æ›´æ–°è¿”回 0ã€ä¸æŠ›ï¼›çœŸæ­£æŠ›å®ƒçš„åªæœ‰ã€Œè°ƒç”¨æ–¹å£°æ˜Žäº†éžæ³•转æ¢ã€ï¼Œé‚£ä¸€æ”¯æŠŠè°ƒç”¨æ–¹çš„ bug 当竞æ€åžæŽ‰ä¸”ä¸ç•™æ—¥å¿—)
  181 +- [x] é‡è·‘ `T-msyu6u9b-939c`ï¼ˆè§ Â§äº”ï¼‰â€”â€” ✅ **2026-08-20 已解开并推进**ï¼Œè§ [27-P3C §17.4 / §17.5](./27-p3c-goal-task-model.md)
  182 +- [x] 给边界守å«åŠ ã€Œå¤šå†™å…¥è€… → 放弃判罚ã€çš„å£å­ï¼ˆÂ§äº” 末尾)—— ✅ å·²åŠ ï¼Œè§ [27-P3C §17.2](./27-p3c-goal-task-model.md)
  183 +
  184 +> **§五 é‚£æ¡ run 的结局值得å•独记一å¥**:本文档判断「它å¡ä½æ˜¯å› ä¸ºè¾¹ç•Œå®ˆå«è¯¯ä¼¤ã€ï¼Œ
  185 +> è¿™ä¸€åŠæ˜¯å¯¹çš„ —— 但守å«ä¿®å®Œä¹‹åŽ**它ä»ç„¶è·‘ä¸åЍ**。第二é“é”在墙钟预算上
  186 +> (`blocked` 挂起等人的时间被算进「已用ã€ï¼Œè¿‡å¤œçš„ run 永远醒ä¸è¿‡æ¥ï¼‰ï¼Œ
  187 +> 那把é”åªæœ‰çœŸåŽ»ç‚¹ä¸€æ¬¡é‡è¯•æ‰éœ²å‡ºæ¥ã€‚
  188 +> **「修完 A å°±èƒ½è·‘ã€æ˜¯ä¸ªå‡è®¾ï¼Œä¸æ˜¯ç»“论 —— å¡ä½çš„东西å¯ä»¥æœ‰ä¸æ­¢ä¸€æŠŠé”。**
180 189  
181 190 > §二 é‚£æ¡ã€Œæ³¨é‡Šæ‰¿è¯ºçš„å‰æè¢«æœ¬è½®è‡ªå·±çš„æ”¹åŠ¨æ”¹æ²¡äº†ï¼Œæ³¨é‡Šè¿˜ç•™ç€ã€å·²ç»æ˜¯ç¬¬ä¸‰æ¬¡ç«‹æ¡ˆ
182 191 > (§å三.3 / §åå››.4 / 本次)。第三次就ä¸è¯¥å†åªå½“个案记 —— å€¼å¾—è€ƒè™‘ä¸€æ¡æœºå™¨å¯æŸ¥çš„守å«ï¼š
... ...
docs/todo/system-design/27-p3c-goal-task-model.md renamed to docs/done/system-design/27-p3c-goal-task-model.md
1 1 # 27-P3C. å…¬å¸ç›®æ ‡ä¸Žä»»åŠ¡ —— goal / task 两级模型 + 控制å°ä»»åŠ¡åˆ—è¡¨
2 2  
3   -> **所属**: [27 Graph Agent æž¶æž„](./27-graph-agent-architecture.md) çš„ **P3 æ”¶å°¾**(P3C),直接续 [27-P3/P4 执行控制å°](./27-p3-p4-work-graph-console.md) §四.B 与 [27-P3B 真跑跑é“](./27-p3b-real-run-runway.md)。
  3 +> **所属**: [27 Graph Agent æž¶æž„](../../todo/system-design/27-graph-agent-architecture.md) çš„ **P3 æ”¶å°¾**(P3C),直接续 [27-P3/P4 执行控制å°](../../todo/system-design/27-p3-p4-work-graph-console.md) §四.B 与 [27-P3B 真跑跑é“](../../todo/system-design/27-p3b-real-run-runway.md)。
4 4 > **日期**: 2026-08-18
5   -> **状æ€**: **五批全部实施完毕并全绿**(§å三 ~ §å六)。132 文件 / 1257 测试,`web:build` 通过。开放问题已全部关闭;åŽç»­é¡¹è§ §15.5 与 §16.8。
  5 +> **状æ€**: ✅ **已完æˆå¹¶å½’æ¡£**(2026-08-20)。五批全部实施(§å三 ~ §å六),§15.5 / §16.8 çš„åŽç»­é¡¹ä¹Ÿå·²å…¨éƒ¨æ”¶æŽ‰ï¼ˆÂ§å七)。
  6 +> 138 文件 / 1292 测试全绿,`web:build` 通过。**çœŸè·‘éªŒæ”¶è§ Â§17.5** —— 返工闭环第一次由真 agentï¼ˆä¸æ˜¯æ³¨å…¥çš„å‡ executor)走通。
6 7 > **âš ï¸ æ‰¹æ¬¡ä¸Ž phase çš„å¯¹åº”ä¸æ˜¯ä¸€ä¸€å¯¹é½çš„**,判断「这份能ä¸èƒ½æ¬è¿› doneã€æ—¶æŒ‰æ‰¹çœ‹ï¼Œåˆ«æŒ‰æ–‡æ¡£å看:
7 8 > · **批 1-3 = 真正的 P3 收尾**(goal/task 两级模型 + `task-planning` + 排队),本文档的主体;
8   -> · **批 4(并行)归 [27-P4](./27-p4-parallel-and-artifacts.md) §一.3**,那边是设计æƒå¨ï¼Œæœ¬æ–‡æ¡£åªæœä»Žï¼ˆè§ §五.2 的警示å—);
  9 +> · **批 4(并行)归 [27-P4](../../todo/system-design/27-p4-parallel-and-artifacts.md) §一.3**,那边是设计æƒå¨ï¼Œæœ¬æ–‡æ¡£åªæœä»Žï¼ˆè§ §五.2 的警示å—);
9 10 > · **批 5(两套任务体系统一)ä¸å±žäºŽä»»ä½•既有 phase** —— 是跨阶段的技术债清ç†ï¼Œé£Žé™©é¢ä¹Ÿä¸Žå‰å››æ‰¹å®Œå…¨ä¸åŒï¼ˆå了是所有 agent 互相派ä¸äº†æ´»ï¼‰ï¼Œè§ §å二.6。
10 11 > **交付物**: â‘  `goals` / `tasks` 两张表,把「人类下达的需求ã€ä¸Žã€Œlemonboss 执行的å•å…ƒã€æ‹†æˆä¸¤çº§ï¼›â‘¡ 基于这两张表的**排队与并行**;③ 执行控制å°ï¼ˆ`/:id/graph-console`)最左侧新增**目标·任务两级列表æ **。
11   -> **命å**: 全文éµå¾ª [27-NAMING](./27-naming-conventions.md),本文档**è½åœ°**的正是它 §四 定义但代ç é‡Œä¸€ç›´æ²¡æœ‰è½½ä½“çš„ `goal 1 : task N` 基数关系。
  12 +> **命å**: 全文éµå¾ª [27-NAMING](../../todo/system-design/27-naming-conventions.md),本文档**è½åœ°**的正是它 §四 定义但代ç é‡Œä¸€ç›´æ²¡æœ‰è½½ä½“çš„ `goal 1 : task N` 基数关系。
12 13 > **代ç å¼•用体例**: 沿用 27-P3/P4 头部约定 —— åªå†™ `文件å` + 函数å / 常é‡å,**ä¸å†™è¡Œå·**。
13 14 >
14 15 > **第二轮(2026-08-18ï¼Œé€æ¡å¯¹ç€ä»£ç å¤æ ¸åˆç¨¿ï¼‰**:抓到 7 处「照åˆç¨¿å®žçŽ°å°±ä¼šå‡º bugã€å’Œ 6 处补æ¼ï¼Œæ­£æ–‡å·²æ”¹ï¼Œå…³é”®çš„错误结论**留档ä¸åˆ **(§三 çš„ âš ï¸ å—ã€Â§äº”.1ã€Â§ä¹.1 开头),因为它们是最容易å†çŠ¯ä¸€æ¬¡çš„é‚£ç±»ã€‚
... ... @@ -47,7 +48,7 @@ C 是根因,A å’Œ B 是它的两个表å¾ã€‚**先拆两级模型,A/B æ‰æœ‰å
47 48  
48 49 ### 2.1 è¿™ä¸æ˜¯æ–°æ¦‚念,是给一个已存在的悬空外键补上它的表
49 50  
50   -[27-NAMING §四](./27-naming-conventions.md) 早已定义好基数:
  51 +[27-NAMING §四](../../todo/system-design/27-naming-conventions.md) 早已定义好基数:
51 52  
52 53 | 概念 | 基数 | 定义(原文) |
53 54 |---|---|---|
... ... @@ -479,7 +480,7 @@ for (const t of queuedTasks) {
479 480  
480 481 **批 4 å•独排期ã€å•独验收**,ç†ç”±ï¼šåˆ æŽ‰ä¸€ä¸ªå”¯ä¸€ç´¢å¼• = 删掉最åŽä¸€é“ DB 兜底,这个动作ä¸è¯¥å’Œã€Œç•Œé¢ä¸Šèƒ½çœ‹åˆ°ä»»åŠ¡åˆ—è¡¨ã€æ··åœ¨ä¸€æ¬¡ä¸Šçº¿é‡Œã€‚
481 482  
482   -> âš ï¸ **批 4 与 [27-P4](./27-p4-parallel-and-artifacts.md) §一.3 是åŒä¸€ä»¶äº‹ï¼Œä¸è¦å„åšä¸€é。** 那份文档的目标 3 é€å­—写ç€ã€Œ**解除「一家公å¸åŒæ—¶åªæœ‰ä¸€ä¸ª active root runã€çº¦æŸ** —— P3 v1 用一个唯一索引强制它(§三.3),并行能力具备åŽåº”放开ã€ã€‚也就是说:**放开约æŸçš„设计归 27-P4,本文档åªè´Ÿè´£åœ¨å®ƒä¹‹ä¸Šå®šä¹‰ã€Œè°æ¥æŽ’é˜Ÿã€æŒ‰ä»€ä¹ˆåºå‡ºé˜Ÿã€**(§五.1)。真到实施时以 27-P4 的并行方案为准,本文档的 §五.2 æœä»Žå®ƒï¼›ä¸¤è¾¹éƒ½å†™ä¸€ç‰ˆä¼šäº§ç”Ÿä¸¤å¥—å¹¶å‘守å«ã€‚
  483 +> âš ï¸ **批 4 与 [27-P4](../../todo/system-design/27-p4-parallel-and-artifacts.md) §一.3 是åŒä¸€ä»¶äº‹ï¼Œä¸è¦å„åšä¸€é。** 那份文档的目标 3 é€å­—写ç€ã€Œ**解除「一家公å¸åŒæ—¶åªæœ‰ä¸€ä¸ª active root runã€çº¦æŸ** —— P3 v1 用一个唯一索引强制它(§三.3),并行能力具备åŽåº”放开ã€ã€‚也就是说:**放开约æŸçš„设计归 27-P4,本文档åªè´Ÿè´£åœ¨å®ƒä¹‹ä¸Šå®šä¹‰ã€Œè°æ¥æŽ’é˜Ÿã€æŒ‰ä»€ä¹ˆåºå‡ºé˜Ÿã€**(§五.1)。真到实施时以 27-P4 的并行方案为准,本文档的 §五.2 æœä»Žå®ƒï¼›ä¸¤è¾¹éƒ½å†™ä¸€ç‰ˆä¼šäº§ç”Ÿä¸¤å¥—å¹¶å‘守å«ã€‚
483 484  
484 485 ---
485 486  
... ... @@ -738,7 +739,7 @@ for (const t of queuedTasks) {
738 739 | **1 · 两级模型è½åº“** | `goals` / `tasks` 建表 + **å­˜é‡å›žå¡«è„šæœ¬ï¼ˆÂ§å››.8)** + ID 生æˆå™¨ä¿®æ­£ + `POST /:cid/tasks` 兼容改造(自动建 goalã€`report_to` è½åº“)+ `GET` 列表端点 + 退役 `/goals` 别å | 4 / 10 / 11 / **12** |
739 740 | **2 · 控制å°å·¦æ  + 拆分** | `GoalTaskPane` 两级树 + URL é€‰ä¸­æ€ + `loadRuns` 修正 + **`task-planning` æœ¬ä½“ï¼ˆå« `_registry.json` 登记)+ 拆分链路 + 失败é™çº§**+ ä¸¤æ­¥è¡¨å• | 1 / 19 / 20 / 21 / 22 |
740 741 | **3 · 排队** | `run_status='queued'` + `RUN_TRANSITIONS` + `syncRunNodesToDef` + `task-scheduler`ï¼ˆæ¼æ–—é’©å­ + ä¸‰ä¸ªè¾…åŠ©è§¦å‘ + é‡å…¥ä¿æŠ¤ + 上游失败推导 blocked)+ `depends_on` 环检测 + 入队/å–æ¶ˆ/rerun 端点 + §四.7 两æ¡ç¦ä»¤ + §ä¹.1 全部回归点 | 2 / 3 / 5 / 6 / 7 / 8 / 9 / 13-18 / 23 |
741   -| **4 · 并行**(å•独排期)| `max_parallel_tasks` + `DROP` 唯一索引 + 事务内 admit。**与 [27-P4](./27-p4-parallel-and-artifacts.md) §一.3 åŒä¸€ä»¶äº‹**,实施以那份为准 | å¦ç«‹éªŒæ”¶ |
  742 +| **4 · 并行**(å•独排期)| `max_parallel_tasks` + `DROP` 唯一索引 + 事务内 admit。**与 [27-P4](../../todo/system-design/27-p4-parallel-and-artifacts.md) §一.3 åŒä¸€ä»¶äº‹**,实施以那份为准 | å¦ç«‹éªŒæ”¶ |
742 743 | **5 · 任务体系统一**(å•独排期)| è§ Â§å二:`executor` / `assignee_agent_id` / `parent_task_id` 三字段 + `/task/dispatch` æ¢å­˜å‚¨ + 删会è¯å推 + `tasklog` 回填 | 25-30 |
743 744  
744 745 > 批 3 的验收从 6 æ¡æ¶¨åˆ° 12 æ¡ï¼Œæ˜¯æœ¬æ¬¡å¤æ ¸çš„直接结果 —— 13/14/15 三æ¡å„自对应一个「åˆç¨¿ä¼šå®žçŽ°å‡ºæ¥çš„é™é»˜æ•…éšœã€ã€‚
... ... @@ -844,7 +845,7 @@ parent_task_id TEXT REFERENCES tasks(id), -- B 的任务链;A 的 depends_
844 845  
845 846 ## åä¸‰ã€æ‰¹ 1 实施记录(2026-08-18,commit `7f24ef0`)
846 847  
847   -> 体例照 [27-P3/P4](./27-p3-p4-work-graph-console.md) §å:**è®¾è®¡æ­£æ–‡ä¸æ”¹å†™ï¼Œåªåœ¨è¿™é‡Œä¸Žå®žçŽ°å¯¹è´¦**。
  848 +> 体例照 [27-P3/P4](../../todo/system-design/27-p3-p4-work-graph-console.md) §å:**è®¾è®¡æ­£æ–‡ä¸æ”¹å†™ï¼Œåªåœ¨è¿™é‡Œä¸Žå®žçŽ°å¯¹è´¦**。
848 849 > å‡¡æœ¬èŠ‚ä¸Žå‰æ–‡å†²çªï¼Œ**以本节为准** —— 剿–‡æ˜¯è®¾è®¡æ—¶çš„判断,本节是跑出æ¥çš„事实。
849 850  
850 851 ### 13.1 è½åœ°äº†ä»€ä¹ˆ
... ... @@ -1199,3 +1200,112 @@ agent 的会è¯ç›®å½• —— 路由那 10 秒缓存就是为它加的。
1199 1200 但它是所有 agent 的工具说明,值得å•独一次改动 + 通告。
1200 1201 3. `TaskTimeline.vue` 未动。它按字段åå–值,本轮ä¿ä½äº†å…¨éƒ¨ 12 个字段,但 `agents` /
1201 1202 `conversationCount` 的语义å˜äº†ï¼ˆè§ §16.6),界é¢ä¸Šçš„æŽªè¾žå¯èƒ½è¦è·Ÿç€è°ƒã€‚
  1203 +
  1204 +---
  1205 +
  1206 +## åä¸ƒã€æ”¶å°¾ä¹‹åŽï¼ˆ2026-08-20)—— §16.8 与 §15.5 全部收掉,外加真跑挖出æ¥çš„三æ¡
  1207 +
  1208 +> ä½“ä¾‹åŒ Â§å三~§å六。这一节记的是 P3C 五批之åŽçš„æ¸…尾,**以åŠä¸€æ¬¡çœŸè·‘**:
  1209 +> å®ƒæ‰æ˜¯è¿™æ‰¹å·¥ä½œçœŸæ­£çš„验收,也是三æ¡ç¼ºé™·çš„出处。
  1210 +
  1211 +### 17.1 §16.8 / §15.5 的欠账(commit `8f4c1b6`)
  1212 +
  1213 +| æ¥æº | 项 | 结果 |
  1214 +|---|---|---|
  1215 +| §16.8-1 | `system/tasklog/` 改åä¿ç•™ | ✅ æ”¹æˆ `system/tasklog.bak-unify/`;回填脚本**两处都认**(先原ä½ç½®å†å¤‡ä»½ä½ç½®ï¼Œé¡ºåºä¸èƒ½å:万一有人从备份æ¢å¤å‡ºä¸€ä»½æ–°çš„ tasklogï¼Œé‚£ä»½æ‰æ˜¯è¦å›žå¡«çš„) |
  1216 +| §16.8-2 | agent æç¤ºè¯é‡Œçš„ç«¯å£ 3000 → 3010 | ✅ å®ˆå« `agent-docs-port.test.js`。第一版扫出 5 æ¡è¯¯æŠ¥ï¼Œå…¨æ˜¯æŸ agent 目录下 Python venv 里 playwright çš„ ThirdPartyNotices —— ç¬¬ä¸‰æ–¹æ–‡ä»¶ä¸æ˜¯æç¤ºè¯ï¼Œå·²è·³è¿‡ `venv/site-packages/workspace/conversations/train` |
  1217 +| §16.8-3 | `TaskTimeline.vue` 的措辞 | ✅ `conversationCount` 批 5 之åŽåªä¼šæ˜¯ 0/1,界é¢å´å†™ `Convs: N` —— 读的人会以为这æ¡ä»»åŠ¡åªæœ‰ä¸€æ¬¡å¯¹è¯ã€‚æ”¹æˆæœ‰/无的表达 |
  1218 +| §15.5-1 | 边界守å«è¯¯åˆ¤å¹¶è¡Œä¼šè¯çš„æ”¹åЍ | ✅ è§ 17.2 |
  1219 +| §15.5-2 | 机器级闸门 | ✅ `SessionPool.maxSessions()` + `SessionPoolFullError` + `_evictForRoom()`ï¼Œå®ˆå« `session-pool-max.test.js` |
  1220 +| §15.5-3 | 批 5 | ✅ §åå…­ |
  1221 +
  1222 +### 17.2 边界守å«ï¼šä»Žã€Œä¹±æ‰£å¸½å­ã€æ”¹æˆã€Œç•™è¯æ®ã€ä¸åˆ¤ç½šã€
  1223 +
  1224 +守å«çš„å‰ææ˜¯ã€Œçª—å£å†…新增的仓库改动 = 这个节点写的ã€ã€‚**多会è¯å…±ç”¨ worktree æ—¶è¿™ä¸ªå‰ææ˜¯å‡çš„** ——
  1225 +`git status` 的差集里没有「è°å†™çš„ã€è¿™ä¸€ç»´ã€‚实测已å‘生:批 3 çš„å¼€å‘æ”¹åŠ¨æŠŠä¸€æ¡ run 判æˆ
  1226 +`boundary_escape` å¡ä½ï¼ˆå°±æ˜¯ §17.4 é‚£æ¡ï¼‰ã€‚
  1227 +
  1228 +坿£€æµ‹çš„ä¿¡å·ï¼šèŠ‚ç‚¹**开跑那一刻**ä»“åº“å°±å·²ç»æœ‰æºç ç›®å½•的未æäº¤æ”¹åЍ → 有人正在这个 worktree 上开å‘
  1229 +→ 窗å£å†…新增的æºç æ”¹åŠ¨æ— æ³•å½’å±ž → **é™çº§ä¸ºåªè®°è¯æ®ã€ä¸åˆ¤ç½š**(与既有的 `unattributable` æ¡¶åŒä¸€è¯­ä¹‰ï¼‰ï¼Œ
  1230 +è€Œä¸æ˜¯å…³æŽ‰å®ˆå«ï¼šè¯æ®ç…§ç•™ï¼Œäººä¸€çœ¼çœ‹å¾—出「这次没判罚,因为当时仓库是è„çš„ã€ã€‚
  1231 +
  1232 +`BOUNDARY_GUARD=strict` 强制判罚(CI / 干净环境),`=record` 一律åªè®°ã€‚å®ˆå« 8 例,å«å…³é”®å¯¹ç…§ï¼š
  1233 +**ä»“åº“è„æ—¶ä¸åˆ¤ã€å¹²å‡€æ—¶åŒæ ·ä¸€å¤„越界ä»åˆ¤ fail** —— å®ˆå«æ²¡è¢«å‰Šå¼±ï¼Œåªæ˜¯ä¸å†ä¹±æ‰£å¸½å­ã€‚
  1234 +
  1235 +### 17.3 测试在往生产图库写(commit `20fed0a`)
  1236 +
  1237 +`agent-chat-tenant-isolation.test.js` æ¯è·‘一次往共享的 `data/graph.sqlite` è½ 2 æ¡ goal + 2 æ¡ task。
  1238 +库里 31 æ¡ goal 里 **22 æ¡æ˜¯å®ƒçš„æ®‹ç•™**,而测试一直全绿。
  1239 +
  1240 +根因是**批 5 的存储è¿ç§»ç•™ä¸‹çš„åŠæˆªæ¸…ç†**:`/task/dispatch` 的元数æ®ä»Ž `system/tasklog/*.json`
  1241 +æ¢è¿›äº† `tasks` 表(§åå…­ 第 3 步),而这个用例的 `afterAll` åªä¼šæ¸…那个目录 ——
  1242 +清ç†ä»£ç è¿˜åœ¨ã€æ¸…的东西已ç»ä¸åœ¨é‚£å„¿äº†ã€‚**这是这次è¿ç§»å”¯ä¸€æ²¡è¢«ä»»ä½•测试照到的一é¢ã€‚**
  1243 +
  1244 +> **它是本仓库第四次踩「测试污染共享库ã€ï¼Œä½†æ¢äº†ä¸ªæ–¹å‘è¿›æ¥ã€‚**
  1245 +> å‰ä¸‰æ¬¡ï¼ˆ`BENCHMARK_DB_PATH` / `USERS_DB_PATH` / `SKILLS_DIR`,记在 `test-isolation-env.test.js`
  1246 +> 文件头)都是「设了 env,生产代ç ä¸è¯»ã€ï¼Œé‚£æ¡å®ˆå«æŸ¥çš„æ­£æ˜¯è¿™ä¸ªå½¢æ€ã€‚
  1247 +> 这次是**一个字都没设** —— æ²¡æœ‰å¯æŸ¥çš„东西,守å«è‡ªç„¶æŸ¥ä¸å‡ºæ¥ã€‚
  1248 +> 陿€æ‰«æºç ä¹Ÿåˆ¤ä¸å‡ºã€Œè¿™ä¸ªæµ‹è¯•会ä¸ä¼šå¼€åº“ã€ï¼ˆè¦è·¨ require 链推导)。
  1249 +
  1250 +修法两层:用例自己开一次性库;`graph-db.getDb()` 加**è¿è¡ŒæœŸé—¸é—¨**(`VITEST` 为真且没设
  1251 +`GRAPH_DB_PATH` → 抛,报错里点å envã€ç‚¹æ˜Žã€Œè¦åœ¨ require 之å‰è®¾ã€ï¼Œå› ä¸º `DB_PATH` 是模å—级 const)。
  1252 +闸门放在 `getDb()` 䏿”¾æ¨¡å—顶层:åªä¸ºå–常é‡è€Œ require æ˜¯åˆæ³•用法,顶层抛会误伤。
  1253 +å®ˆå« `graph-db-prod-guard.test.js` 4 例(å«ã€Œæ²¡æœ‰ VITEST æ—¶ä¸ç”Ÿæ•ˆã€â€”— é˜²æ­¢æŠŠç”Ÿäº§ä¸€èµ·é”æ­»ï¼‰ã€‚
  1254 +
  1255 +å­˜é‡æ¸…ç†ï¼šåˆ æŽ‰ `created_by LIKE 'zz-tenant-%'` çš„ 22 goal + 22 task,其余 9 æ¡çœŸå®žæ•°æ®ä¸€æ¡æ²¡åŠ¨ã€‚
  1256 +
  1257 +### 17.4 é‚£æ¡å¡äº†ä¸¤å¤©çš„ run:真正å¡ä½å®ƒçš„䏿˜¯è¾¹ç•Œå®ˆå«ï¼Œæ˜¯å¢™é’Ÿé¢„ç®—
  1258 +
  1259 +`run_9168bd24f46c`(`e2e-demo` åš lemonai 官网)2026-08-18 16:19 判 `blocked` 之åŽå†æ²¡èƒ½èµ·æ¥ã€‚
  1260 +17.2 修完误判之åŽå®ƒ**ä»ç„¶è·‘ä¸åЍ** —— 第二é“é”在预算上:
  1261 +
  1262 +> 墙钟按 `now - spent.started_at` 算,而 `started_at` 是「第一次花钱的ç»å¯¹æ—¶åˆ»ã€ã€‚
  1263 +> 这与 `blocked` 的语义**直接对撞**:预算耗尽ã€èŠ‚ç‚¹åˆ¤ç½šéƒ½ä¼šæŠŠ run 打到 `blocked`,
  1264 +> 而 `blocked` 的定义就是**挂起等人工**。人隔夜æ¥å¤„ç½® → 等待那段被算æˆã€Œå·²ç”¨ã€â†’
  1265 +> 一起跑就报 `wallclock_ms` 耗尽 → å† `blocked` → å†ç­‰äººã€‚**过夜的 run 永远醒ä¸è¿‡æ¥ã€‚**
  1266 +
  1267 +而且报出æ¥çš„åŽŸå› å…·æœ‰è¯¯å¯¼æ€§ï¼šå†™ç€ `wallclock_ms`(跑太久),实际是**等人等太久**。
  1268 +è¿™æ¡ run åªèŠ±äº† 7/100 次调用ã€69,961/5,000,000 tokens —— **预算用掉ä¸åˆ° 2%**。
  1269 +
  1270 +改法:`spent` 改记 `active_ms`(累计活跃时长),`started_at` 退化æˆã€Œå½“å‰è¿™ä¸€æ®µçš„起点ã€ï¼Œ
  1271 +ä¸åœ¨ `running` 时为 null。起止结算挂在 `graph-run-sse.afterRunTransition` 这个**å•ä¸€æ¼æ–—**上。
  1272 +
  1273 +âš ï¸ é’©å­å¿…须放在那个 early return **之å‰**:进 `running` æ—¢ä¸æ˜¯æ”¶æ•›ã€ä¹Ÿä¸ç©ºå‘,两个æ¡ä»¶éƒ½ä¸æ»¡è¶³ï¼Œ
  1274 +放åŽé¢å°±å˜æˆã€Œåªç»“ç®—åœä¸‹æ¥ã€ä»Žä¸å¼€å§‹è®¡æ—¶ã€ï¼Œç—‡çŠ¶æ˜¯ `active_ms` æ’ 0ã€å¢™é’Ÿå½¢åŒè™šè®¾ï¼Œ**而且照样全绿**。
  1275 +
  1276 +**第一版的洞是真起æœåŠ¡ã€çœŸç‚¹é‡è¯•æ‰æ’žå‡ºæ¥çš„**(commit `9891c3b`):预算行挂在 root,
  1277 +我就åªè®¤ root 的转æ¢ï¼›è€Œäººå·¥é‡è¯•一个 work 层节点动的是**å­ run**(`blocked → running`),
  1278 +root 全程 `blocked` —— å­ run 跑整场ã€å¢™é’Ÿä¸€æ¬¡éƒ½æ²¡å¼€å§‹è®¡ã€‚**啿µ‹å½“时全绿,因为它们åªå–‚了 root。**
  1279 +
  1280 +å­˜é‡é‡é”šå¿…须放在**开库路径**里:钩å­åªåœ¨ã€Œè¿› / 出 runningã€æ—¶è§¦å‘,而å‡çº§é‚£ä¸€åˆ»æ­£åœåœ¨
  1281 +`running` çš„ run ä¸ä¼šå†è¿›ä¸€æ¬¡ `running`ã€‚âš ï¸ ç¬¬ä¸€ç‰ˆæŠŠè¿™æ®µè¿ç§»å†™è¿›äº† `graph-db.js` çš„ `migrate()`,
  1282 +而 `graph_runs` 是 `work-graph-db` 建的表ã€graph-db çš„è¿ç§»å—è·‘åœ¨å®ƒä¹‹å‰ â€”â€” 新库上直接
  1283 +`no such table: graph_runs`,`getDb()` èµ·ä¸æ¥ã€‚**å’Œ §16.2 那次「加索引写进建表å—ã€æ˜¯åŒä¸€ç±»é¡ºåºé—®é¢˜ï¼Œè¿™æ˜¯ç¬¬äºŒæ¬¡ã€‚**
  1284 +
  1285 +### 17.5 真跑结果(2026-08-20)
  1286 +
  1287 +é‡å¯æœåŠ¡ï¼ˆè¿ç§»åœ¨çœŸåº“上跑到)→ é‡è¯• `org-planner-sdd` → é€èŠ‚ç‚¹ `/next`:
  1288 +
  1289 +| 节点 | 结果 |
  1290 +|---|---|
  1291 +| `org-planner-sdd` | ✅ success(attempt 2) |
  1292 +| `org-planner-benchmark` | ✅ success |
  1293 +| `org-planner-validator` | ✅ success → æ•´å¼  work graph 五节点全 success,work run `completed` |
  1294 +| (父节点自动拉回) | ✅ `reviveParentFromChild` 把 root 从 `blocked` 拉回 `running` |
  1295 +| `org-coder` | → 起实现层å­å›¾ `run_91c4e38492dd` |
  1296 +| `org-coder-impl` | ✅ success |
  1297 +| `org-coder-validator` | 判 fail → **走回退边打回 `org-coder-impl`**(`loopCount: 1`),判è¯ï¼šé¡¹ç›®æ ¹ä¸‹åªæœ‰ä¸€ä»½è®¡åˆ’文档,没有任何交付文件 |
  1298 +
  1299 +**返工闭环在真跑里æˆç«‹äº†** —— 这是 P3 的核心机制第一次由真 agentï¼ˆä¸æ˜¯æ³¨å…¥çš„å‡ executor)走通。
  1300 +预算 13/100 次调用ã€114,847/5,000,000 tokens。
  1301 +
  1302 +### 17.6 这一轮的三æ¡ç»éªŒ
  1303 +
  1304 +1. **「修完 A å°±èƒ½è·‘ã€æ˜¯ä¸ªå‡è®¾ï¼Œä¸æ˜¯ç»“论。** 17.2 修完误判之åŽé‚£æ¡ run ä»ç„¶è·‘ä¸åŠ¨ï¼Œ
  1305 + 第二é“é”ï¼ˆå¢™é’Ÿï¼‰åªæœ‰çœŸåŽ»ç‚¹ä¸€æ¬¡æ‰éœ²å‡ºæ¥ã€‚**å¡ä½çš„东西å¯ä»¥æœ‰ä¸æ­¢ä¸€æŠŠé”。**
  1306 +2. **啿µ‹å–‚什么形状,就åªèƒ½å®ˆä½ä»€ä¹ˆå½¢çŠ¶ã€‚** 墙钟第一版的 8 æ¡ç”¨ä¾‹å…¨ç»¿ï¼Œ
  1307 + 因为它们全都直接喂 root run —— 而生产里触å‘计时的是**å­ run**。
  1308 + §16.7 è¯´ã€Œå­˜é‡æ•°æ® / çœŸå®žæŽ¥å£ / 肉眼å¯è§ä¸‰ç±»è¦å¦å¤–走一éã€ï¼Œè¿™é‡Œè¦è¡¥ç¬¬å››ç±»ï¼š
  1309 + **æ ‘å½¢ç»“æž„çš„æœºåˆ¶ï¼Œæµ‹è¯•å¿…é¡»å–‚éžæ ¹èŠ‚ç‚¹**。
  1310 +3. **åŒä¸€ç±»é¡ºåºé—®é¢˜ç¬¬äºŒæ¬¡äº†**(è¿ç§»å†™é”™æ¨¡å— vs §16.2 加索引写进建表å—)。
  1311 + 判æ®å¯ä»¥å›ºåŒ–æˆä¸€å¥è¯ï¼š**凡是写è¿ç§»ï¼Œå…ˆé—®ã€Œè¿™å¼ è¡¨æ˜¯è°å»ºçš„ã€ï¼Œç­”案就是这段è¿ç§»è¯¥å¾…的文件。**
... ...
docs/todo/system-design/27-graph-agent-architecture.md
... ... @@ -2,7 +2,7 @@
2 2  
3 3 > **版本**: v0.3(P0/P1 已实现;Org Graph 建模在 v0.3 修正为 company 级 workflow)
4 4 > **日期**: 2026-08-15
5   -> **状态**(2026-08-18 校准,此前这一行落后两个阶段): P0 ✅ 已实现(`graph-db.js` + `graph-seed-service.js`,见第七节);P1 ✅ 已实现(commit `226489d`,`graph-service.js`);**P2 ✅ 已实现**(设计已归档 [27-P2](../../done/system-design/27-p2-org-graph.md));**P3 主体 ✅ 已实现**(`c3abf4a` 起七轮,见 [27-P3/P4](./27-p3-p4-work-graph-console.md) §十 实现记录 + 第六轮终验回填;收尾见 [27-P3B](./27-p3b-real-run-runway.md));**P4 📝 设计中/未实现**([27-P4](./27-p4-parallel-and-artifacts.md) 自述 v0.1 设计阶段)
  5 +> **状态**(2026-08-20 校准): P0 ✅ 已实现(`graph-db.js` + `graph-seed-service.js`,见第七节);P1 ✅ 已实现(commit `226489d`,`graph-service.js`);**P2 ✅ 已实现**(设计已归档 [27-P2](../../done/system-design/27-p2-org-graph.md));**P3 主体 ✅ 已实现**(`c3abf4a` 起七轮,见 [27-P3/P4](./27-p3-p4-work-graph-console.md) §十 实现记录);**P3 收尾 ✅ 已完成并归档**([27-P3C](../../done/system-design/27-p3c-goal-task-model.md) 五批 + §十七 清尾,2026-08-20 真跑走通返工闭环);**P3B 真跑跑道 📝 仍在推进**([27-P3B](./27-p3b-real-run-runway.md),验收 7 真跑不成立、2/4/8/9 未验);**P4 📝 设计中/未实现**([27-P4](./27-p4-parallel-and-artifacts.md) 自述 v0.1 设计阶段)
6 6 >
7 7 > ⚠️ 这一行是别人判断「哪些文档能从 `docs/todo/` 搬去 `docs/done/`」的依据 —— 它过期会连累后面每一次迁移判断,改阶段状态时请顺手更新它。
8 8 > **命名**: 新增 agent id / 表名 / 字段名前先读 [27-NAMING 命名规范](./27-naming-conventions.md)
... ...
docs/todo/system-design/27-p3b-real-run-runway.md
... ... @@ -5,6 +5,11 @@
5 5 > **日期**: 2026-08-16
6 6 > **起因**: [27-REQ](./27-requirement.md) R-18(招聘归 `workgraph-planning`;停用 mock 改真 CLI)
7 7 > **前置**: P3 主体已实现并提交(`c3abf4a` 起七轮),测试 719/719 全绿
  8 +> **状态**(2026-08-20 校准): 📝 **仍在推进**。第一批验收 1/3 已验、2 的后半与 4 未在干净环境重验;
  9 +> 第二批验收 7 ⛔ 真跑不成立(§六bis 缺陷③ `readme-writer` 混进 org graph,**未修**);
  10 +> 第三批 8/9 真 CLI 未验。
  11 +> §六bis 缺陷② 的**根因**(边界守卫误判并行会话的改动)已于 2026-08-20 修掉,
  12 +> 见 [27-P3C §17.2](../../done/system-design/27-p3c-goal-task-model.md) —— 但**根因修了不等于验收点验了**,那几条仍要重跑一遍。
8 13  
9 14 ---
10 15  
... ... @@ -760,8 +765,8 @@ agent 读的是 `agent.md`,那一侧不改,模型就会继续以为「前三
760 765 | # | 标准 | 状态 |
761 766 |---|---|---|
762 767 | 1 | 服务启动后 `system_agents` 与 `system/templates/` 一致,无悬空 `company_hired` 行;新加一个模板目录、重启服务,它自动出现在表里 | ✅ **已验**(生产库实查 + hermetic 用例)。一处**已知且合理**的偏差:`system/agents/` 与 `system/templates/` 同名的 6 个 id(`agent-creator` / `org-innovator` / `innovator-{digest,evolver,hunt}` / `evolver-youtube-crawler`)按设计 skip,仍是 `global_agent`。图用到的本体都不在这 6 个里 |
763   -| 2 | 起一个真 CLI 的 run,节点产出全部落在 `data/companies/{cid}/projects/{pid}/` 内;`git status` 在宿主仓库无任何新增/修改 | 🟡 **前半已验、后半被并行 agent 打破**(2026-08-17,§六bis):`workgraph-planning` 的产物真的落在 `data/companies/p3bfin/projects/p-24vxi8/workspace/` 内,`project-root.json` 四环闭合;宿主仓库出现的两处改动经查是**并行的 Master agent** 写的(缺陷②),已复原。被判罚的那个 work 节点自己一个字节都没往仓库写 |
764   -| 3 | 故意让节点往产物目录外写,被守卫拒绝并在 timeline 留痕 | ✅ **真 CLI 已验**(2026-08-17,§六bis):git 扫描确实扫到了宿主仓库里的那处改动,`node.boundary` 事件带完整 `entries`,结果被降级判 fail 且 `fail_reason='boundary_escape'` 落库。**但同一次也验出了误判**:那处改动是并行的 Master agent 写的,不是被判罚的节点写的(W3「拦不住」第 5 条,见 §六bis 缺陷②)。判罚逻辑侧另有 W12 补完那一轮加的三条分支用例 |
  768 +| 2 | 起一个真 CLI 的 run,节点产出全部落在 `data/companies/{cid}/projects/{pid}/` 内;`git status` 在宿主仓库无任何新增/修改 | 🟡 **前半已验、后半被并行 agent 打破**(2026-08-17,§六bis)。**2026-08-20 补记**:后半那个「被并行 agent 打破」本身已经不再导致误判 —— 守卫改成「节点开跑那一刻仓库就脏 → 只记证据、不判罚」,见 [27-P3C §17.2](../../done/system-design/27-p3c-goal-task-model.md)。**但这条验收标准本身仍未在干净环境下重验**。当时的原始记录:`workgraph-planning` 的产物真的落在 `data/companies/p3bfin/projects/p-24vxi8/workspace/` 内,`project-root.json` 四环闭合;宿主仓库出现的两处改动经查是**并行的 Master agent** 写的(缺陷②),已复原。被判罚的那个 work 节点自己一个字节都没往仓库写 |
  769 +| 3 | 故意让节点往产物目录外写,被守卫拒绝并在 timeline 留痕 | ✅ **真 CLI 已验**(2026-08-17,§六bis):git 扫描确实扫到了宿主仓库里的那处改动,`node.boundary` 事件带完整 `entries`,结果被降级判 fail 且 `fail_reason='boundary_escape'` 落库。**但同一次也验出了误判**:那处改动是并行的 Master agent 写的,不是被判罚的节点写的(W3「拦不住」第 5 条,见 §六bis 缺陷②)。判罚逻辑侧另有 W12 补完那一轮加的三条分支用例。**2026-08-20 补记**:误判那一半已修([27-P3C §17.2](../../done/system-design/27-p3c-goal-task-model.md),`BOUNDARY_GUARD=strict|record` 两个开关 + 8 例守卫,含「仓库干净时同样一处越界仍判 fail」的对照) |
765 770 | 4 | 造一份非法契约跑 `benchmark-validator`:判决为失败且引擎按失败处理(**不是** success) | 🟡 **静态成立,未真跑**。模板已改写 `verdict: "attributed"`,而 `FAILING_VERDICTS={attributed,inconclusive}` → `readNodeProduct` 置 `failingVerdict=true` → `callAgentNode` 判 `fail`(`graph-engine.js:473/385`),链路读通;防线测试三次反例变异全部变红 |
766 771  
767 772 > 2 与 3 都要真 CLI 才验得了,而真 CLI 现在会先死在 W5/W6 上。**这两条应挪到第二批之后一起验。**
... ...
docs/todo/system-design/27-requirement.md
... ... @@ -563,7 +563,7 @@ git diff,最后 W13 只能把计数挪去另一个被 ignore 的文件。`file
563 563  
564 564 统一还顺带修好两件事:30 分钟派单去重从「`readdirSync` 整个 tasklog 目录 + 逐个 JSON.parse」变成一条 SQL;两套同前缀不同源的 `T-` id 合一。
565 565  
566   -**落点**:[27-P3C goal / task 两级模型](./27-p3c-goal-task-model.md)(本条派生出的工作项文档)。
  566 +**落点**:[27-P3C goal / task 两级模型](../../done/system-design/27-p3c-goal-task-model.md)(本条派生出的工作项文档)。
567 567  
568 568 ---
569 569  
... ...
docs/todo/system-design/28-followups.md
... ... @@ -63,17 +63,26 @@
63 63 只有设计,没有实现。任务目录 `system/agents/{aid}/{cid}/{taskId}/` 在源码树里无限增长。
64 64 **实现前必须先读主文档 §5.6b** —— 公司态是 dream 的原料,不是缓存,只能清任务态。
65 65  
66   -### 3.3 `agent-chat.js:1209` 是心跳落点 bug 的第二个入口
  66 +### 3.3 ~~`agent-chat.js` 是心跳落点 bug 的第二个入口~~ ✅ 已修(2026-08-20,`edeff2e`)
67 67 `PUT /api/agent/:agentId/heartbeat`(前端 Agent 详情页走的就是它)用
68 68 `locator.bodyDir(parseAddress(id).agentId)` 把公司段丢掉,然后整份重写本体 `config.json`。
  69 +后果是**静默无效**:公司态文件一旦存在,读侧优先取公司态,界面收到 `{success:true}`
  70 +而实际在跑的还是旧值;`GET /info` 同理报的是本体缺省。症状是「界面写 30 分钟、
  71 +调度器按 15 分钟在跑」,两边都不报错。
69 72  
70   -心跳落点已在 `company.js` 侧修好(写 `system/agents/{aid}/{cid}/heartbeat.json`),
71   -**但这个入口没改**,且因此多了一个新问题:公司态文件一旦存在,读侧优先取公司态,
72   -于是这个端点的写入对该 (agent, 公司) 变成**静默无效**。
  73 +读写都已改走 `heartbeat-service` 的 `readHeartbeatConfig` / `writeHeartbeatConfig`,
  74 +与心跳挂载读的是同一个答案;入参校验归服务(`intervalMinutes` 直接进 `setInterval`,
  75 +NaN / 0 / 负数会让定时器退化成每 tick 触发一次,而每次 tick 真起一轮 LLM),端点翻成 400。
73 76  
74   -修法(一行级):那段读改写换成
75   -`require('../services/heartbeat-service').writeHeartbeatConfig(req.params.agentId, req.body)`,
76   -`GET :1203` 的 `heartbeat: config?.heartbeat` 同理换成 `readHeartbeatConfig`。
  77 +**顺带修的一处**:404 闸门原来也用 `getBodyDir(id)`。`cid:role` 里冒号后面是**角色名**,
  78 +未必等于本体 id(`company_agents` 的映射)—— 拿角色名当本体 id 判存在性,凡是角色名 ≠ 本体 id 的
  79 +都会被判成「agent 不存在」,而写侧其实找得到。**判 404 和写入必须问同一个问题。**
  80 +
  81 +守卫:`heartbeat-company-scoped.test.js` 补 3 例(反向验过,退回旧写法立刻红)。
  82 +
  83 +> ⚠️ **一处没修,别当成修过了**:`GET /info` 的 404 闸门仍是 `getBodyDir(id)`,
  84 +> 对 `cid:role` 会直接 404。那是 `/info` 整体寻址的既有缺口(它还要按同一个目录读
  85 +> `identity` / `agent.md` / `cron`),不在心跳这一条的范围内。测试里用裸 agent id 绕开。
77 86  
78 87 ---
79 88  
... ... @@ -95,12 +104,16 @@
95 104  
96 105 ## 五、已经立起来的守卫(别重复造,也别删)
97 106  
98   -这几条是沉淀下来的不变式测试(前三条出自 agent 目录重构那一轮,第四条出自 27-P3C 批 1,第五、六条出自 CLI 进程泄漏那一轮)。
99   -**前四条**守的都是「同一个事实只能有一处持有者」,而且**六条都带「样本非空」前置断言** —— 少了那一条,扫描路径一写错就会以
100   -「零违例」的形式全绿,一条永远通过的不变式测试和没有这条测试是一回事。
  107 +这几条是沉淀下来的不变式测试(前三条出自 agent 目录重构那一轮,第四条出自 27-P3C 批 1,第五、六条出自 CLI 进程泄漏那一轮,
  108 +第七、八条出自 27-P3C 收尾之后那一轮)。
  109 +**第 1-4 条 + 第 8 条**守的都是「同一个事实只能有一处持有者」,而且**凡是靠扫描的都带「样本非空」前置断言** ——
  110 +少了那一条,扫描路径一写错就会以「零违例」的形式全绿,一条永远通过的不变式测试和没有这条测试是一回事。
101 111  
102   -后两条形状不同:第五条守的是**资源生命周期**(每一条创建路径都要有对应的回收路径),判据不靠扫源码,而是把回收行为当黑盒去探;
103   -第六条守的是**指路牌的有效性**(文档 / 清单里指向的东西必须真实存在)。列在一起是因为「别重复造,也别删」这条规矩对它们同样适用。
  112 +另外三条形状不同,判据都不靠扫源码:
  113 +第 5 条守的是**资源生命周期**(每一条创建路径都要有对应的回收路径),把回收行为当黑盒去探;
  114 +第 6 条守的是**指路牌的有效性**(文档 / 清单里指向的东西必须真实存在);
  115 +第 7 条守的是**运行期闸门本身**(起真子进程去撞,看撞不撞得动 —— 静态扫源码判不出「这个测试会不会开库」)。
  116 +列在一起是因为「别重复造,也别删」这条规矩对它们同样适用。
104 117  
105 118 | 测试 | 守什么 | 违例时 |
106 119 |------|--------|--------|
... ... @@ -110,6 +123,8 @@
110 123 | `runs-root-single-holder.test.js` | 凡是把 `process.env.GRAPH_RUNS_DIR` 绑到标识符上的模块,那个标识符必须在**代码里**(不是注释里)真正被用到 | 精确点名到文件行号 |
111 124 | `agent-chat-session-reclaim.test.js` | agent-chat 的 `sessions` 池:一次性 convId 的调用跑完必须回收,可复用的(pipeline / 人类对话)必须留下并受 TTL 兜底;顺带锁 `CALL_KINDS` 的标注 | 探针 `/chat/:convId/stop` 报告会话还在 |
112 125 | `no-dead-path-references.test.js` | CLAUDE.md 的仓库路径与 npm run、package.json 的 scripts/bin/main、docs/README.md 的相对链接,四类引用都必须指向真实存在的东西 | 列出死引用的出处与目标 |
  126 +| `graph-db-prod-guard.test.js` | 测试进程不许打开共享生产库 `data/graph.sqlite`(判据在 `graph-db.getDb()` 的运行期闸门上,这条测试是对闸门本身的黑盒验证) | 子进程撞库时抛,报错点名 env 与「要在 require 之前设」 |
  127 +| `heartbeat-company-scoped.test.js` | 心跳设置是公司级状态,两个入口(`/api/company/...` 与 `/api/agent/...`)都不许落到共享本体上,且写完要能从读侧读回 | 本体 `config.json` 的 mtime / 内容变了,或读侧读回的不是刚写的值 |
113 128  
114 129 > 第四条的来历值得记:`goal-contract.js` 里曾有一行 `const RUNS_ROOT = process.env.GRAPH_RUNS_DIR || null`,
115 130 > 注释白纸黑字写着「与 graph-engine.RUNS_ROOT 是同一个变量(测试隔离在用)」,**全文件却零引用**。
... ... @@ -137,6 +152,17 @@
137 152 > 上下文里的相对片段(`_base/`、`todo/future/`)、glob、`<repo>/…` 示意写法一律不判。
138 153 > 宽一档就会把这些一起判红,防线于是被人整条注释掉。
139 154  
  155 +> 第七条的来历是**第四次踩「测试污染共享库」**,而且换了个方向进来。前三次
  156 +> (`BENCHMARK_DB_PATH` / `USERS_DB_PATH` / `SKILLS_DIR`)都是「设了 env、生产代码不读」——
  157 +> `test-isolation-env.test.js` 查的正是这个形态。这次那个用例**一个字都没设**,
  158 +> 于是那条守卫没有可查的东西,`/task/dispatch` 每跑一次往生产库落 2 条 goal + 2 条 task,
  159 +> 攒到 22 条才被人翻库发现。
  160 +>
  161 +> 静态扫源码判不出「这个测试会不会开库」(要跨 require 链推导),所以这一条改成
  162 +> **运行期闸门 + 对闸门本身的黑盒验证**:起一个真子进程去撞,看撞不撞得动。
  163 +> 判据里特意留了「没有 VITEST 时不生效」那一例 —— 少了它,闸门写成「永远不许开
  164 +> `data/graph.sqlite`」也会全绿,而那会把生产一起锁死。
  165 +
140 166 **改动它们之前先想清楚**:这几条的价值全在于「红了才有用」。
141 167 放宽判据、加例外、或者把断言改成永远成立的形式,等于把守卫拆掉 ——
142 168 本仓库有过「隔离是表演」的测试污染前科。
... ...