Commit 39213ab2ce8268aabe54a1fa75a082161e11885e

Authored by graphlemon
1 parent ebfcc437

graphlemon: auto-commit uncommitted changes for e30e6617-203e-4941-b85f-131e4ae9…

…be04-main-checkout-drift
Showing 1 changed file with 148 additions and 0 deletions
docs/build-report.md 0 → 100644
  1 +# graphlemon 构建报告
  2 +
  3 +**六个 Phase,45 个 Unit,一套真正跑起来的"熄灯"软件工厂。**
  4 +
  5 +graphlemon 是一个 Level 5 自主研发系统:固定的 Planner → Coder → Validator Org Graph,驱动每个任务
  6 +动态生成的 Work Graph,完全跑在 Claude Code 自己的 `claude -p` 后端之上——能写代码、能抓自己的回归,
  7 +到本次会话结束时,还能在无人读 diff 的情况下重新部署自己正在运行的进程。
  8 +
  9 +- **状态**:PH0~PH5 全部完成,45 / 45 个 Unit
  10 +- **测试**:552 个测试全绿
  11 +- **Git**:`fc94ae8`(初始基线)→ `59e96d3`(U-043,当前 tip)
  12 +- **数据模型**:17 张 sqlite 表
  13 +- **Unit 分类**:Risk Gate 18 / Value Path 17 / Enabler 10
  14 +- **过程中"停下来问用户"的关键决策**:3 次
  15 +
  16 +---
  17 +
  18 +## Phase 链路
  19 +
  20 +```
  21 +PH0(9 units,Enabler)→ PH1(6 units,MVP 闭环)→ PH2(7 units,质量闭环)
  22 + → PH3(10 units,控制台)→ PH4(3 units,全量回归收口)→ PH5(10 units,自举能力)
  23 +```
  24 +
  25 +---
  26 +
  27 +## PH0:脚手架与第一个高风险假设
  28 +
  29 +**Unit**:U-001 ~ U-008、U-004.5
  30 +
  31 +15 张核心表的数据模型、Hermes 人设迁移到 `.claude/agents/*.md`、一套受 `RUN_REAL_AGENT_E2E` 环境变量
  32 +门控的真实 API 测试 harness,以及本地后端/前端的骨架——后面一切工作的地基。
  33 +
  34 +> **假设验证——不是"干净通过"**:A-2 假设在这里被真正验证:Planner/Validator 的人设几乎可以原样迁移,
  35 +> 但 Coder 的 `SOUL.md` 不行——里面硬编码了一个真实的飞书 Base API token、整段"认领"机制强绑定
  36 +> `lark-cli`、还指示自己再跑一次 `claude --dangerously-skip-permissions`,三处都必须删除或重写才能安全
  37 +> 运行。
  38 +
  39 +---
  40 +
  41 +## PH1:第一条真正跑通的闭环
  42 +
  43 +**Unit**:U-009 ~ U-014
  44 +
  45 +用"实现贪吃蛇游戏"这个目标真实跑通全链路:Planner 产出 BRD→PRD→SDD→Benchmark,Coder 实现并自测,
  46 +Validator 复核并给出根因归属——架构文档 §11 验收标准第 1-3 条,是真跑出来的,不是模拟的。
  47 +
  48 +> **假设确认**:A-1 假设在这里被确认——一次真实花费 $0.46 的 spike 证明了 Claude Code 的动态工作流原语
  49 +> (`agent()`/`parallel()`/`pipeline()`)可以通过 `claude -p` 无交互调用,并返回可解析的结构化结果。
  50 +
  51 +> **平台层怪癖(实测发现)**:`--json-schema` 一旦和 `--agent` 同时传,会被静默忽略——模型退化成把结构化
  52 +> 内容塞进自由文本里的一个 ```` ```json ```` 围栏代码块,而不是填充 `structured_output`。官方文档没有
  53 +> 说明,是靠真实调用发现的。
  54 +
  55 +---
  56 +
  57 +## PH2:教会它从自己的错误里恢复
  58 +
  59 +**Unit**:U-015 ~ U-021
  60 +
  61 +三视角根因判定、Org-level Loop 的 `fast_lane`/`full_replan` 路由、双层预算护栏、Claude plan 额度耗尽的
  62 +等待重试机制、Graph Engine 断点恢复。人为植入一个 bug,从一端进去,从另一端出来时已经是一次真实的修复、
  63 +重新验证、任务关闭。
  64 +
  65 +---
  66 +
  67 +## PH3:一个不需要构建步骤的控制台
  68 +
  69 +**Unit**:U-022 ~ U-030、U-024.5
  70 +
  71 +项目创建、目标输入、实时仪表盘、任务看板与详情页、DAG 图可视化、实时日志查看器、Artifact/Skill 浏览器、
  72 +配置页——纯原生 HTML/CSS/JS,配一个手写的 WebSocket 服务端,因为"纯 stdlib、无第三方依赖、无构建步骤"
  73 +这条约束对 graphlemon 自己的控制台同样适用。
  74 +
  75 +> **真实 bug**:HTTP 服务端各请求线程和 WebSocket 轮询线程共享同一个 sqlite 连接时,如果关闭连接没有
  76 +> 持有和读写操作同一把锁,会**直接把解释器段错误崩溃**——"关闭"看起来像一次性操作,但对同一个连接对象
  77 +> 而言并不天然安全。修复后连续压测多次全部稳定。
  78 +
  79 +> **后期补漏**:一次收口审计中发现,WebSocket 重连后任务看板和任务详情页从未真正重新拉取过状态快照——
  80 +> 只有仪表盘做出反应,而且也只是切换了一个提示条。现在三处重连后都会真正刷新,符合 REQ-12 自己的边界
  81 +> 用例要求。
  82 +
  83 +---
  84 +
  85 +## PH4:两轮审计,十个真实缺口
  86 +
  87 +**Unit**:U-031 ~ U-033
  88 +
  89 +把 06 节 REQ-01~REQ-14 的全部验收用例,逐条对照实际测试覆盖重新核对了两遍——而不是相信"单测全绿"就
  90 +等于"验收要求真的被覆盖了"。
  91 +
  92 +> **结构性缺口**:Work Graph 的三个核心控制器(规划、执行、单节点运行)各自都做过完整单测,但**从来没有
  93 +> 在生产代码里被真正串联调用过**——唯一验证过的闭环(PH1 的贪吃蛇场景)悄悄绕开了它们,走了一条更简单
  94 +> 的并行路径。补上这层编排后,真实 API 调用又暴露出两个新 bug(一个 manifest 字段名不匹配、一个缺失的
  95 +> 工作目录),都是只有真实调用才会暴露的问题。
  96 +
  97 +> **第二轮审计**:PH5 开工前对验收用例的又一次逐条复核,发现了 5 个新的真实缺口:一处遗漏的中间状态写入、
  98 +> 一个从未真正测过的调度器场景、三条"节点被标记 blocked 但从未告知父任务"的失败路径、一个原本完全不存在
  99 +> 的 PRD 一致性检查、外加一处偏弱的测试断言。其中一次修复(新增的一致性检查调用)当场抓到模型把
  100 +> `consistent` 字段返回成 JSON **字符串** `"false"`,而 Python 的真值判断把它当成了 `True`。
  101 +
  102 +> **假设正式收口**:A-2 假设在这里正式收口,结论仍是"部分成立"——PH0 之后又有四个不同 Unit 里真实调用
  103 +> 过迁移后的人设,没有再暴露新的偏差。但结论不会因此升级为"confirmed":那次重写已经发生了,后面跑得再
  104 +> 干净也不能把它抹掉。
  105 +
  106 +---
  107 +
  108 +## PH5:教会它重新部署自己
  109 +
  110 +**Unit**:U-034 ~ U-043
  111 +
  112 +一整套蓝绿自部署机制:在独立的 git worktree 里拉起候选实例、跑三项 cutover 前健康检查、切换生产流量、
  113 +在监控窗口内采样四类信号、必要时回滚——包括"回滚本身也失败"这条兜底路径。
  114 +
  115 +> **SDD 内部冲突**:设计文档和正式规范对"到底什么条件会触发一次自部署"有分歧——设计文档说"self-target
  116 +> 改动通过验收即可",规范原文却把它挂在一条已存在的 `core_engine` bug 记录上——而一次干净的自我改进任务
  117 +> 根本不会产生这条记录。没有挑一种理解悄悄往下走,而是直接问了用户。
  118 +
  119 +> **真实 bug**:用 `kill(pid, 0)` 做存活检测分不清"真的在跑"和"已经退出但从未被父进程回收"——一个僵尸
  120 +> 进程能让这个检测正常通过。一个真实(未 mock)的、真的等待进程消失的测试因此一直挂起,直到补上正确的
  121 +> 进程回收逻辑才修好。
  122 +
  123 +> **其他发现**:缺一个跨重启追踪候选实例 checkout 目录的字段、后端服务完全没有命令行入口、参数表里唯独
  124 +> 缺一个固定的生产端口、也没有 `/api/health` 端点给健康检查调用。
  125 +
  126 +---
  127 +
  128 +## ⚠️ 尚未真实执行的一项
  129 +
  130 +U-042 的验收测试——对本仓库执行一次真实的自举 cutover,真实调用 `claude`、真实替换正在运行的进程——已经
  131 +建好并且在 mock 下全部通过,但被一个刻意设置得更严格、和项目里其他真实测试用的环境变量**不同**的开关
  132 +(`RUN_REAL_SELF_HOSTING_E2E=1`)挡住,因为这是整个代码库里爆炸半径最大的一个动作:它能替换掉正在运行
  133 +的 graphlemon 进程本身,还会在这个真实仓库上执行 git revert。
  134 +
  135 +**这项测试从未被真正执行过。** 是否要真的跑一次,是需要用户决定的事,不是构建过程自己能替你做的决定。
  136 +
  137 +---
  138 +
  139 +## 假设台账
  140 +
  141 +| ID | 假设 | 结论 |
  142 +|---|---|---|
  143 +| A-1 | Claude Code 的动态工作流原语可以通过 `claude -p` 无交互调用,并返回可解析的结构化结果 | **confirmed** |
  144 +| A-2 | 本地 Hermes 人设文件(`SOUL.md`/`AGENTS.md`)可以原样迁移到 `.claude/agents/*.md`,无需大改 | **部分成立**(已收口) |
  145 +
  146 +---
  147 +
  148 +*graphlemon · 纯 stdlib Python 实现,无任何第三方依赖 · 552 个测试 · 17 张表 · `fc94ae8` → `59e96d3`*
... ...