implementation-gap-analysis.md 16.7 KB

实现现状 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/<skill_id>/ 真实文件,测试靠 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 ✅ 已修复(2026-08-04,真正走 graphlemon 自举流程验证) 文档滞后(§4) 让 Planner/Coder 核对 development-plan.md/unit_matrix.json 与 git log 的实际进度,补齐/订正"done"状态字段 低 这是本次会话第一次真正用 graphlemon 自己的 Planner→Coder→Validator 闭环修复自己(不是人工直接改代码,对照顺序 1)。真实注册 graphlemon (self) project → scheduler.run_goal_to_completion() 后台跑约 40 分钟 → Coder 找出 6 处真实文档/machine-readable 不一致并订正(含主动发现"另一会话"两个功能提交在 unit_matrix.json 里缺 Unit 条目,补建 U-044/U-045)→ Validator 独立重跑全量 513 测试 + 逐条核对 git commit 后判 PASS,未直接信任 Coder 报告。过程中触发了一次真实 ensure_worktree_committed 主仓库漂移自动提交,机制本身也顺带得到一次真实验证。详见 git log(43dc7333 相关提交链,3bebe3b起)。
3 Skill 内容未真正迁移(§3) 把 ~/.hermes/profiles/{code,planning,qa}/skills/ 下 frontmatter 引用到的 Skill 真实内容迁移进仓库 skills/<skill_id>/ 中 已确认 ~/.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 节)。