Commit 411af4e569684b8ac773b1835772b31ec4fe1159
1 parent
ab57a0af
docs(27-P4): 照代码逐条核对任务表 —— 阶段 C 与 T1 早就做完了
按任务表逐条 grep 代码,发现这份文档落后于实现相当多:
· **T1 已完成**(P3C §15.5-2):SessionPool.maxSessions + scope key,两条守卫盯着。
· **T3 后半已完成**(P3C 批 4):单 active root run 的唯一索引已 DROP,
换成四步事务内准入(BEGIN IMMEDIATE → 重读 → 计数 → 条件更新),8 进程实测零超发。
· **阶段 C 整个已完成,但形态换了**:产物索引做成了 graph_files **表**而不是 files.json。
表比文件多拿到两样:部分唯一索引保证「同一路径只有一个当前版本」,
superseded_by 让历史版本可共存。守卫 graph-files-index.test.js 七条。
· 产物也早就按 run/node 分目录了(runs/{rootRunId}/nodes/{nodeRunId}/),
§3.6 里「按 agent 分目录、同一 agent 不同任务混在一起」那条已不成立。
§3.6 那两个 ❌ 改成校准块 —— 保留原文(它记录了当时的判断依据),
但当前状态以校准块为准。
**真正剩下的只有阶段 B**:max_concurrency 列、advanceBatch、三层额度取小、
并行执行与部分失败降级,以及 T10 的控制台可视化。
> 这是「文档落后于代码」的又一例。判断一个阶段还剩多少工作量时,
> **先照着任务表逐条 grep 代码**,别照文档估 —— 照文档估会把已完成的三项当成待办。
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Showing
1 changed file
with
29 additions
and
8 deletions
docs/todo/system-design/27-p4-parallel-and-artifacts.md
| ... | ... | @@ -115,10 +115,25 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_graph_runs_one_active_root |
| 115 | 115 | |
| 116 | 116 | ### 3.6 产物目录现状 |
| 117 | 117 | |
| 118 | +> ⚠️ **本节写于 2026-08-16,下面两个 ❌ 已经不成立了**(2026-08-20 校准)。 | |
| 119 | +> 留着原文是因为它记录了当时的判断依据;**当前状态看这一段的校准块**。 | |
| 120 | + | |
| 118 | 121 | - ✅ `goal-contract.js` 已实现验收契约的跨节点传递(R-15.6 验收先行)。 |
| 119 | -- ✅ `graph-engine.js:283/407/444` 有节点级产物路径:`data/companies/{cid}/agents/{systemAgentId}/.../attempt-{n}.json`。 | |
| 120 | -- ❌ **没有 `files.json`**(全仓库无此文件、代码无引用)。 | |
| 121 | -- ❌ 产物按 **agent** 分目录,不是按 **task** 分目录——同一 agent 在不同任务下的产出混在一起。 | |
| 122 | +- ✅ `graph-engine.js` 有节点级产物路径。 | |
| 123 | +- ~~❌ 没有 `files.json`~~ → **✅ 阶段 C 已落地,但形态换了**:产物索引做成了 | |
| 124 | + `graph_files` **表**(`recordFile` / `findFiles` / `rebuildFilesFromNodes`), | |
| 125 | + 不是 `files.json` 文件。表比文件多拿到两样东西:部分唯一索引保证「同一路径只有一个当前版本」, | |
| 126 | + 以及 `superseded_by` 让历史版本可共存。守卫 `graph-files-index.test.js` 七条, | |
| 127 | + 含「删掉索引后能从节点行重建」和「两个 task 的同名产物不互相覆盖」。 | |
| 128 | +- ~~❌ 产物按 agent 分目录~~ → **✅ 已按 run/node 分目录**: | |
| 129 | + `data/companies/{cid}/runs/{rootRunId}/nodes/{nodeRunId}/`, | |
| 130 | + 跨 org node 的共享产物在 `runs/{rootRunId}/artifacts/`。 | |
| 131 | + 同一 agent 在不同任务下的产出因此天然不混。 | |
| 132 | + | |
| 133 | +> **2026-08-20 顺带修掉一个存量库缺陷**:生产库里还留着产物索引加版本之前的 | |
| 134 | +> **无条件**唯一索引 `idx_graph_files_path`,导致重试时同路径第二次写必撞、 | |
| 135 | +> 被降级成一条 timeline —— **产物索引在任何有重试的 run 上都不全**,而且不报错。 | |
| 136 | +> 详见 [27-P3B §六ter](./27-p3b-real-run-runway.md)。 | |
| 122 | 137 | |
| 123 | 138 | --- |
| 124 | 139 | |
| ... | ... | @@ -485,14 +500,14 @@ R-19 之后这两件事有实体(`graph_edge_contracts` × `graph_files`), |
| 485 | 500 | |
| 486 | 501 | | # | 任务 | 文件 | 依赖 | |
| 487 | 502 | |---|---|---|---| |
| 488 | -| **T1** | `SessionPool` 加 `maxSessions` 上限 + 调用方传 `scope`(`gr:{nodeRunId}`) | `server/src/core/session-pool.js`、`server/src/core/agent-manager.js` | 无 | | |
| 503 | +| ~~**T1**~~ ✅ | `SessionPool` 加 `maxSessions` 上限 + 调用方传 `scope` —— **已完成**(27-P3C §15.5-2,守卫 `session-pool-max.test.js` / `session-pool-scope-key.test.js`) | `server/src/core/session-pool.js` | 无 | | |
| 489 | 504 | | **T2** | DevLoop 规格:§12 第一条不变量放宽为 `(pid, agent, scope)`。**改 HTML 后必须跑 `npm run spec:extract`** | `docs/prd/newfunction/*.html` | 无 | |
| 490 | -| **T3** | `graph_runs` 加 `max_concurrency` 列;DROP `idx_graph_runs_one_active_root`,改为事务内计数检查 | `server/services/work-graph-db.js` | 无 | | |
| 505 | +| **T3** | `graph_runs` 加 `max_concurrency` 列(**未做**);~~DROP `idx_graph_runs_one_active_root`,改为事务内计数检查~~ ✅ **后半已完成**(27-P3C 批 4:四步准入 `BEGIN IMMEDIATE` → 事务内重读 → 事务内计数 → 条件更新,8 进程实测零超发) | `server/services/work-graph-db.js` | 无 | | |
| 491 | 506 | | **T4** | `advanceBatch(runId, {maxConcurrency})`:事务内批量拾取并置 running;`advanceOne` 降级为薄封装 | `server/services/graph-engine.js` | T3 | |
| 492 | 507 | | **T5** | 并发额度计算(三层取小)+ 额度为 0 时的等待语义 | `server/services/graph-engine.js` | T1, T3, T4 | |
| 493 | 508 | | **T6** | 并行执行 + 错误降级(照搬 `orchestrator.executeWithDependencies` 的 `Promise.allSettled` 策略,单分支失败不终结整批) | `server/services/graph-engine.js` | T4 | |
| 494 | -| **T7** | `files.json` 服务:追加、查询、rebuild | `server/services/company-files-index.js`(新增) | 无,可并行 | | |
| 495 | -| **T8** | 产物落盘路径改为 `tasks/{taskId}/`;节点产出后自动写 `files.json` | `server/services/graph-engine.js`、`goal-contract.js` | T7 | | |
| 509 | +| ~~**T7**~~ ✅ | 产物索引:追加、查询、rebuild —— **已完成,形态换成 `graph_files` 表**(见 §3.6 校准块),不是 `files.json` | `server/services/work-graph-db.js` | — | | |
| 510 | +| ~~**T8**~~ ✅ | 产物按 run/node 分目录 + 节点产出后自动进索引 —— **已完成**(`runs/{rootRunId}/nodes/{nodeRunId}/`) | `server/services/graph-engine.js` | — | | |
| 496 | 511 | | **T9** | node agent 的 prompt 注入 `files.json` 检索说明 | `system/templates/base/agent.md` 等 | T7 | |
| 497 | 512 | | **T10** | 控制台:fan-in 等待态可视化(「在等哪几个节点」)+ 并行运行中的多节点高亮 | `web/src/views/GraphConsole.vue` | T6 | |
| 498 | 513 | | **T11** | 测试:批量拾取的并发幂等(两个 `advanceBatch` 不拾取重叠集合)、部分失败的 fan-in 停等、额度上限生效、`files.json` rebuild 一致性 | `server/tests/unit/` | T4-T8 | |
| ... | ... | @@ -501,12 +516,18 @@ R-19 之后这两件事有实体(`graph_edge_contracts` × `graph_files`), |
| 501 | 516 | |
| 502 | 517 | | 阶段 | 含 | 交付 | 可否独立上线 | |
| 503 | 518 | |---|---|---|---| |
| 504 | -| **A · 隔离** | T1, T2 | 同一 agent 可安全并发调用 | ✅ 可以,此时引擎仍串行,但隔离能力已具备 | | |
| 519 | +| **A · 隔离** | ~~T1~~ ✅, T2 | 同一 agent 可安全并发调用 —— **T1 已完成**,只剩 T2(DevLoop 规格放宽) | 基本具备 | | |
| 505 | 520 | | **B · 并行** | T3-T6, T10 | fan-out 真正并发;解除单 root run 约束 | ✅ 依赖 A | |
| 506 | 521 | | **C · 产物索引** | T7-T9 | `files.json` + 按 task 分目录 | ✅ **完全独立于 A/B**,可最先做 | |
| 507 | 522 | |
| 508 | 523 | **阶段 C 与 A/B 无依赖**,如果想先看到效果,可以先做 C(它是用户明确要求过的第 3 项)。 |
| 509 | 524 | |
| 525 | +> **2026-08-20 校准**:C 已经完成,A 的 T1 也完成了(都是在 P3C 那几批里顺手落的, | |
| 526 | +> 当时没回来更新这份文档)。**真正剩下的是 B**:`max_concurrency` 列、`advanceBatch`、 | |
| 527 | +> 三层额度取小、并行执行与部分失败降级,以及 T10 的控制台可视化。 | |
| 528 | +> 这一段是「文档落后于代码」的又一例 —— 判断 P4 还剩多少工作量时, | |
| 529 | +> **先照着任务表逐条 grep 一遍代码**,别照文档估。 | |
| 530 | + | |
| 510 | 531 | --- |
| 511 | 532 | |
| 512 | 533 | ## 六、验收标准 | ... | ... |