# 实现现状 vs 目标/BRD/PRD/SDD 差距分析 **日期**: 2026-08-03 **性质**: 现状快照,回应用户 "现在整个系统的实现和我们的文档的 goal 和 brd prd sdd 还有哪些差距"。基于对 `git log`、 `docs/development-plan.md`(含各 Unit 事后补记)、`docs/build-report.md`、`docs/sdd/06-验收与测试锚点.md` 和实际 代码(`src/`、`supervisor/`)的交叉核对得出,不是重新跑一遍验收。 **结论先说**: 45 个 Unit(U-001~U-043 + U-004.5/U-024.5)全部有对应实现和提交,`docs/build-report.md` 的 "全部完成"判断在"每个 Unit 都有代码落地"这个意义上是对的。但"全部完成"不等于"和文档设定的目标完全对齐"—— 差距集中在 PH5 的"自动"两个字还没完全兑现、系统还不是真正自驱动的、以及若干 SDD 契约的已知简化。逐条见下。 **如何维护本文档**: 这是一次性快照,会随实现推进而过时。发现某条已经补上或又出现新缺口时,直接编辑对应条目 (改状态、补日期),不要另开一份新文件——避免重蹈 `development-plan.md`/`unit_matrix.json`/`build-report.md` 互相之间已经出现的"哪份是最新的"混乱(见第 4 节)。 --- ## 1. 目标层面:PH5 的"自动"闭环从未真正走完 - REQ-15(Deploy Supervisor 蓝绿部署 + 自动回滚)的 happy path 只验证到**真实 cutover**,从没有一次交互式压测 真正等到 `finalized`——生产参数是 24 小时或 10 个真实任务的监控窗口,本来就不该在一次交互会话里等到。 - 更关键:**Deploy Supervisor 真正"自动"的那部分——持续轮询"有没有新的 self-target 合并等待部署"——从未 实现**。`supervisor/deploy_supervisor.py`(U-036)只管进程生命周期(start/stop/status/PID),`poll_fn` 是留 给未来的钩子;`supervisor/self_hosting_e2e.py`(U-042)只是验收脚本的一次性编排(人工触发一条 Goal→...→ cutover 的直线调用),不是常驻发现循环。PH5 的目标"自主修改自己代码后自动安全部署",目前是"能做到"而不是 "会自己做"。 - 回滚路径 B(监控期异常检测触发)只在 mock 测试里验证过分支逻辑,从未在真实生产数据下真正触发过。 - **(2026-08-03 自举可行性分析中新发现)部署缺互斥锁**:`supervisor/deploy_stage.stage_deployment()` 只检查 `_last_finalized_deployment()`(上一次成功落地的部署是什么),**不检查当前是否已有一个进行中 (`staged`/`candidate_starting`/…未到终态)的部署**。如果用调度器并发派发多个 self-target 任务、且多个都 想 cutover,会互相踩——这不是原来清单里的条目,是分析"能否用调度器批量跑 gap 修复"时才暴露出来的新缺口, 建议在真正启用并发自举之前先补上。 ## 2. "熄灯"叙事本身:没有常驻调度入口 `src/scheduler.py`(U-032)从未被 `backend_server.py` 或任何生产入口调用——`backend_server.py` 里只有一句注 释提到"调度器以后会长在这里"(grep 确认,无实际调用)。系统目前不存在一个真正常驻、自动扫描 `queued` 任务 并派发的进程;每一次"跑起来"都是脚本/测试手动调用 `run_scheduler_once`/`run_goal_to_completion`。这和"Level 5 自主研发系统"的叙事有实质差距——机制都齐了,但缺"自己跑起来"这一层。 ## 3. SDD 契约与实现之间已知的简化/偏差 - **Skill 内容从未真正迁移**:`.claude/agents/*.md` 的 `skills:` frontmatter 只是引用名字(如 `code-task-development`),仓库里没有 `skills//` 真实文件,测试靠 seed 占位内容绕过—— `src/skill_update.py` 自己的注释也承认这点。 - **Coder 阶段没有真正的多模块 Work Graph 规划**:`c_work_graph_plan` 目前只服务 Planner 的固定四节点线性图 (brd→prd→sdd→benchmark);Coder 永远走一个合成的单节点 manifest,"规划一个真正的多文件代码变更图"这个能 力从未被要求也没实现。 - **✅ 已修复(2026-08-03)普通 target project 从未部署过 Agent 定义**: `agent_profile.deploy_agent_definitions()` 存在,但没有任何生产代码路径调用它——`project_scaffold.create_project()` 建 project 时不会调,`org_node_trigger.py` 自己的注释也如实写着"this function does not deploy it"。self-target 场景"恰好"没事,是因为 `.claude/agents/*.md` 本来就是 graphlemon 自己仓库里已提交的文件;但任何**新建的普通 target project**,第一次触发 Planner 时 `claude --agent planner` 会因为 cwd 下找不到 agent 定义而非零退出, 抛出 `OrgNodeTriggerError`——这个异常不在 `scheduler._ROUTABLE_EXCEPTIONS` 里,被兜底成笼统的 `blocked_reason='execution_error'`,真实报错内容不会被持久化,控制台上完全看不出原因。真实复现:项目 `LemonGraphFront`(`target_folder_path=.../graphlemon/frontend/`)的任务从 `queued` 直接跳到 `blocked_pending_human`,零 artifact 产出。 **修复**:`project_scaffold.create_project()` 现在会在 `.graphlemon/` 初始化提交时一并调用 `agent_profile.deploy_agent_definitions()` 并 commit(同一个 commit,没有多引入一次提交,也顺带解决了下面 worktree 隔离那条 gap);`scheduler._block_task()`/`task_execution._mark_blocked()` 新增 `detail` 参数,把真实 异常信息写进 `execution_event.payload`,不再是不可诊断的裸字符串(`blocked_reason` 本身值不变, `budget_guardrail` 等地方靠精确匹配它的值,没有改)。新增/扩展了 3 处回归测试 (`test_project_scaffold.py`/`test_scheduler.py`/`test_task_execution.py`),`src/` 全量 498 个测试 + `supervisor/` 123 个测试全绿。**真实验证**:给 `LemonGraphFront` 项目手动补部署+提交 agent 定义后,`task_id=7400d876-…` 走完 了完整闭环——BRD/PRD/SDD/Benchmark/code_diff/test_report 六个 artifact 全部 `validation_status=passed`,中途 Validator 第一轮 FAIL 还真实触发了一次 Org-level Loop 的 `full_replan` 路由、重新规划后第二轮通过,最终 `task.status=done`。是通过这次交互式会话直接改代码修的,**不是**走 graphlemon 自己的 Planner→Coder→Validator 自举出来的——对应第 6 节任务清单顺序 1(原描述是"补 commit",实际根因和修复范围比原描述更大,一并记在这里)。 - **普通 target project 的并行 worktree 隔离没被真正踩过**:`needs_worktree` 目前只有 self-target 场景被 `work_graph_orchestrate.py` 强制打开;给普通项目手动开启时,原先 `agent_profile.deploy_agent_definitions()` 只 写 `.claude/agents/*.md` 文件、不 commit,而 `git worktree add` 只认已提交内容——这条路径理论上会失败。 **随上面那条一起修复**:`create_project()` 现在会把部署的 agent 定义提交,新建项目从一开始就有已提交的 `.claude/agents/*.md`,这个阻塞点已解除;但"手动对一个已存在、之前没有 agent 定义的项目开启 worktree"这种 场景仍未专门测试过,不算完全清零。 - `v_artifact_browser`(U-028)有意不做 Markdown 渲染/代码高亮(02-V 原型期望有),因为要避免引入第一个前端 第三方库,判断为有意简化而非漏做。 ## 4. 文档本身滞后于实现(这本身就是一种"差距") - `development-plan.md`/`unit_matrix.json` 从写就没有随实现更新"done"状态,只能靠 `git log` 和散落在各 Unit 条目下的事后补记("实现补充"/"真实 bug")判断真实进度。 - `docs/build-report.md` 里"⚠️ 尚未真实执行的一项"那一段(称 `RUN_REAL_SELF_HOSTING_E2E` 从未跑过)本身也已 经过时——`development-plan.md` U-042 条目下 2026-08-03 的记录显示之后确实做了 13 次真实自举压测(`git log` 里那一长串 `graphlemon: auto-commit`/`merge`/artifact 提交就是证据),只是仍未到达 `finalized`。连"总结性 收口文档"都会在自举持续运行的过程中被甩在后面——这是个会持续放大的风险,不是一次性的疏漏。 ## 5. 验证方法上的缺口 - 几乎所有 PH3 前端 Unit(U-022~U-030)的验证方式都写着"浏览器扩展本次会话不可用",靠 `curl`/Node 原生 WebSocket/`node --check` 语法检查代替,**没有一次是真人在浏览器里点击验证过的**——功能逻辑上大概率没问 题,但这是个反复出现、被如实记录但从未补上的验证缺口。 - `supervisor-auto-rollback-design.md` 里健康检查超时、监控窗口时长等参数明确标注"工程经验值,需要实测校 准",还没有真实生产数据校准过(PH5 已知交叉缺口第 4 条,`development-plan.md` 第 422-427 行)。 - **✅ 已修复(2026-08-03)健康检查 canary 探测永久泄漏 DB 记录**:`supervisor/deploy_health_check.py` 的 `check_canary_task()` 每次健康检查都会真实调候选进程的 `POST /api/projects`+`POST /api/tasks` 验证 HTTP+DB 写路径,但只清理了临时 git 目录,从未清理通过 API 真实创建的 project/task 行——**每跑一次真实健康检查, 候选进程当时用的数据库里就永久多两条垃圾记录**。真实发现:在真实的 `~/.graphlemon/graphlemon.db` 里发现 5 个 `deploy-canary` 项目,全部指向早已被系统清掉的 `/var/folders/.../deploy-canary-*` 临时目录,任务永远卡 在 `queued`,是之前某次真实健康检查验证(08-03 凌晨 05:50 那几次)留下的。已手动归档这 5 条历史记录 (`PUT /api/projects/:id {status:'archived'}`,跟控制台"归档"按钮走的是同一条路径——没用硬删除,因为 `task`/`artifact` 表有外键引用 `project_id`,硬删会破坏历史)。**修复**:`check_canary_task()` 的 `finally` 块里新增:只要 project 行被真实创建过(不管后续 task 创建/校验成功还是失败),就调用同一条归档 API 清理掉 自己建的 project(最佳努力——归档调用本身失败不覆盖真实检查结果,避免把"没能清理自己"误判成"健康检查失 败")。新增 2 个回归测试:一次成功的 canary 检查后 project 应变成 `archived`;task 创建失败时 project 也 不应该泄漏。`supervisor/` 全量 125 个测试 + `src/` 513 个测试全绿。 --- ## 6. 用 graphlemon 自举修复以上 gap 的可行性,及任务拆解清单 **结论**:机制上可行且已被验证过(13 次真实自举压测已经走通 Planner→Coder→Validator→Org-level Loop→Deploy Supervisor 全链路),但不能整体当成"黑灯工厂"一次性丢给它——原因就是第 2 节本身:没有常驻调度器,每一次 执行仍需人工手动触发(`run_goal_to_completion()` 或门控测试),这是当前系统的真实边界,不是这批任务的缺陷。 下表把上述 gap 拆成可以逐个手动触发的 self-target task,标注风险等级和建议顺序。"手动触发"指人工调用一次 `scheduler.run_goal_to_completion(...)`(或未来对应的 API),不是让它们排队后无人值守跑完;每个任务完成、 Deploy Supervisor 走到 cutover 前,仍按现有习惯人工确认一次。 | 顺序 | Gap(对应章节) | 建议 goal_text 方向 | 风险等级 | 备注 | |---|---|---|---|---| | 1 | ✅ 已修复(2026-08-03) 普通 target project 从未部署 Agent 定义 + worktree 隔离未提交(§3) | ~~让 `agent_profile.deploy_agent_definitions()` 在写完 `.claude/agents/*.md` 后自动 `git add`+commit~~ | 低 | 实际根因比预想的更基础(根本没调用点,不只是没 commit);**这次是人工直接改代码修的,不是走自举流程验证的**——留作顺序 2 之后再真正试一次"用 graphlemon 自己修 graphlemon"的对照 | | 2 | 文档滞后(§4) | 让 Planner/Coder 核对 `development-plan.md`/`unit_matrix.json` 与 `git log` 的实际进度,补齐/订正"done"状态字段 | 低 | 纯文档任务,不改行为代码,出错代价最小;但要求 Coder 能准确核对而不是编造状态,建议 Validator 阶段重点复核 | | 3 | Skill 内容未真正迁移(§3) | 把 `~/.hermes/profiles/{code,planning,qa}/skills/` 下 frontmatter 引用到的 Skill 真实内容迁移进仓库 `skills//` | 中 | 已确认 `~/.hermes/skills` 在本机真实存在;风险点在于 Coder 会话对仓库外路径的读取权限没有专门验证过,需要先确认 `auto` 权限模式下这条路径可达 | | 4 | 部署缺互斥锁(本节新发现,§1) | 给 `deploy_stage.stage_deployment()` 加"当前是否已有进行中部署"的检查,拒绝/排队重复 staging | 中 | 应该在启用并发自举(顺序 6 之后)之前完成,否则后续任务并发跑时有真实冲突风险 | | 5 | PH3 前端从未被真人验证(§5) | 不适合作为自动化 Coder 任务——这是"人用浏览器点一遍"的验证缺口,不是代码缺陷;列在这里是为了不让它被误当成可自举任务 | 不适用 | 需要人(或 claude-in-chrome 之类的浏览器自动化)介入,不建议塞进 Planner→Coder 循环 | | 6 | 调度器接入生产入口(§2) | 给某个常驻进程(`backend_server.py` 或独立进程)接入 `scheduler.run_scheduler_once()` 的轮询循环 | 高 | **改变系统自己的自主权边界**,建议单独一批、额外人工审查 diff,不要和其他 gap 混跑;完成并 cutover 后,理论上后续 gap 才谈得上真正黑灯 | | 7 | Deploy Supervisor 缺 `poll_fn`(§1) | 实现"发现待部署的 self-target 合并"逻辑,接入 `supervisor/deploy_supervisor.py` 的 `poll_fn` 钩子 | 高 | 依赖顺序 6 先完成(两者共同构成"真正自驱动");且 SDD 里"什么条件触发自部署"本身有文档内部冲突(设计文档 vs 规范正文),需要人工先拍板这个设计决策,不能让 Planner 自己悄悄选一种理解 | | — | Coder 阶段的多模块 Work Graph 规划(§3) | 不建议列入这批"修 gap"任务 | 不适用 | 这是被明确判断为"超出范围的新能力",不是缺陷;如果要做,应该走正常的新功能立项,不该包装成"修复"塞进自动循环 | **执行建议**:先跑 1→2(验证流程本身),再跑 3→4(补齐已知风险点),5 留给人工/浏览器自动化处理,6→7 作为 独立的、审查最严格的一批,完成后再评估是否真的要把后续维护交给自动调度。整个过程每一步仍需人工确认后触发, 不建议现在就配置成无人值守连续跑——待 6/7 完成并观察一段时间稳定后再考虑。 **顺序 1 验证过程中额外发现的一个非代码问题,记一笔**:`org_node_lifecycle._check_concurrency()` 统计"活跃任务 数"是**跨全部 project 全局统计**的,不分项目;`/tmp/graphlemon-visual-check/graphlemon.db` 这个测试库里另一个 project 下有条历史演示任务一直停在 `coding`(非终态但没人真的在跑),加上 `org_concurrency_config` 表当时是空 的(兜底 `max_concurrent_goals=1`),导致新任务永远被并发闸门挡住,和 agent 定义那个 gap 完全无关,纯粹是这个 临时测试库里的历史数据问题(已经通过 `PUT /api/settings/concurrency` 调高上限绕过,没有改代码)。不算一个新 gap,但**全局而非按项目的并发统计**是不是有意为之,值得找个时间单独确认一下——如果以后真的多项目并行用,这 个设计会让不相关项目的任务互相卡对方的并发额度。 --- ## 最值得关注的三条 1. 调度器没接入生产入口,系统还不是真正自驱动的(第 2 节)。 2. Deploy Supervisor 缺"自动发现待部署改动"的 `poll_fn`,PH5 的"自动"两个字还没完全兑现(第 1 节)。 3. 文档(development-plan/unit_matrix/build-report)本身持续滞后于自举产生的新提交,这个滞后会越滚越大, 建议找个时间点做一次文档收口,而不是继续靠事后补记维持可读性(第 4 节)。