plan-migration.html 26.6 KB
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" />
<title>最小改造路径 · LemonBoss PRD</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,300;9..144,500;9..144,700&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="assets/shell.css" />
</head>
<body data-page="plan-migration.html">
<div class="shell">
  <aside id="sidebar"></aside>
  <main class="page">
    <header class="page-head">
      <div class="crumb"><span class="pill">08 · PLAN</span><span class="sep">/</span><span>最小改造路径</span></div>
      <h1>最小改造路径</h1>
      <p class="deck"><b>五</b>个阶段递进,每阶段独立可演示。P0 把 79 个工具实现 + ACP 桥接搭好;P1 不动核心,让 PM+Architect 跑出文档;P2 先单 Unit;P3 才把 L1 + L2 接起来;P4 加 L3 反馈 + UI。每阶段对应一个 PR。</p>
    </header>
    <article class="body">

      <section>
        <h2>第一天 Quick-Start · 从零起步</h2>
        <p>「我装好仓库 cd 进去,第一行命令该是什么」—— 答案:</p>
<pre class="code"><span class="c"># 1. 拉仓库 + 装依赖</span>
git clone gitlab-wuwei.hexpm.com:yibo/lemonboss.git
cd lemonboss
pnpm install                                          <span class="c"># LemonBoss 用 pnpm workspace</span>

<span class="c"># 2. 配 .env</span>
cp .env.example .env
<span class="c"># 编辑设置 PORT=3010 等;v1 不需要 OPEN_API_KEYS</span>

<span class="c"># 3. 浏览本 PRD (推荐先扫一遍 index → reading-guide)</span>
open docs/prd/newfunction/index.html                  <span class="c"># macOS</span>
<span class="c"># 或: python3 -m http.server -d docs/prd/newfunction 8000 → open localhost:8000</span>

<span class="c"># 4. 验证文档侧 tooling 已经就绪</span>
node scripts/extract-manifest.js                      <span class="c"># 期望: 54 MVCP defs 100%</span>
node scripts/build-search-index.js                    <span class="c"># 期望: 51 pages 195KB</span>

<span class="c"># 5. 从 P0.0 开始动代码 (按 §五阶段总览 P0 表格顺序)</span>
mkdir -p server/services
<span class="c"># 第一个文件: server/services/path-resolver.js  (所有人都依赖它)</span>
<span class="c"># 第二个文件: server/services/doc-store.js</span>
<span class="c"># ...按 §P0 子任务速览 P0.0 行的服务清单顺次实现</span>

<span class="c"># 6. P0.B 启用 Mock Claude CLI 模式 (一旦工具骨架在)</span>
<span class="c">#    详见 arch-acp-bridge.html · Mock Mode 章节</span>
MOCK_CLAUDE=1 node scripts/phase0-verify.js           <span class="c"># 工具流跑通,不烧 token</span>

<span class="c"># 7. 真跑 P0 验证 (P0.J 完成后)</span>
node scripts/phase0-verify.js                         <span class="c"># ✓ All 79 tools + 1 mock PM call</span>
node scripts/phase0-test-call.js                      <span class="c"># ✓ todolist 落盘 + SSE 触发</span>

<span class="c"># 8. 进 P1: 准备启动真实 Agent</span>
PORT=3010 node server/index.js &amp;                      <span class="c"># server 起来</span>
node scripts/devloop-new.js \
  --name <span class="s">"Auto TODO"</span> \
  --requirement <span class="s">"做一个 TODO API + Vue 前端"</span>     <span class="c"># sandbox 模式</span>
<span class="c"># 期望: 30-60s 内 data/.../projects/p-XXXXXX/prd/ 完整生成</span></pre>
        <p class="sig">第一天能 100% 跑通到第 4 步(文档侧验证);P0.0 实施开始后第 5 步以下才有意义。</p>
      </section>

      <section>
        <h2>五阶段总览</h2>
        <table>
          <thead><tr><th>阶段</th><th>目标</th><th>新增 / 修改</th><th>可演示场景</th></tr></thead>
          <tbody>
            <tr>
              <td><b>P0 · Bootstrap</b><br/><span class="sig">3.5 周</span></td>
              <td><b>服务层 7 件套</b>(pathResolver/docStore/unitRegistry/bugTracker/timelineLogger/sseBroker/GitVault)+ 79 工具实现 + Mock Claude CLI 模式 + ACP 桥接 + 系统提示提取 + git 集成</td>
              <td>7 个 <code>server/services/*.js</code>、<a href="arch-tool-registry.html">tool-registry</a>(34 工具)、<a href="arch-acp-bridge.html">acp-bridge</a> + Mock 模式、<a href="arch-git-versioning.html">git-versioning</a>、scripts/extract-agent-prompts.js、scripts/phase0-verify.js</td>
              <td><code>MOCK_CLAUDE=1 phase0-verify</code> 通过 → 真跑 phase0-verify 通过 → 一个 mock PM call 落 todolist + .git 初始化 + 首个 prd commit</td>
            </tr>
            <tr>
              <td><b>P1 · Docs MVP</b></td>
              <td>能由 PM + Architect 把一段需求转成多页 PRD 站点 + 多页 SDD 站点 + <code>units.json</code> + <code>integration/spec.json</code></td>
              <td><code>DocStore</code>、PM / Architect 模板、<code>POST /api/devloop/projects</code></td>
              <td>curl 一段中文需求 → 文件系统里看到 PRD/SDD 多页站点 + units.json + integration/spec.json + agent-state/</td>
            </tr>
            <tr>
              <td><b>P2 · L1 单 Unit</b></td>
              <td>对单个 Unit 跑 Coder→Tester 重试到通过</td>
              <td>Coder / Tester 模板、<code>UnitRegistry</code>、<code>retryWithReflection</code>(新写在 loop-controller.js 内,不抽公共)</td>
              <td>故意挖一个 bug 让 Tester 红,看 Coder 反思后绿</td>
            </tr>
            <tr>
              <td><b>P3 · L1 + L2 联动</b></td>
              <td>多 Unit 并行 + 集成测试 + 失败回写</td>
              <td><code>LoopController</code>、Integrator / BugTriager 模板,复用 <code>scheduler</code></td>
              <td>故意写 contract mismatch,看 SDD 自动 patch + 受影响 Unit reset → 重跑 L1</td>
            </tr>
            <tr>
              <td><b>P4 · L3 + UI</b></td>
              <td>人类反馈触发增量;前端实时看板</td>
              <td><code>DevLoopDashboard.vue</code>、SSE 流、PRD diff 渲染</td>
              <td>页面上发新需求 → 看到 PRD 新增 section + 新 Unit 自动入队</td>
            </tr>
          </tbody>
        </table>
      </section>

      <section>
        <h2>P0 · Bootstrap(~2.5 周 / 11.5 天)</h2>
        <div class="callout warn">
          <b>这是 P1 的<u>前置条件</u>。</b>没有 P0,PM/Architect 的 79 个工具签名都是空中楼阁。详细工时分解 + 工具组织见 <a href="arch-tool-registry.html">arch-tool-registry §⑪</a>。
        </div>

        <h3>P0 子任务速览</h3>
        <table class="dense">
          <thead><tr><th>子阶段</th><th>内容</th><th>工时</th><th>难度</th></tr></thead>
          <tbody>
            <tr><td><b>P0.0 服务层 7 件套</b><br/><span class="sig">所有其他都依赖它</span></td>
                <td>
                  <code>server/services/</code> 顺次实现:<br/>
                  ① <code>path-resolver.js</code>(~80 行;<b>第一个写</b>,其余都依赖它)<br/>
                  ② <code>doc-store.js</code>(~140 行;prd/sdd/units IO + cheerio 校验)<br/>
                  ③ <code>unit-registry.js</code>(~120 行;Unit FSM + l2GateOpen)<br/>
                  ④ <code>bug-tracker.js</code>(~110 行;bugs.ndjson CRUD + dedupKey)<br/>
                  ⑤ <code>timeline-logger.js</code> + <code>changelog-writer.js</code>(~80 行合计)<br/>
                  ⑥ <code>sse-broker.js</code>(~80 行;订阅 + 心跳 + replay)<br/>
                  ⑦ <code>git-vault.js</code>(~150 行;spawn git wrapper + per-pid mutex)<br/>
                </td>
                <td>4.5 天</td><td>低中(独立实现 · 每个文件可单测)</td></tr>
            <tr><td>P0.A 工具实现<br/><span class="sig">需 P0.0 完成</span></td><td><code>server/src/tools/devloop/</code> 下 7 个文件,34 个独立函数 (~1700 行)。每个工具 wrapper 通过 ctx 引用 P0.0 的服务</td><td>5 天</td><td>中(cheerio 多)</td></tr>
            <tr><td><b>P0.A2 Mock Claude CLI 模式</b><br/><span class="sig">开发期省 token</span></td>
                <td>给 <code>ClaudeCliProtocol</code> 加 <code>MOCK_CLAUDE=1</code> 分支,读 <code>system/mock-responses/{agent}/*.json</code> 当 stub 回复。详见 <a href="arch-acp-bridge.html">acp-bridge · Mock Mode</a></td>
                <td>0.5 天</td><td>低</td></tr>
            <tr><td>P0.B 提示提取</td><td><code>scripts/extract-agent-prompts.js</code> 从 6 个 agent HTML §2.2 抽 prompt</td><td>0.5 天</td><td>低(正则)</td></tr>
            <tr><td>P0.C 模板注册</td><td><code>system/templates/_registry.json</code> 加 6 条 devloop-* + toolPolicy</td><td>0.5 天</td><td>低</td></tr>
            <tr><td>P0.D CLI tools 注入</td><td><code>packages/acp-core/protocol/ClaudeCliProtocol.js</code> 改 ~10 行,按 toolPolicy 生成 --tools json</td><td>1 天</td><td>中</td></tr>
            <tr><td>P0.E agent-manager 透传</td><td>加 toolRegistry / toolCtx / onChunk 三个可选参数,~10 行</td><td>0.5 天</td><td>低</td></tr>
            <tr><td>P0.F jsonGuard 挂 Bash</td><td>Bash 工具 preExecute 钩子拦截 inline JSON</td><td>0.5 天</td><td>低</td></tr>
            <tr><td>P0.G 验证脚本</td><td><code>scripts/phase0-verify.js</code> + <code>phase0-test-call.js</code></td><td>1 天</td><td>低</td></tr>
            <tr><td>P0.H 联调</td><td>跑一个 mock PM 调用 → 看 todolist 落盘 + SSE 触发</td><td>2 天</td><td>—</td></tr>
            <tr><td>P0.I git 集成到 LoopController</td><td>createProject 时 git init + .gitignore 模板;callAgentWithPersistence success 分支加 commitAfterAgent;recoverOnBoot 加 git status 检查(GitVault 已在 P0.0 ⑦ 落盘)</td><td>1 天</td><td>中</td></tr>
            <tr><td>P0.J git 验证</td><td>phase0-verify 加:项目初始化后 .git 存在 + 一次 mock commit + tag · listTags</td><td>0.5 天</td><td>低</td></tr>
            <tr><td><b>P0 合计</b></td><td>—</td><td><b>17 天 ≈ 3.5 周</b></td><td>—</td></tr>
          </tbody>
        </table>

        <h3>验收</h3>
<pre class="code">node scripts/phase0-verify.js
<span class="c"># ✓ All 79 tools registered (34 unique impl)</span>
<span class="c"># ✓ 6 system prompts extracted to system/templates/devloop-*.md</span>
<span class="c"># ✓ _registry.json contains all 6 devloop-* entries</span>

node scripts/phase0-test-call.js
<span class="c"># ✓ Mock PM call → write_todolist tool invoked</span>
<span class="c"># ✓ data/companies/c-test/projects/p-mock/agent-state/pm-todo.json written</span>
<span class="c"># ✓ SSE agent.todolist event emitted</span>
<span class="c"># ✓ No sandbox violations</span></pre>

        <div class="callout ok">
          <b>关键决策:</b>P0 期间 agent-manager 改动 ≤ 20 行,全是<b>追加可选参数</b>。老调用方(Master Agent / Innovator)不受影响。
        </div>
      </section>

      <section>
        <h2>P1 · Docs MVP(~1 周 / 5 天)</h2>
        <div class="callout">
          <b>建议的 demo 需求:</b>「一个 TODO 列表 API + 前端」。比登录系统更小、不涉及 auth/JWT/bcrypt 等坑、30 分钟能端到端跑通。
          预期 Architect 拆出 3 个 Unit:<code>todo-be</code>(POST/GET /todos)· <code>todo-fe</code>(Vue 列表)· 可选 <code>todo-db</code>(SQLite schema)。
          登录系统留到 <b>P3 当 contract_mismatch 演示</b>用。
        </div>

        <h3>新增文件</h3>
        <pre class="tree">
server/
├── services/
│   └── <span class="new">doc-store.js</span>             <span class="com"># ~140 行</span>
├── routes/
│   └── <span class="new">devloop.js</span>                <span class="com"># 只挂 POST /projects · GET /state,~80 行</span>
└── src/core/
    └── (LoopController 阶段性 stub)

system/templates/
├── <span class="new">devloop-pm.md</span>                 <span class="com"># PM system prompt</span>
├── <span class="new">devloop-architect.md</span>          <span class="com"># Architect system prompt</span>
└── <span class="new">_registry.json</span>                <span class="com"># 追加 6 条(先用 PM + Architect 两条)</span>
        </pre>

        <h3>验收</h3>
        <pre class="code">curl -X POST http://localhost:3010/api/devloop/projects -d @/tmp/req.json
<span class="c"># /tmp/req.json: {"company_id":"c-001","name":"todo-demo","requirement":"做一个 TODO 列表:能新增、列表、Vue 前端"}</span>

<span class="c"># 期望产物(与 data-layout.html 对齐)</span>
data/companies/c-001/projects/p-XXXXXX/
├── project.json                              ✓  <span class="c"># M-1 项目元数据</span>
├── prd/                                      ✓  <span class="c"># M-3 多页 PRD 站点</span>
│   ├── index.html
│   ├── reading-guide.html
│   ├── product/{background,personas,...}.html
│   ├── feature/feature-tree.html
│   ├── flow/user-flows.html
│   └── prototype/proto-*.html
├── sdd/                                      ✓  <span class="c"># M-4 多页 SDD 站点</span>
│   ├── index.html
│   └── mvcp/{model,view,control,process}.html
├── units.json                                ✓  <span class="c"># M-2 含 l2_rounds / l2_budget 初值</span>
├── integration/spec.json                     ✓  <span class="c"># Architect 写</span>
├── agent-state/                              ✓  <span class="c"># M-10 / M-12 Agent 持久化运行态</span>
│   ├── pm.json · pm-todo.json
│   └── architect.json · architect-todo.json
└── history/                                  ✓  <span class="c"># 全部 rev 归档</span>
    ├── prd-rev-001.html
    └── sdd-rev-001.html</pre>
      </section>

      <section>
        <h2>P2 · L1 单 Unit(~1.5 周 / 8 天)</h2>

        <h3>新增文件</h3>
        <pre class="tree">
server/
├── services/
│   └── <span class="new">unit-registry.js</span>          <span class="com"># ~120 行</span>
└── src/core/
    └── <span class="new">loop-controller.js</span>        <span class="com"># runUnit() 单 unit 循环 + retryWithReflection() 内置,~140 行</span>

system/templates/
├── <span class="new">devloop-coder.md</span>
└── <span class="new">devloop-tester.md</span></pre>

        <div class="callout warn">
          <b>关于反思重试:</b>直接在 <code>loop-controller.js</code> 内写一份 <code>retryWithReflection()</code>。<b>不</b>从 <code>evolution-loop.js</code> 抽公共。原因见 <a href="arch-mapping.html">arch-mapping · 为什么 P1~P4 不抽公共 retry 函数</a>。
        </div>

        <h3>修改文件</h3>
        <ul>
          <li><code>server/routes/devloop.js</code> · 加 <code>POST /api/devloop/projects/:pid/run</code>(即 <a href="sdd-control.html">sdd-control · C-3</a>);P2 阶段 handler 临时支持 query <code>?only=&lt;unitId&gt;</code> 调用 <code>loopController.runUnit(pid, unitId)</code> 让单 unit 可测,P3 改造 <code>runProject()</code> 后即移除 <code>only</code> 参数,与 C-3 完全等价</li>
          <li><code>server/services/evolution-loop.js</code> · <b>不动</b></li>
        </ul>

        <h3>验收</h3>
        <p>跑命令后看到:</p>
        <ul>
          <li>Unit 状态从 <code>pending → coding → testing → failed → coding → testing → passed</code></li>
          <li><code>coder.log</code> 第二条决策明显引用了第一条的失败原因(说明反思生效)</li>
          <li>沙箱越权(试图改其他 unit code)被工具层拒绝</li>
        </ul>
      </section>

      <section>
        <h2>P3 · L1 + L2 联动(~3 周 / 15 天)</h2>

        <h3>新增 / 完善</h3>
        <pre class="tree">
server/src/core/loop-controller.js   <span class="com"># 完整 runProject() 主循环(去掉 P2 的 ?only= 临时入口)</span>

system/templates/
├── <span class="new">devloop-integrator.md</span>
└── <span class="new">devloop-triager.md</span>

server/services/
├── <span class="new">sse-broker.js</span>                <span class="com"># SSE 订阅管理 + stream.log replay,~80 行</span>
└── <span class="new">bug-tracker.js</span>               <span class="com"># 写 bugs.ndjson + GET /bugs 端点支持,~80 行</span>

server/routes/devloop.js             <span class="com"># 加 C-5 GET /api/devloop/projects/:pid/stream + GET /:pid/bugs</span>

<span class="c"># 同步生成的 append-only 产物(与 data-layout.html 对齐)</span>
projects/{pid}/
├── timeline.ndjson                  <span class="com"># M-13 全流程统一日志(loop-controller / agent-bridge 写)</span>
├── bugs.ndjson                      <span class="com"># M-14 跨 run bug 台账(bug-tracker 写)</span>
├── changelog.ndjson                 <span class="com"># M-15 PRD/SDD/units rev 变更流(DocStore 写)</span>
└── stream.log                       <span class="com"># SSE 客户端视角日志(sse-broker 写,7 天滚动)</span></pre>

        <h3>验收</h3>
        <p>P3 必须在 <b>4 类 L2 分支</b>(参见 <a href="sdd-process.html">sdd-process · P-2</a>)下都跑通:</p>

        <h4>① <code>contract_mismatch</code> · 自动 patch SDD</h4>
        <ol>
          <li>需求 = 「一个登录系统:邮箱密码 + token,前端展示」</li>
          <li>在 Architect 生成的 SDD 中<b>故意</b>插入矛盾(auth-be 写 401,auth-fe 假设 403)</li>
          <li>L1 全部 passed → L2 集成失败</li>
          <li>BugTriager 给出 <code>contract_mismatch</code>,confidence ≥ 0.5</li>
          <li>Architect 自动 patch SDD(mode=patch)→ <code>sdd.updated</code> 事件</li>
          <li>auth-be + auth-fe reset → 重跑 L1(计 1 个 l2_round)</li>
          <li>第二次 L2 通过 → <code>project.shipped</code></li>
        </ol>

        <h4>② <code>impl_bug</code> · 不改 SDD,仅 reset</h4>
        <ul>
          <li>SDD 正确,故意把 auth-be 实现写成 password 字段名打错</li>
          <li>BugTriager 归因 <code>impl_bug</code> → SDD 不动 → 仅 auth-be reset → 重跑 L1(<b>不</b>烧 l2_round 预算)</li>
        </ul>

        <h4>③ <code>spec_ambiguous</code> / confidence &lt; 0.5 · 升 L3 等待人类</h4>
        <ul>
          <li>需求中故意留模糊点(如「token 续期策略」未定)</li>
          <li>Triager 给出 <code>spec_ambiguous</code> 或 confidence &lt; 0.5</li>
          <li>SSE 收到 <code>human_intervention_needed</code>(reason=<code>low_confidence_triage</code>)→ LoopController 进入 <code>l2_blocked</code>,<b>不</b>自动 patch</li>
        </ul>

        <h4>④ <code>infra_flake</code> · 直接重跑</h4>
        <ul>
          <li>模拟 Integrator 进程超时(kill -9)→ 归因 <code>infra_flake</code> → 直接 <code>runL2()</code> 重跑,<b>不</b>烧预算、<b>不</b>动 Unit</li>
        </ul>

        <h4>⑤ 可观测性产物校验(4 类分支跑完后统一检查)</h4>
        <ul>
          <li><code>bugs.ndjson</code> 含上述每次 triage 结果(open → fixing → fixed → verified 状态机轨迹)</li>
          <li><code>changelog.ndjson</code> 至少 1 条 sdd-rev 变更(来自分支 ①)</li>
          <li><code>timeline.ndjson</code> 含完整事件链路(unit.state / integration.result / triage.result / sdd.updated)</li>
          <li>SSE <code>GET /api/devloop/projects/:pid/stream</code> 用 Last-Event-ID 重连后能 replay 缺失事件</li>
        </ul>

        <h3>桥梁:极简 Status Page</h3>
        <p>P3 末尾顺手做一个 <b>~100 行的纯静态 HTML status page</b>(不上 Vue 路由,单文件放 <code>server/public/devloop-status.html</code>),轮询 <code>GET /api/devloop/projects/:pid/state</code> 渲染 DAG 与 loop 状态条。作用:</p>
        <ul>
          <li>给 P3 后期调试时一个可视化窗口(眼看 unit 状态翻飞比 tail 文件直观)</li>
          <li>作为 P4 完整 Dashboard 的功能预演 — 提前发现交互问题</li>
          <li>~100 行,不算进 P4 工作量</li>
        </ul>
      </section>

      <section>
        <h2>P4 · L3 + UI(~2 周 / 10 天)</h2>

        <h3>新增</h3>
        <pre class="tree">
web/src/views/
├── <span class="new">DevLoopDashboard.vue</span>         <span class="com"># ~400 行</span>
└── <span class="new">DevLoopOps.vue</span>                <span class="com"># Ops 容器(4 个 tab:Bugs / Loops / Changelog / Progress)</span>

web/src/components/devloop/         <span class="com"># Dashboard 子组件</span>
├── <span class="new">DashboardHeader.vue</span>
├── <span class="new">LoopStatusBar.vue</span>
├── <span class="new">UnitsDAG.vue</span>                 <span class="com"># 复用 PipelineEditor 渲染层</span>
├── <span class="new">LiveAgentStream.vue</span>
├── <span class="new">PrdDiffPanel.vue</span>
└── <span class="new">FeedbackModal.vue</span>

web/src/components/devloop/ops/     <span class="com"># Ops 子页(与 ops-*.html wireframe 对齐)</span>
├── <span class="new">BuglistView.vue</span>              <span class="com"># 渲染 bugs.ndjson(M-14)</span>
├── <span class="new">LoopLogView.vue</span>              <span class="com"># 按 L1/L2/L3 分组 timeline.ndjson</span>
├── <span class="new">ChangelogView.vue</span>            <span class="com"># 渲染 changelog.ndjson(M-15)</span>
└── <span class="new">ProgressView.vue</span>             <span class="com"># 项目实时进度聚合</span>

web/src/router/index.js              <span class="com"># 加 /devloop/:pid 主路由 + /devloop/:pid/ops/{bugs,loops,changelog,progress} 4 个子路由</span>

server/routes/devloop.js             <span class="com"># 加 C-6 POST /:pid/sign-off + C-7 POST /:pid/abandon(参见 sdd-control)</span></pre>

        <h3>验收</h3>
        <ul>
          <li>打开 <code>http://localhost:5173/devloop/p-XXXXXX</code> 看到 wireframe 描述的全部 4 个区域</li>
          <li>点 「+ NEW REQUIREMENT」发新需求 → PRD diff 区出现新 section(触发 PM incremental 模式)</li>
          <li>Live 流实时滚动 Agent 输出(断网 5s 后自动重连,用 Last-Event-ID replay)</li>
          <li>DAG 节点点击展开抽屉,看 unit 的最近 3 次 run</li>
          <li>4 个 Ops 子页都能打开:<code>/ops/bugs</code> · <code>/ops/loops</code> · <code>/ops/changelog</code> · <code>/ops/progress</code></li>
          <li>项目交付后点 「Sign Off」按钮 → <code>POST /api/devloop/projects/:pid/sign-off</code> → 状态变 <code>shipped-final</code>,前端拒绝再发新反馈</li>
          <li>异常项目点 「Abandon」按钮 → <code>POST /api/devloop/projects/:pid/abandon</code> → 状态变 <code>abandoned</code>,SSE 发 close 帧</li>
        </ul>
      </section>

      <section>
        <h2>成本估算</h2>
        <table class="dense">
          <thead><tr><th>类型</th><th>文件数</th><th>预估行数</th><th>难度</th></tr></thead>
          <tbody>
            <tr><td>新增 JS(后端)</td><td>6 (<code>doc-store</code> · <code>devloop</code> route · <code>unit-registry</code> · <code>loop-controller</code> · <code>sse-broker</code> · <code>bug-tracker</code>)</td><td>~800</td><td>中</td></tr>
            <tr><td>新增 Agent 模板</td><td>6 (PM · Architect · Coder · Tester · Integrator · Triager)</td><td>~900</td><td>中(参考 <a href="agents-pm.html">agents-pm</a> / <a href="agents-architect.html">agents-architect</a>,单模板 ~150 行 + 多个 few-shot 例子)</td></tr>
            <tr><td>新增 Vue 组件</td><td>12 (Dashboard 1 + Ops 容器 1 + dashboard 子组件 6 + ops 子页 4)</td><td>~1650</td><td>中</td></tr>
            <tr><td>修改既有</td><td>3 (<code>server/index.js</code> 挂路由 · <code>_registry.json</code> 加 6 条 · <code>web/src/router/index.js</code> 加 5 条路由)</td><td>~50</td><td>低</td></tr>
            <tr><td>新增包依赖</td><td>1 (<code>cheerio</code>)</td><td>—</td><td>—</td></tr>
            <tr><td><b>合计</b></td><td><b>27</b></td><td><b>~3400 行</b></td><td>—</td></tr>
          </tbody>
        </table>
        <p class="sig">较早前版本(20 文件 / ~1580 行)低估了:① Agent 模板单文件实际 prompt 长度(PM/Architect 当前 PRD 已揭示需 200-300 行 prompt + 数个 few-shot);② Dashboard 子组件粒度(DAG / 抽屉 / diff 渲染单组件就 100+ 行);③ Ops 4 个子页此前未计入。</p>

        <h3>时间预算</h3>
        <p>单人 Claude Code 协同开发:<b>P0(17 天)</b> → P1(5 天)→ P2(8 天)→ P3(18 天)→ P4(15 天)= 约 <b>10.5 周</b>。每阶段末 1 天用于演示 + 写迭代 PR 描述。</p>
        <ul>
          <li><b>P0(17 天)</b>:<b>P0.0 服务层 7 件套</b>(4.5 天,<b>第一个写</b>)+ 工具 + Mock Claude + ACP 桥接 + 提示提取 + GitVault 集成 + 验证脚本。详见上方 P0 表 + <a href="arch-tool-registry.html">tool-registry</a> + <a href="arch-acp-bridge.html">acp-bridge</a> + <a href="arch-git-versioning.html">git-versioning</a></li>
          <li><b>P3 +3 天</b>:增加 4 类 L2 分支演示(contract_mismatch / impl_bug / spec_ambiguous / infra_flake)+ 可观测性产物(bugs/changelog/timeline.ndjson)</li>
          <li><b>P4 +5 天</b>:Ops 4 个子页(Bugs / Loops / Changelog / Progress)+ sign-off / abandon 端点联调</li>
        </ul>
        <p class="sig">原估 4 周 → 6 周 → 7 周 → 9.5 周 → 10 周 → <b>10.5 周(含 P0.0 服务层 + Mock 模式)</b>。每次都是补缺,不是膨胀。参考 <a href="plan-cost-concurrency.html">成本预算</a>。</p>
      </section>

      <section>
        <h2>「自举」乐趣</h2>
        <div class="callout ok">
          <b>P4 完成后</b>,你可以让 LemonBoss DevLoop 系统去开发 <b>LemonBoss 自己</b>的下一个 feature。换句话说:用 v1 的 DevLoop 写 v1.1 的代码。这是验证三层 Loop 是否真的「能自我迭代」的最朴素方式。
        </div>
      </section>

    </article>
    <nav class="prev-next"></nav>
    <footer class="site"><div><b>Section</b>08 · Plan</div><div><b>Page</b>plan-migration.html</div></footer>
  </main>
</div>
<script src="assets/shell.js"></script>
</body>
</html>