loops-l3.html
7.83 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
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" />
<title>L3 · Human Feedback Loop · 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="loops-l3.html">
<div class="shell">
<aside id="sidebar"></aside>
<main class="page">
<header class="page-head">
<div class="crumb"><span class="pill">02 · LOOPS</span><span class="sep">/</span><span>L3 · Human</span></div>
<h1>L3 · Human Feedback Loop</h1>
<p class="deck">最外层。接收人类的新需求 / 反馈 / 否决,把它<b>合并进 PRD</b>,再让 Architect 重算 SDD diff,仅对增量 Unit 触发 L1 + L2。</p>
</header>
<article class="body">
<section>
<h2>状态机</h2>
<svg viewBox="0 0 1100 200" width="100%" role="img">
<defs><marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto"><path d="M0,0 L10,5 L0,10 Z" fill="#0E0E10"/></marker></defs>
<g font-family="JetBrains Mono" font-size="12" fill="#0E0E10">
<rect x="20" y="70" width="140" height="60" rx="4" fill="#ECE4FB" stroke="#6E48C3"/><text x="90" y="105" text-anchor="middle">human request</text>
<rect x="220" y="70" width="140" height="60" rx="4" fill="#fff" stroke="#0E0E10"/><text x="290" y="95" text-anchor="middle">PM Agent</text><text x="290" y="115" text-anchor="middle" font-size="10" fill="#3B3B40">+ patch PRD</text>
<rect x="420" y="70" width="140" height="60" rx="4" fill="#fff" stroke="#0E0E10"/><text x="490" y="95" text-anchor="middle">Architect</text><text x="490" y="115" text-anchor="middle" font-size="10" fill="#3B3B40">diff SDD</text>
<rect x="620" y="70" width="140" height="60" rx="4" fill="#fff" stroke="#0E0E10"/><text x="690" y="95" text-anchor="middle">unit diff</text><text x="690" y="115" text-anchor="middle" font-size="10" fill="#3B3B40">new / changed</text>
<rect x="820" y="70" width="140" height="60" rx="4" fill="#E2F2EA" stroke="#0E8C5A"/><text x="890" y="105" text-anchor="middle">→ L1 (incr.)</text>
<line x1="160" y1="100" x2="215" y2="100" stroke="#6E48C3" marker-end="url(#arr)"/>
<line x1="360" y1="100" x2="415" y2="100" stroke="#0E0E10" marker-end="url(#arr)"/>
<line x1="560" y1="100" x2="615" y2="100" stroke="#0E0E10" marker-end="url(#arr)"/>
<line x1="760" y1="100" x2="815" y2="100" stroke="#0E0E10" marker-end="url(#arr)"/>
</g>
</svg>
</section>
<section>
<h2>触发渠道</h2>
<div class="grid-3">
<div class="card l3">
<h4>① REST</h4>
<p><code>POST /api/devloop/projects/:pid/requirement</code><br/>JSON body 走 CLAUDE.md 推荐的 <code>-d @/tmp/req.json</code> 方式。</p>
</div>
<div class="card l3">
<h4>② Web UI</h4>
<p>DevLoopDashboard 右上角 <span class="kbd">+ NEW REQUIREMENT</span>,弹出 textarea。</p>
</div>
<div class="card l3">
<h4>③ 自动信号</h4>
<p>L1 <code>blocked</code> 或 L2 <code>exhausted</code> 时,LoopController 主动发 SSE,由前端弹「请补充信息」对话框。</p>
</div>
</div>
</section>
<section>
<h2>增量 Unit 算法</h2>
<p>Architect 对比新旧 <code>units.json</code>,标记三种变化:</p>
<table class="dense">
<thead><tr><th>变化类型</th><th>判断</th><th>处置</th></tr></thead>
<tbody>
<tr><td><b>added</b></td><td>新 unit.id 不在旧 list</td><td>status = pending,加入 L1 队列</td></tr>
<tr><td><b>changed</b></td><td>同 id,<code>contract_hash</code> 变化</td><td>status 回退到 pending,加入 L1 队列(旧代码归档到 <code>history/</code>)</td></tr>
<tr><td><b>removed</b></td><td>旧 id 不在新 list</td><td>整个 unit 目录归档到 <code>history/removed/</code>,从 DAG 摘除</td></tr>
<tr><td><b>unchanged</b></td><td>id 在且 hash 不变</td><td>保持 passed,<b>无须重跑</b>。这是增量化的关键</td></tr>
</tbody>
</table>
</section>
<section>
<h2>PRD 增量合并示例</h2>
<p>PM Agent 不重写整个 PRD,只追加 <code><section data-rev=N></code>,并维护 doc 级 <code>data-rev</code> 自增。这样人类能直观看到「这一轮反馈引入了什么」。</p>
<div class="tabs" data-tabs>
<div class="tabbar" role="tablist">
<button role="tab" aria-selected="true" aria-controls="t-before">prd.html · rev 2</button>
<button role="tab" aria-selected="false" aria-controls="t-after">prd.html · rev 3 (after feedback)</button>
</div>
<div class="tabpanel" id="t-before">
<pre class="code"><span class="k"><article</span> <span class="n">data-doc</span>=<span class="s">"prd"</span> <span class="n">data-rev</span>=<span class="s">"2"</span><span class="k">></span>
<span class="k"><section</span> <span class="n">data-rev</span>=<span class="s">"1"</span><span class="k">></span>
<span class="v">用户名密码登录,会话 7 天有效</span>
<span class="k"></section></span>
<span class="k"><section</span> <span class="n">data-rev</span>=<span class="s">"2"</span><span class="k">></span>
<span class="v">个人主页:显示用户名 / 邮箱</span>
<span class="k"></section></span>
<span class="k"></article></span></pre>
</div>
<div class="tabpanel" id="t-after" hidden>
<pre class="code"><span class="k"><article</span> <span class="n">data-doc</span>=<span class="s">"prd"</span> <span class="n">data-rev</span>=<span class="s">"3"</span><span class="k">></span>
<span class="k"><section</span> <span class="n">data-rev</span>=<span class="s">"1"</span><span class="k">></span>...<span class="k"></section></span>
<span class="k"><section</span> <span class="n">data-rev</span>=<span class="s">"2"</span><span class="k">></span>...<span class="k"></section></span>
<span class="k"><section</span> <span class="n">data-rev</span>=<span class="s">"3"</span> <span class="n">data-origin</span>=<span class="s">"yibo@2026-05-12T10:31"</span><span class="k">></span>
<span class="r">+</span> <span class="v">新增:支持 GitHub OAuth 登录</span>
<span class="r">+</span> <span class="v">NFR:3rd-party token 刷新 ≤ 5s</span>
<span class="k"></section></span>
<span class="k"></article></span></pre>
</div>
</div>
</section>
<section>
<h2>什么时候算「项目结束」</h2>
<p>L3 没有自动退出条件。结束信号来自人类的显式动作:</p>
<ul>
<li><b>显式 sign-off:</b><code>POST /api/devloop/projects/:pid/sign-off</code> → 项目 status 置 <code>shipped-final</code>,停止接收新需求。</li>
<li><b>归档:</b>30 天无人类反馈,自动归档但保留所有产物。</li>
<li><b>放弃:</b><code>POST .../abandon</code>,整个项目目录加 <code>.abandoned</code> 标记,从 Dashboard 列表移除。</li>
</ul>
</section>
</article>
<nav class="prev-next"></nav>
<footer class="site"><div><b>Section</b>02 · Loops</div><div><b>Page</b>loops-l3.html</div></footer>
</main>
</div>
<script src="assets/shell.js"></script>
</body>
</html>