plan-reproducibility.html
12.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Claude Code 复现指南 · 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-reproducibility.html">
<div class="shell">
<aside id="sidebar"></aside>
<main class="page">
<header class="page-head">
<div class="crumb"><span class="pill">07 · PLAN</span><span class="sep">/</span><span>Claude Code 复现指南</span></div>
<h1>Claude Code 复现指南</h1>
<p class="deck">把这套 PRD + SDD 喂给一个全新的 Claude Code session,让它从空仓库(仅有 LemonBoss 既有代码)重建整套 DevLoop 系统。本页含:执行 prompt 模板 + manifest 抽取脚本 + 验收清单。</p>
</header>
<article class="body">
<section>
<h2>三步法</h2>
<svg viewBox="0 0 1100 220" width="100%" role="img">
<defs><marker id="arrRP" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M0,0 L10,5 L0,10 Z" fill="#0E0E10"/></marker></defs>
<g font-family="JetBrains Mono" font-size="11" fill="#0E0E10">
<rect x="40" y="80" width="280" height="60" rx="6" fill="#F7E8D2" stroke="#C77C2C"/>
<text x="180" y="105" text-anchor="middle" font-weight="700">① 抽取 build-manifest</text>
<text x="180" y="125" text-anchor="middle" font-size="10">cheerio 扫 sdd-*.html → JSON</text>
<rect x="400" y="80" width="280" height="60" rx="6" fill="#ECE4FB" stroke="#6E48C3"/>
<text x="540" y="105" text-anchor="middle" font-weight="700">② 投喂 Claude Code</text>
<text x="540" y="125" text-anchor="middle" font-size="10">manifest + 复现 prompt</text>
<rect x="760" y="80" width="280" height="60" rx="6" fill="#E2F2EA" stroke="#0E8C5A"/>
<text x="900" y="105" text-anchor="middle" font-weight="700">③ 自动开发 + 自验</text>
<text x="900" y="125" text-anchor="middle" font-size="10">写代码 → 单测 → 集成</text>
<g stroke="#0E0E10" fill="none" marker-end="url(#arrRP)">
<line x1="320" y1="110" x2="395" y2="110"/>
<line x1="680" y1="110" x2="755" y2="110"/>
</g>
</g>
</svg>
</section>
<section>
<h2>步骤 ① · 抽取 build-manifest.json</h2>
<p>需要 node + cheerio。脚本 ~80 行:</p>
<pre class="code"><span class="c">// scripts/extract-manifest.js · NEW</span>
<span class="k">const</span> fs = <span class="n">require</span>(<span class="s">'fs'</span>);
<span class="k">const</span> path = <span class="n">require</span>(<span class="s">'path'</span>);
<span class="k">const</span> cheerio = <span class="n">require</span>(<span class="s">'cheerio'</span>);
<span class="k">const</span> docsDir = path.<span class="n">resolve</span>(__dirname, <span class="s">'../docs/prd/newfunction'</span>);
<span class="k">const</span> manifest = <span class="p">{</span>
meta: <span class="p">{</span> source: <span class="s">'docs/prd/newfunction'</span>, prdRev: <span class="s">'v0.2'</span> <span class="p">}</span>,
model: <span class="p">[]</span>, view: <span class="p">[]</span>, control: <span class="p">[]</span>, process: <span class="p">[]</span>,
units: <span class="p">[]</span>,
<span class="p">}</span>;
<span class="c">// 1. 从 sdd-{mvcp}.html 抽 4 象限</span>
<span class="k">for</span> (<span class="k">const</span> mvcp <span class="k">of</span> <span class="p">[</span><span class="s">'model'</span>, <span class="s">'view'</span>, <span class="s">'control'</span>, <span class="s">'process'</span><span class="p">]</span>) <span class="p">{</span>
<span class="k">const</span> html = fs.<span class="n">readFileSync</span>(path.<span class="n">join</span>(docsDir, <span class="s">`sdd-</span><span class="v">${mvcp}</span><span class="s">.html`</span>), <span class="s">'utf8'</span>);
<span class="k">const</span> $ = cheerio.<span class="n">load</span>(html);
$(<span class="s">'[data-def-name]'</span>).<span class="n">each</span>((_, el) => <span class="p">{</span>
manifest[mvcp].<span class="n">push</span>(<span class="p">{</span>
name: $(el).<span class="n">attr</span>(<span class="s">'data-def-name'</span>),
path: $(el).<span class="n">find</span>(<span class="s">'code.path'</span>).<span class="n">first</span>().<span class="n">text</span>() ||
$(el).<span class="n">find</span>(<span class="s">'code.path.mono'</span>).<span class="n">first</span>().<span class="n">text</span>(),
shape: $(el).<span class="n">find</span>(<span class="s">'pre.shape'</span>).<span class="n">text</span>() ||
$(el).<span class="n">find</span>(<span class="s">'pre.code.shape'</span>).<span class="n">text</span>(),
contract: $(el).<span class="n">find</span>(<span class="s">'ul.contract li'</span>).<span class="n">map</span>((_,li) => $(li).<span class="n">text</span>()).<span class="n">get</span>(),
tests: $(el).<span class="n">find</span>(<span class="s">'ul.tests li'</span>).<span class="n">map</span>((_,li) => $(li).<span class="n">text</span>()).<span class="n">get</span>(),
<span class="p">}</span>);
<span class="p">}</span>);
<span class="p">}</span>
<span class="c">// 2. 从 prd-feature-tree.html 抽 Unit 列表(粗)</span>
<span class="c">// 这步实际由 Architect Agent 做 P1 时的拆分;脚本只做最简取出 file tree 中的 Unit id</span>
fs.<span class="n">writeFileSync</span>(<span class="s">'build-manifest.json'</span>, <span class="n">JSON.stringify</span>(manifest, <span class="v">null</span>, <span class="v">2</span>));
console.<span class="n">log</span>(<span class="s">`✓ extracted </span><span class="v">${manifest.model.length + manifest.view.length + manifest.control.length + manifest.process.length}</span><span class="s"> definitions`</span>);</pre>
<p>跑一下:</p>
<pre class="code">cd lemonboss
node scripts/extract-manifest.js
<span class="c"># → build-manifest.json (~30KB)</span></pre>
</section>
<section>
<h2>步骤 ② · 复现 Prompt 模板</h2>
<p>把以下 prompt 喂给一个全新的 Claude Code session(在空 lemonboss 仓库根目录启动)。</p>
<pre class="code"><span class="c"># 复现 prompt · 直接粘到 claude code</span>
我手上有一份 LemonBoss DevLoop 系统的完整 PRD + SDD(HTML 形式),位于
docs/prd/newfunction/ 下,共 41 页。我已用脚本抽出 build-manifest.json。
请你扮演 Architect + Coder + Tester 三个角色,完成以下工作:
【阶段 A · 拆 Unit】
1. 读 docs/prd/newfunction/prd-feature-tree.html,确认 34 个 Unit
2. 读 build-manifest.json,把 MVCP 四象限的定义映射到 Unit
3. 在 data/companies/c-repro/projects/p-init/units.json 落地 DAG
【阶段 B · 实现每个 Unit】
对每个 Unit 顺次:
1. 读对应 Unit 的所有 MVCP 定义(manifest 里的 model/view/control/process)
2. 按 path 字段落盘,按 shape 字段写代码骨架
3. 按 contract 列表实现行为
4. 按 tests 列表写 vitest 用例(后端 supertest + 内存 SQLite,前端 @vue/test-utils)
5. 跑 vitest,红了反思(参考 docs/prd/newfunction/loops-l1.html 的 retryWithReflection
章节),重写直到绿
【阶段 C · 集成】
1. 读 docs/prd/newfunction/sdd-process.html 实现 LoopController.runProject
2. 启动后端 + 前端,cd 到 docs/prd/newfunction,用 docs 自己做 demo 项目跑一遍
3. 注入「contract_mismatch」演示自愈
【约束】
- 严格遵守 docs/prd/newfunction/agents-coder.html 的沙箱规则
- 任何带 JSON body 的 curl 必须先写 /tmp/*.json 再 -d @file
(参见 CLAUDE.md L91-99)
- 不动 server/services/evolution-loop.js(参见 arch-mapping.html PATCH 说明)
- 不动 packages/acp-core/ · core/master-session.js · core/agent-manager.js
【验收】
完成后跑 npm test,所有 vitest 必须通过。然后跑:
curl -X POST http://localhost:3010/api/devloop/projects -d @/tmp/test.json
(/tmp/test.json 单行紧凑:
{"company_id":"c-001","name":"todo","requirement":"做个 TODO API"})
应在 60 秒内看到 prd.html + sdd.html + units.json 三份文档生成。
开始吧。</pre>
</section>
<section>
<h2>步骤 ③ · 验收清单</h2>
<p>Claude Code 跑完后,人类只需对照以下 12 条逐项检查:</p>
<table>
<thead><tr><th>#</th><th>检查点</th><th>判定</th></tr></thead>
<tbody>
<tr><td>1</td><td><code>server/src/core/loop-controller.js</code> 存在且导出 loopController</td><td>✓ require 不报错</td></tr>
<tr><td>2</td><td><code>server/services/doc-store.js</code> 存在</td><td>✓</td></tr>
<tr><td>3</td><td><code>server/services/unit-registry.js</code> 存在</td><td>✓</td></tr>
<tr><td>4</td><td><code>server/services/sse-broker.js</code> 存在</td><td>✓</td></tr>
<tr><td>5</td><td><code>server/routes/devloop.js</code> 存在且 7 个端点全</td><td>✓ <code>curl /api/health</code> + grep</td></tr>
<tr><td>6</td><td><code>system/agents/devloop-{pm,architect,coder,tester,integrator,triager}/prompt.md</code> 全部存在</td><td>✓ ls 应见 6 个</td></tr>
<tr><td>7</td><td><code>system/agents/_registry.json</code> 含 devloop-* 六条</td><td>✓ grep</td></tr>
<tr><td>8</td><td><code>web/src/views/DevLoopDashboard.vue</code> + 7 个子组件</td><td>✓ ls web/src/components/devloop/</td></tr>
<tr><td>9</td><td>npm test 全绿</td><td>✓</td></tr>
<tr><td>10</td><td>POST /api/devloop/projects 60s 内生成 3 份文档</td><td>✓ file 存在</td></tr>
<tr><td>11</td><td>SSE 流持续推 unit.state 事件</td><td>✓ curl -N 看到</td></tr>
<tr><td>12</td><td>整套 DevLoop 能<b>对自己做增量</b>(用 DevLoop 给 DevLoop 加新需求)</td><td>✓ 元-自举测试</td></tr>
</tbody>
</table>
</section>
<section>
<h2>典型失败模式与诊断</h2>
<table class="dense">
<thead><tr><th>失败</th><th>诊断</th><th>修</th></tr></thead>
<tbody>
<tr><td>缺某个 MVCP 定义</td><td>build-manifest.json 该项空</td><td>检查对应 SDD 页是否漏 data-def-name</td></tr>
<tr><td>shape 抽不到</td><td>HTML class 不规范</td><td>用 pre.shape 不是 pre.code 也不是 pre.code.shape,统一</td></tr>
<tr><td>Claude Code 写出的代码风格与 LemonBoss 不一致</td><td>prompt 缺约束</td><td>在复现 prompt 顶部 require 它先读 CLAUDE.md</td></tr>
<tr><td>contract.json 与 SDD 不一致</td><td>Architect 没遵循 hashContract 算法</td><td>看 docs/prd/newfunction/api-contracts.html 第 4 节</td></tr>
<tr><td>L2 修复死循环</td><td>l2_budget 没设</td><td>project.json 默认值校验</td></tr>
<tr><td>SSE 不断重连</td><td>心跳没发</td><td>看 sse-broker.js 25s setInterval</td></tr>
</tbody>
</table>
</section>
<section>
<h2>「文档驱动」承诺</h2>
<div class="callout ok">
<b>这套 PRD + SDD 的一致性是项目本身的健康指标。</b>
<p style="margin:6px 0 0">如果未来某次实际代码与文档脱节超过 20%(脚本扫描 unit id 对齐率),系统会发 SSE 警告,提示要么改文档要么改代码。文档永远是 source of truth;代码是执行结果。</p>
</div>
</section>
<section>
<h2>下一步</h2>
<p>完成本页所述复现一次,相当于:</p>
<ul>
<li>✓ 验证 PRD + SDD 的<b>可执行性</b>(不只是写给人看)</li>
<li>✓ 验证 Claude Code + LemonBoss ACP 的<b>能力上限</b></li>
<li>✓ 给团队和投资人一个明确的<b>能力证明</b>(demo 时直接放复现录屏)</li>
</ul>
<p>复现成功的录屏 + 时间戳 + manifest hash 应保存在 <code>docs/prd/newfunction/repro-evidence/</code>,作为项目交付物的一部分。</p>
</section>
</article>
<nav class="prev-next"></nav>
<footer class="site"><div><b>Section</b>07 · Plan</div><div><b>Page</b>plan-reproducibility.html</div></footer>
</main>
</div>
<script src="assets/shell.js"></script>
</body>
</html>