xp-gate 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adapter-common.sh +192 -0
- package/adapters/cpp.sh +76 -0
- package/adapters/dart.sh +41 -0
- package/adapters/flutter.sh +41 -0
- package/adapters/go.sh +59 -0
- package/adapters/iac.sh +189 -0
- package/adapters/java.sh +191 -0
- package/adapters/kotlin.sh +77 -0
- package/adapters/objectivec.sh +38 -0
- package/adapters/powershell.sh +138 -0
- package/adapters/python.sh +104 -0
- package/adapters/shell.sh +55 -0
- package/adapters/swift.sh +44 -0
- package/adapters/typescript.sh +61 -0
- package/bin/xp-gate.js +157 -0
- package/hooks/adapter-common.sh +192 -0
- package/hooks/pre-commit +1667 -0
- package/hooks/pre-push +395 -0
- package/lib/__tests__/detect-deps.test.js +209 -0
- package/lib/__tests__/doctor.test.js +448 -0
- package/lib/__tests__/download-skill.test.js +281 -0
- package/lib/__tests__/init.test.js +327 -0
- package/lib/__tests__/install-skill.test.js +326 -0
- package/lib/__tests__/migrate.test.js +212 -0
- package/lib/__tests__/rollback.test.js +183 -0
- package/lib/__tests__/ui-detector.test.ts +200 -0
- package/lib/__tests__/uninstall-skill.test.js +189 -0
- package/lib/__tests__/uninstall.test.js +589 -0
- package/lib/__tests__/update-skill.test.js +276 -0
- package/lib/detect-deps.js +157 -0
- package/lib/doctor.js +370 -0
- package/lib/download-skill.js +96 -0
- package/lib/init.js +367 -0
- package/lib/install-skill.js +184 -0
- package/lib/migrate.js +120 -0
- package/lib/rollback.js +78 -0
- package/lib/ui-detector.ts +99 -0
- package/lib/uninstall-skill.js +69 -0
- package/lib/uninstall.js +401 -0
- package/lib/update-skill.js +90 -0
- package/package.json +39 -0
- package/plugins/claude-code/.claude-plugin/plugin.json +21 -0
- package/plugins/claude-code/bin/delphi-review-guard.sh +68 -0
- package/plugins/claude-code/bin/xp-gate-check +47 -0
- package/plugins/claude-code/hooks/hooks.json +37 -0
- package/skills/delphi-review/.delphi-config.json.example +45 -0
- package/skills/delphi-review/AGENTS.md +54 -0
- package/skills/delphi-review/INSTALL.md +152 -0
- package/skills/delphi-review/SKILL.md +371 -0
- package/skills/delphi-review/evals/evals.json +82 -0
- package/skills/delphi-review/opencode.json.delphi.example +56 -0
- package/skills/delphi-review/references/code-walkthrough.md +486 -0
- package/skills/ralph-loop/SKILL.md +330 -0
- package/skills/ralph-loop/evals/evals.json +311 -0
- package/skills/ralph-loop/evolution-history.json +59 -0
- package/skills/ralph-loop/evolution-log.md +16 -0
- package/skills/ralph-loop/references/components/memory.md +55 -0
- package/skills/ralph-loop/references/components/middleware.md +54 -0
- package/skills/ralph-loop/references/components/skill-invocations.md +39 -0
- package/skills/ralph-loop/references/components/system-prompt.md +24 -0
- package/skills/ralph-loop/references/components/tool-descriptions.md +32 -0
- package/skills/ralph-loop/references/phase-2-build-ralph.md +89 -0
- package/skills/ralph-loop/templates/progress-log.md +36 -0
- package/skills/sprint-flow/SKILL.md +600 -0
- package/skills/sprint-flow/evals/evals.json +78 -0
- package/skills/sprint-flow/evolution-history.json +39 -0
- package/skills/sprint-flow/evolution-log.md +23 -0
- package/skills/sprint-flow/references/components/memory.md +87 -0
- package/skills/sprint-flow/references/components/middleware.md +72 -0
- package/skills/sprint-flow/references/components/skill-invocations.md +104 -0
- package/skills/sprint-flow/references/components/system-prompt.md +27 -0
- package/skills/sprint-flow/references/components/tool-descriptions.md +96 -0
- package/skills/sprint-flow/references/phase-0-think.md +115 -0
- package/skills/sprint-flow/references/phase-1-plan.md +178 -0
- package/skills/sprint-flow/references/phase-2-build.md +198 -0
- package/skills/sprint-flow/references/phase-3-review.md +213 -0
- package/skills/sprint-flow/references/phase-4-uat.md +125 -0
- package/skills/sprint-flow/references/phase-5-feedback.md +100 -0
- package/skills/sprint-flow/references/phase-6-ship.md +193 -0
- package/skills/sprint-flow/references/phase-7-land.md +140 -0
- package/skills/sprint-flow/references/phase-8-cleanup.md +192 -0
- package/skills/sprint-flow/templates/emergent-issues-template.md +120 -0
- package/skills/sprint-flow/templates/pain-document-template.md +115 -0
- package/skills/sprint-flow/templates/sprint-summary-template.md +120 -0
- package/skills/test-specification-alignment/AGENTS.md +59 -0
- package/skills/test-specification-alignment/SKILL.md +605 -0
- package/skills/test-specification-alignment/evals/evals.json +75 -0
- package/skills/test-specification-alignment/references/alignment-verification-algorithm.md +493 -0
- package/skills/test-specification-alignment/references/phase2-constraint-enforcement.md +431 -0
- package/skills/test-specification-alignment/references/specification-format.md +348 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ralph-loop
|
|
3
|
+
description: >
|
|
4
|
+
Default Phase 2 BUILD mode for Sprint-Flow. Processes ONE REQ at a time from
|
|
5
|
+
specification.yaml with clean isolated context per subagent dispatch, persists
|
|
6
|
+
memory via git history + classified learnings, runs full regression tests on each
|
|
7
|
+
REQ, and only commits on verification pass. Designed to reduce token consumption
|
|
8
|
+
from linear context accumulation to per-REQ fixed budgets (40-67% savings).
|
|
9
|
+
Token-constraint is the default — every Phase 2 uses this mode automatically.
|
|
10
|
+
Use `--mode parallel` to opt into the legacy all-at-once mode if needed.
|
|
11
|
+
maturity: stable
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Ralph Loop — Default REQ-Level Iterative Build
|
|
15
|
+
|
|
16
|
+
## 核心原则
|
|
17
|
+
|
|
18
|
+
| 原则 | 说明 |
|
|
19
|
+
|------|------|
|
|
20
|
+
| **每次迭代 = 全新上下文** | 每个 REQ dispatch 独立 subagent,不累积历史对话 |
|
|
21
|
+
| **一次只处理一个 REQ** | 小粒度执行,避免大任务吞掉整个 context window |
|
|
22
|
+
| **失败不提交** | 验证不通过的代码不 commit,保持代码库绿色 |
|
|
23
|
+
| **全量回归测试** | 每个 REQ 完成后运行 ALL tests(不只是 @test REQ-XXX),检测跨 REQ 回归 |
|
|
24
|
+
| **Git 持久记忆** | 代码变更 + checkpoint 天然持久,不需要在 prompt 里反复解释 |
|
|
25
|
+
| **浓缩型分类学习** | permanent(架构级)+ contextual(最近 3 条)双层 learnings |
|
|
26
|
+
| **AGENTS.md 统一更新** | orchestrator 统一写,subagent 不直接修改 — 无竞态 |
|
|
27
|
+
|
|
28
|
+
## 作为 Phase 2 默认行为
|
|
29
|
+
|
|
30
|
+
Ralph Loop 是 Sprint-Flow **Phase 2 BUILD 的默认模式**:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
Sprint-Flow Phase 2 (默认):
|
|
34
|
+
ralph-loop → 逐 REQ 迭代 → 每次干净上下文 → 全量回归 → token 节约 40-67%
|
|
35
|
+
|
|
36
|
+
Sprint-Flow Phase 2 --mode parallel (可选):
|
|
37
|
+
dispatching-parallel-agents → 所有需求一次性并行 → 上下文线性增长
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**为什么它是默认**: 每个 Sprint 都受 token limit 约束。累积模式在 3+ REQs 时限流频率显著上升。ralph-loop 确保每个 REQ 的 token 预算独立可控。
|
|
41
|
+
|
|
42
|
+
**切换回并行模式**: `/sprint-flow "需求" --mode parallel`
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 完整流程
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
Phase 0: 准备 → 读取 specification.yaml → 构建依赖图 → 拓扑排序
|
|
50
|
+
│
|
|
51
|
+
▼
|
|
52
|
+
Phase 1: 迭代循环 (max_iterations=15 默认)
|
|
53
|
+
│
|
|
54
|
+
├── 取下一个 READY REQ(依赖已满足,优先级最高)
|
|
55
|
+
│
|
|
56
|
+
├── 测试基础设施检查
|
|
57
|
+
│ 1. 检查 test-utils.ts(或等效文件)是否存在
|
|
58
|
+
│ 2. 检查必需接口契约:createTestApp()、withTestDb()
|
|
59
|
+
│ 3. 不存在或接口缺失 → dispatch "生成测试基础设施" subagent
|
|
60
|
+
│ retry max 2 → 仍失败 → BLOCK 或 fallback inline 生成
|
|
61
|
+
│ 4. 与业务代码合并为同一 commit
|
|
62
|
+
│
|
|
63
|
+
├── 注入测试基础设施摘要到业务代码 subagent context:
|
|
64
|
+
│ 【已有测试基础设施】test-utils.ts 已存在,导出以下 API:
|
|
65
|
+
│ - createTestApp(): 创建应用实例 + 真实测试依赖
|
|
66
|
+
│ - withTestDb(): 测试数据库生命周期(seed + cleanup)
|
|
67
|
+
│ 必须 import 这些函数,禁止重新手搓同名 helper。
|
|
68
|
+
│
|
|
69
|
+
├── Dispatch 独立 subagent
|
|
70
|
+
│ 使用: task(category="unspecified-high", load_skills=["test-driven-development"], timeout=300)
|
|
71
|
+
│ Context:
|
|
72
|
+
│ - 当前 REQ + 所有 AC
|
|
73
|
+
│ - permanent learnings(架构决策,始终传入)
|
|
74
|
+
│ - contextual learnings(最近 3 条)
|
|
75
|
+
│ - retry-failures(仅 retry 时注入失败原因)
|
|
76
|
+
│ - AGENTS.md(项目约定)
|
|
77
|
+
│ - git log --oneline -5
|
|
78
|
+
│ - 【TDD 铁律】RED → GREEN → REFACTOR。任何模块必须先写测试再写实现。
|
|
79
|
+
│ - 【Mock 边界】(覆盖 TDD skill 默认策略)
|
|
80
|
+
│ ✅ MOCK: 外部 HTTP API、LLM 调用、第三方平台(钉钉/微信)
|
|
81
|
+
│ ✅ MOCK: 时间/随机数/UUID(注入依赖)
|
|
82
|
+
│ ❌ NO MOCK: 数据库操作(用真实测试库或 sqlite-in-memory)
|
|
83
|
+
│ ❌ NO MOCK: HTTP 路由(用 app.inject() 真实注入)
|
|
84
|
+
│ ❌ NO MOCK: 模板引擎(用真实 Nunjucks/Jinja 渲染)
|
|
85
|
+
│ ❌ NO MOCK: 纯业务逻辑(用真实输入输出)
|
|
86
|
+
│ - 【Mock 密度上限】测试中 mock/spy/fn 引用行数 > 总测试行数 30% 时,
|
|
87
|
+
│ 必须添加 // @mock-justified: <至少10字符理由> 注释说明为何无法用集成测试。
|
|
88
|
+
│
|
|
89
|
+
├── Subagent 完成 → 三层验证
|
|
90
|
+
│ ├── L1: typecheck + lint → FAIL? → retry
|
|
91
|
+
│ ├── L2: 全量测试(ALL tests)→ FAIL? → retry
|
|
92
|
+
│ └── L3: coverage ≥ 80% → FAIL? → retry
|
|
93
|
+
│
|
|
94
|
+
├── PASS → git commit → 标记 done
|
|
95
|
+
│ → 写 learnings(分类为 permanent/contextual)
|
|
96
|
+
│ → 调用 `gstack/learn` 及时总结经验教训
|
|
97
|
+
│ → orchestrator 统一更新 AGENTS.md
|
|
98
|
+
│ → 原子写 checkpoint
|
|
99
|
+
│ → 继续下一个 READY REQ
|
|
100
|
+
│
|
|
101
|
+
└── FAIL → retry(max 3,注入上次错误摘要)
|
|
102
|
+
└── 仍失败 → BLOCK → 依赖级联 → 用户决策
|
|
103
|
+
│
|
|
104
|
+
▼
|
|
105
|
+
终止条件:
|
|
106
|
+
- 所有 REQ done → COMPLETE → 返回 Phase 3 REVIEW
|
|
107
|
+
- max_iterations 达到 → PARTIAL → 保留 done commits
|
|
108
|
+
- BLOCK → WAIT_USER → skip/manual/stop/rollback
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## 输入格式 (specification.yaml)
|
|
114
|
+
|
|
115
|
+
```yaml
|
|
116
|
+
specification:
|
|
117
|
+
requirements:
|
|
118
|
+
- id: REQ-001
|
|
119
|
+
description: "创建 User Model 和数据库迁移"
|
|
120
|
+
acceptance_criteria:
|
|
121
|
+
- id: AC-001-01
|
|
122
|
+
criteria: "User model 包含 email (unique), password_hash, created_at"
|
|
123
|
+
- id: AC-001-02
|
|
124
|
+
criteria: "Migration 成功执行"
|
|
125
|
+
priority: 1
|
|
126
|
+
status: pending
|
|
127
|
+
|
|
128
|
+
- id: REQ-002
|
|
129
|
+
description: "实现密码加密工具函数"
|
|
130
|
+
depends_on: [REQ-001]
|
|
131
|
+
acceptance_criteria:
|
|
132
|
+
- id: AC-002-01
|
|
133
|
+
criteria: "hashPassword() 返回 bcrypt hash"
|
|
134
|
+
- id: AC-002-02
|
|
135
|
+
criteria: "verifyPassword() 正确比对明文和 hash"
|
|
136
|
+
priority: 2
|
|
137
|
+
status: pending
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**每个 REQ 自动作为一个迭代单元**,其所有 `AC-XXX-XX` 作为验收标准。
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 依赖排序
|
|
145
|
+
|
|
146
|
+
1. **拓扑排序**:对所有 pending REQs 构建依赖图(基于 `depends_on`)
|
|
147
|
+
2. **Kahn's algorithm**:执行拓扑排序,检测循环依赖
|
|
148
|
+
3. **同层按 priority**:同一拓扑层内的 REQ 按 `priority` 升序排列
|
|
149
|
+
4. **循环依赖**:→ BLOCK + 报告循环链(`REQ-A → REQ-B → REQ-C → REQ-A`)
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Learnings 分类
|
|
154
|
+
|
|
155
|
+
| 分类 | 内容 | 传递策略 | 升级条件 |
|
|
156
|
+
|------|------|---------|---------|
|
|
157
|
+
| **permanent** | 架构决策、接口约定、全局约定 | 始终传入(每个 REQ context)| (1) 被 ≥2 个 REQ 引用<br>(2) 涉及模块接口/数据结构<br>(3) 用户手动标记 |
|
|
158
|
+
| **contextual** | 实现细节、一次性 gotchas、临时技巧 | 滑动窗口(最近 3 条) | 满足 permanent 条件自动升级,否则 3 条后过期 |
|
|
159
|
+
|
|
160
|
+
**自动升级示例**:
|
|
161
|
+
- `"migration files must be in src/migrations/"` → 第 2 个 REQ 也引用 → 升级为 permanent
|
|
162
|
+
- `"use bcrypt 不要使用 md5"` → 安全规范 → 自动 permanent
|
|
163
|
+
- `"第 42 行有个 off-by-one"` → 仅影响单个 REQ → 保持 contextual
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## AGENTS.md 更新机制
|
|
168
|
+
|
|
169
|
+
**由 orchestrator 统一执行,不由 subagent 各自写**:
|
|
170
|
+
|
|
171
|
+
1. subagent 完成后输出 `agentmd_addition` 字段
|
|
172
|
+
2. orchestrator 读取当前 AGENTS.md
|
|
173
|
+
3. orchestrator append `## ralph-loop: [REQ-XXX title] (auto-added)` 段
|
|
174
|
+
4. orchestrator 将 AGENTS.md 变更纳入 git commit
|
|
175
|
+
|
|
176
|
+
当 AGENTS.md > 500 行时触发归档:保留最近 6 个月 entries,更早的归档到 `.sprint-state/ralph-loop/agents-archive/`。
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## 三层验证 Gate
|
|
181
|
+
|
|
182
|
+
每个 REQ 完成后执行:
|
|
183
|
+
|
|
184
|
+
| 层级 | 范围 | 工具 | 失败行为 |
|
|
185
|
+
|------|------|------|---------|
|
|
186
|
+
| L1 | 变更文件 | `lsp_diagnostics` + linter | retry |
|
|
187
|
+
| L1b | 测试先行比率 | 新增测试行数 / (新增测试 + 新增实现) ≥ 40% | retry |
|
|
188
|
+
| L2 | **全量测试**(不只是 @test REQ-XXX) | 项目测试框架 | retry |
|
|
189
|
+
| L3 | 整体覆盖率 ≥ 80% | coverage report | retry |
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## 状态机
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
PENDING → test_infra_check → [infra needed?] → test_infra_dispatch
|
|
197
|
+
│ │
|
|
198
|
+
│ FAIL │ pass
|
|
199
|
+
│ (max 2 retry) │
|
|
200
|
+
▼ ▼
|
|
201
|
+
BLOCK/fallback test_infra_ready → in_progress → done (commit)
|
|
202
|
+
│ │
|
|
203
|
+
│ depend not met │ all done → COMPLETE
|
|
204
|
+
│ ┌───────────────┘
|
|
205
|
+
▼ │
|
|
206
|
+
PENDING (waiting)
|
|
207
|
+
│
|
|
208
|
+
│ fail
|
|
209
|
+
▼
|
|
210
|
+
RETRY (n≤3, 注入上次错误)
|
|
211
|
+
│
|
|
212
|
+
│ n≥3
|
|
213
|
+
▼
|
|
214
|
+
BLOCKED → 用户决策 (skip/manual/stop/rollback)
|
|
215
|
+
│
|
|
216
|
+
│ 依赖上游 blocked → 自动 blocked(含依赖链)
|
|
217
|
+
▼
|
|
218
|
+
auto-blocked REQs
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**REQ 状态转换规则**:
|
|
222
|
+
|
|
223
|
+
| 从 | 到 | 触发 |
|
|
224
|
+
|---|---|---|
|
|
225
|
+
| pending | test_infra_check | 拓扑排序轮到 + 依赖已满足 |
|
|
226
|
+
| test_infra_check | test_infra_dispatch | test-utils.ts 不存在或接口缺失 |
|
|
227
|
+
| test_infra_check | in_progress | test-utils.ts 已存在且接口完整 |
|
|
228
|
+
| test_infra_dispatch | test_infra_ready | 测试基础设施生成完成 |
|
|
229
|
+
| test_infra_dispatch | blocked | retry max 2 仍失败 |
|
|
230
|
+
| test_infra_dispatch | test_infra_ready | fallback inline 生成成功(记录 warning)|
|
|
231
|
+
| test_infra_ready | in_progress | 测试基础设施就绪,dispatch 业务代码 subagent |
|
|
232
|
+
| in_progress | done | L1+L1b+L2+L3 全部通过 |
|
|
233
|
+
| in_progress | retry | 验证失败, n<3 |
|
|
234
|
+
| retry | done | 验证通过 |
|
|
235
|
+
| retry | blocked | n≥3 仍失败 |
|
|
236
|
+
| pending | blocked(auto) | 上游依赖 blocked |
|
|
237
|
+
| blocked | skipped | 用户选择跳过 |
|
|
238
|
+
| blocked | done | 用户手动修复后确认 |
|
|
239
|
+
| 任意 | partial | 用户选择停止 |
|
|
240
|
+
| 任意 | rollback | 用户选择回滚 (git reset) |
|
|
241
|
+
|
|
242
|
+
**崩溃恢复**:启动时检测 checkpoint → 跳过已 done REQs → 从下一个 pending 继续。已 commit 的 REQ 不需要重做。
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Retry 策略
|
|
247
|
+
|
|
248
|
+
| 轮次 | 注入上下文 | 超时 |
|
|
249
|
+
|------|-----------|------|
|
|
250
|
+
| 第 1 次 | 标准上下文 | 300s |
|
|
251
|
+
| 第 2 次 | 标准 + 上次失败摘要 (linter+tests) | 300s |
|
|
252
|
+
| 第 3 次 | 标准 + 前两次失败摘要 + "请使用不同实现方式" | 300s |
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## 与 Sprint-Flow 集成
|
|
257
|
+
|
|
258
|
+
**默认启用**:Phase 2 BUILD 自动使用 ralph-loop 模式。
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
/sprint-flow "开发用户登录"
|
|
262
|
+
# → Phase 2 自动使用 ralph-loop 模式
|
|
263
|
+
|
|
264
|
+
/sprint-flow "开发小改动" --mode parallel
|
|
265
|
+
# → 可选:切换回旧有的并行模式
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Phase 0, 1, 3-6 行为完全不变。
|
|
269
|
+
|
|
270
|
+
**与 test-specification-alignment 完全兼容**:
|
|
271
|
+
- Test alignment 仍解析 specification.yaml (REQ/AC 不变)
|
|
272
|
+
- 仍查找 `@test REQ-XXX` / `@covers AC-XXX-XX`
|
|
273
|
+
- PARTIAL 状态下仅检查已 done REQs
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## Output Format (MANDATORY)
|
|
278
|
+
|
|
279
|
+
```json
|
|
280
|
+
{
|
|
281
|
+
"skill_name": "ralph-loop",
|
|
282
|
+
"version": "2.0.0",
|
|
283
|
+
"specification_source": "specification.yaml",
|
|
284
|
+
"topology_order": ["REQ-001", "REQ-002", "REQ-003"],
|
|
285
|
+
"requirements": { "total": 6, "done": 4, "pending": 1, "blocked": 1, "skipped": 0 },
|
|
286
|
+
"current_requirement": { "id": "REQ-005", "status": "done", "retry_count": 0 },
|
|
287
|
+
"learnings": {
|
|
288
|
+
"permanent": ["Auth middleware must run before validation"],
|
|
289
|
+
"contextual": ["migration files must be in src/migrations/"]
|
|
290
|
+
},
|
|
291
|
+
"status": "running",
|
|
292
|
+
"checkpoint_at": "2026-05-08T10:30:00Z"
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Eval assertions**: `done + pending + blocked + skipped == total`, `iteration <= max_iterations`.
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Anti-Patterns
|
|
301
|
+
|
|
302
|
+
| ❌ 错误 | ✅ 正确 |
|
|
303
|
+
|---|---|
|
|
304
|
+
| 一个 REQ 包含所有需求 | 每个 REQ ≤ 1 context window |
|
|
305
|
+
| 验证失败仍 commit | 不提交 |
|
|
306
|
+
| 只跑 @test REQ-XXX | 全量回归测试 |
|
|
307
|
+
| priority 排序忽略 depends_on | 拓扑排序 + 同层 priority |
|
|
308
|
+
| retry 不注入失败原因 | 每次 retry 注入上次错误 |
|
|
309
|
+
| subagent 各自写 AGENTS.md | orchestrator 统一更新 |
|
|
310
|
+
| progress.log 写长篇大论 | 3-5 行结构化摘要 |
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## Token Savings
|
|
315
|
+
|
|
316
|
+
| REQ 数量 | 默认模式 | ralph-loop | 节约 |
|
|
317
|
+
|---------|---------|-----------|------|
|
|
318
|
+
| 3 | ~15k | ~9k | 40% |
|
|
319
|
+
| 5 | ~50k | ~25k | 50% |
|
|
320
|
+
| 10 | ~150k | ~50k | 67% |
|
|
321
|
+
|
|
322
|
+
> 原理: 默认 = sum(i × cost_i), ralph-loop = sum(cost_i)
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## References
|
|
327
|
+
|
|
328
|
+
- [Design Doc: ralph-loop v3.0](docs/ralph-loop-design.md) — 完整设计文档 + Delphi 评审记录
|
|
329
|
+
- [Phase 2 Integration](references/phase-2-build-ralph.md) — Sprint-Flow 集成细节
|
|
330
|
+
- [Progress Log Template](templates/progress-log.md)
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "ralph-001",
|
|
4
|
+
"name": "specification.yaml 作为输入源验证",
|
|
5
|
+
"description": "验证 ralph-loop 使用 specification.yaml 中的 REQ 作为迭代单元,而非 stories.json",
|
|
6
|
+
"input": {
|
|
7
|
+
"specification": {
|
|
8
|
+
"requirements": [
|
|
9
|
+
{ "id": "REQ-001", "description": "创建 User Model", "acceptance_criteria": [{ "id": "AC-001-01", "criteria": "email unique" }], "status": "pending" },
|
|
10
|
+
{ "id": "REQ-002", "description": "实现密码加密", "depends_on": ["REQ-001"], "status": "pending" }
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"expected": {
|
|
15
|
+
"input_source": "specification.yaml",
|
|
16
|
+
"iteration_units": ["REQ-001", "REQ-002"],
|
|
17
|
+
"no_stories_json": true
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "ralph-002",
|
|
22
|
+
"name": "拓扑排序 + 依赖顺序",
|
|
23
|
+
"description": "验证 REQ 按 depends_on 拓扑排序,同层按 priority 升序",
|
|
24
|
+
"input": {
|
|
25
|
+
"requirements": [
|
|
26
|
+
{ "id": "REQ-003", "depends_on": ["REQ-002"], "priority": 3 },
|
|
27
|
+
{ "id": "REQ-001", "depends_on": [], "priority": 1 },
|
|
28
|
+
{ "id": "REQ-002", "depends_on": ["REQ-001"], "priority": 2 }
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
"expected": {
|
|
32
|
+
"sorted_order": ["REQ-001", "REQ-002", "REQ-003"],
|
|
33
|
+
"algorithm": "Kahn's topological sort"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": "ralph-003",
|
|
38
|
+
"name": "循环依赖检测",
|
|
39
|
+
"description": "REQ 存在循环依赖时 → BLOCK + 报告循环链",
|
|
40
|
+
"input": {
|
|
41
|
+
"requirements": [
|
|
42
|
+
{ "id": "REQ-001", "depends_on": ["REQ-002"] },
|
|
43
|
+
{ "id": "REQ-002", "depends_on": ["REQ-003"] },
|
|
44
|
+
{ "id": "REQ-003", "depends_on": ["REQ-001"] }
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
"expected": {
|
|
48
|
+
"status": "blocked",
|
|
49
|
+
"cycle_detected": true,
|
|
50
|
+
"cycle_chain": "REQ-001 → REQ-002 → REQ-003 → REQ-001"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "ralph-004",
|
|
55
|
+
"name": "Learnings 双层分类 — permanent 自动升级",
|
|
56
|
+
"description": "被 ≥2 个 REQ 引用的 learnings 自动升级为 permanent",
|
|
57
|
+
"input": {
|
|
58
|
+
"learnings": [
|
|
59
|
+
{ "id": 1, "text": "migration files in src/migrations/", "ref_count": 1, "scope": "contextual" },
|
|
60
|
+
{ "id": 2, "text": "Auth middleware before validation", "ref_count": 3, "scope": "interface" }
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"expected": {
|
|
64
|
+
"permanent": [
|
|
65
|
+
{ "id": 2, "reason": "ref_count >= 2 AND scope == interface" }
|
|
66
|
+
],
|
|
67
|
+
"contextual": [
|
|
68
|
+
{ "id": 1, "reason": "ref_count < 2 AND scope != interface" }
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"id": "ralph-005",
|
|
74
|
+
"name": "Subagent 上下文隔离 — 不传递历史对话",
|
|
75
|
+
"description": "每个 subagent context 仅包含:当前 REQ + AC + permanent/contextual/retry-failures + AGENTS.md + git log -5",
|
|
76
|
+
"input": {
|
|
77
|
+
"current_req": "REQ-003",
|
|
78
|
+
"learnings": { "permanent": ["rule1"], "contextual": ["tip1", "tip2"] },
|
|
79
|
+
"agents_md": "project conventions",
|
|
80
|
+
"git_log": "commit1, commit2"
|
|
81
|
+
},
|
|
82
|
+
"expected": {
|
|
83
|
+
"context_sources": ["current_req", "acceptance_criteria", "permanent_learnings", "contextual_learnings", "agents_md", "git_log"],
|
|
84
|
+
"no_historical_dialogue": true,
|
|
85
|
+
"context_is_bounded": true
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"id": "ralph-006",
|
|
90
|
+
"name": "三层验证 Gate — 失败不提交",
|
|
91
|
+
"description": "验证失败 → 不 commit → retry(L1: typecheck+lint, L2: all tests, L3: coverage)",
|
|
92
|
+
"input": {
|
|
93
|
+
"verification": { "l1": "fail", "l2": "skipped", "l3": "skipped" },
|
|
94
|
+
"retry_count": 0,
|
|
95
|
+
"max_retries": 3
|
|
96
|
+
},
|
|
97
|
+
"expected": {
|
|
98
|
+
"committed": false,
|
|
99
|
+
"retry": true,
|
|
100
|
+
"new_retry_count": 1,
|
|
101
|
+
"run_all_tests_on_next_try": true
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"id": "ralph-007",
|
|
106
|
+
"name": "全量回归测试 — 不只跑 @test REQ-XXX",
|
|
107
|
+
"description": "REQ-003 完成后,L2 验证跑 ALL tests(包括 @test REQ-001, @test REQ-002),不只跑 @test REQ-003",
|
|
108
|
+
"input": {
|
|
109
|
+
"current_req": "REQ-003",
|
|
110
|
+
"available_tests": ["test_REQ-001", "test_REQ-002", "test_REQ-003"],
|
|
111
|
+
"test_scope": "all"
|
|
112
|
+
},
|
|
113
|
+
"expected": {
|
|
114
|
+
"tests_run": ["test_REQ-001", "test_REQ-002", "test_REQ-003"],
|
|
115
|
+
"scope": "full_regression",
|
|
116
|
+
"not_just_current_req": true
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"id": "ralph-008",
|
|
121
|
+
"name": "Retry 失败上下文注入",
|
|
122
|
+
"description": "retry 时注入上次失败的错误摘要,不是重复相同上下文",
|
|
123
|
+
"input": {
|
|
124
|
+
"retry_count": 1,
|
|
125
|
+
"last_failure": { "linter": ["unused-var at line 42"], "tests": ["test_login fails: 401 != 200"] }
|
|
126
|
+
},
|
|
127
|
+
"expected": {
|
|
128
|
+
"context_extended": true,
|
|
129
|
+
"failure_summary": "Linter: unused-var at line 42. Tests: test_login fails",
|
|
130
|
+
"instruction": "请使用不同的实现方式"
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"id": "ralph-009",
|
|
135
|
+
"name": "BLOCK 状态 — 依赖级联",
|
|
136
|
+
"description": "上游 REQ-001 blocked → REQ-002, REQ-003 自动 blocked(含依赖链)",
|
|
137
|
+
"input": {
|
|
138
|
+
"requirements": [
|
|
139
|
+
{ "id": "REQ-001", "status": "blocked", "reason": "max_retry_exceeded" },
|
|
140
|
+
{ "id": "REQ-002", "depends_on": ["REQ-001"], "status": "pending" },
|
|
141
|
+
{ "id": "REQ-003", "depends_on": ["REQ-002"], "status": "pending" }
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
"expected": {
|
|
145
|
+
"REQ-001_status": "blocked",
|
|
146
|
+
"REQ-002_status": "blocked(auto)",
|
|
147
|
+
"REQ-003_status": "blocked(auto)",
|
|
148
|
+
"dependency_chain": "REQ-001(blocked) → REQ-002 → REQ-003"
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"id": "ralph-010",
|
|
153
|
+
"name": "PARTIAL 状态行为",
|
|
154
|
+
"description": "部分完成时:已 done commits 保留,Phase 3 仅检查 done REQs",
|
|
155
|
+
"input": {
|
|
156
|
+
"reqs_done": 4,
|
|
157
|
+
"reqs_total": 6,
|
|
158
|
+
"reqs_blocked": 1,
|
|
159
|
+
"reqs_skipped": 1,
|
|
160
|
+
"status": "partial"
|
|
161
|
+
},
|
|
162
|
+
"expected": {
|
|
163
|
+
"commits_retained": true,
|
|
164
|
+
"phase3_scope": "done_reqs_only",
|
|
165
|
+
"spec_alignment_scope": "partial",
|
|
166
|
+
"report": "4/6 REQ 完成,1 blocked,1 skipped"
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"id": "ralph-011",
|
|
171
|
+
"name": "AGENTS.md 由 orchestrator 统一更新",
|
|
172
|
+
"description": "subagent 不直接写 AGENTS.md,输出 agentmd_addition 字段给 orchestrator",
|
|
173
|
+
"input": {
|
|
174
|
+
"subagent_output": { "agentmd_addition": "## ralph-loop: REQ-003 (api endpoint)\n- Patterns: REST CRUD" },
|
|
175
|
+
"orchestrator_action": "read_agents_md → append → commit"
|
|
176
|
+
},
|
|
177
|
+
"expected": {
|
|
178
|
+
"agens_md_updated_by": "orchestrator",
|
|
179
|
+
"no_subagent_direct_write": true,
|
|
180
|
+
"no_race_condition": true
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"id": "ralph-012",
|
|
185
|
+
"name": "状态输出格式 — v3.0",
|
|
186
|
+
"description": "输出 JSON 必须符合 v3.0 state format",
|
|
187
|
+
"input": {
|
|
188
|
+
"output": {
|
|
189
|
+
"skill_name": "ralph-loop",
|
|
190
|
+
"version": "2.0.0",
|
|
191
|
+
"specification_source": "specification.yaml",
|
|
192
|
+
"requirements": { "total": 6, "done": 2, "pending": 3, "blocked": 1, "skipped": 0 },
|
|
193
|
+
"learnings": { "permanent": ["..."], "contextual": ["..."] },
|
|
194
|
+
"topology_order": ["REQ-001", "REQ-002", "REQ-003"]
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
"expected": {
|
|
198
|
+
"valid": true,
|
|
199
|
+
"assertions": [
|
|
200
|
+
"done + pending + blocked + skipped == total",
|
|
201
|
+
"learnings has permanent and contextual arrays",
|
|
202
|
+
"topology_order exists and is non-empty"
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"id": "ralph-013",
|
|
208
|
+
"name": "崩溃恢复 — checkpoint 机制",
|
|
209
|
+
"description": "主进程崩溃后,从 checkpoint 恢复,跳过已 done REQs",
|
|
210
|
+
"input": {
|
|
211
|
+
"checkpoint": {
|
|
212
|
+
"iteration": 3,
|
|
213
|
+
"done_reqs": ["REQ-001", "REQ-002"],
|
|
214
|
+
"last_commit": "ralph-loop: REQ-002"
|
|
215
|
+
},
|
|
216
|
+
"recover_from": "crash"
|
|
217
|
+
},
|
|
218
|
+
"expected": {
|
|
219
|
+
"next_req": "REQ-003",
|
|
220
|
+
"skip_reqs": ["REQ-001", "REQ-002"],
|
|
221
|
+
"commits_retained": true,
|
|
222
|
+
"no_redo_committed": true
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"id": "ralph-014",
|
|
227
|
+
"name": "REQ 粒度过大检测",
|
|
228
|
+
"description": "REQ 超时 2 次后 BLOCK + 提示用户拆分",
|
|
229
|
+
"input": {
|
|
230
|
+
"req": "REQ-004",
|
|
231
|
+
"timeout_count": 2,
|
|
232
|
+
"max_timeout": 300
|
|
233
|
+
},
|
|
234
|
+
"expected": {
|
|
235
|
+
"status": "blocked",
|
|
236
|
+
"message": "REQ-004 过大,建议拆分为多个子 REQ",
|
|
237
|
+
"user_options": ["split", "skip", "continue"]
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"id": "ralph-015",
|
|
242
|
+
"name": "Subagent dispatch — OpenCode task()",
|
|
243
|
+
"description": "验证 dispatch 使用 task() 工具,带正确 input contract",
|
|
244
|
+
"input": {
|
|
245
|
+
"req": "REQ-001",
|
|
246
|
+
"dispatch_method": "task(category=unspecified-high, load_skills=[test-driven-development], timeout=300)",
|
|
247
|
+
"context": {
|
|
248
|
+
"requirement": "REQ-001: 创建 User Model",
|
|
249
|
+
"permanent_learnings": ["auth middleware before validation"],
|
|
250
|
+
"contextual_learnings": ["migration files in src/migrations/"],
|
|
251
|
+
"agents_md": "project conventions",
|
|
252
|
+
"git_log": "commit1, commit2, commit3"
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
"expected": {
|
|
256
|
+
"dispatched": true,
|
|
257
|
+
"timeout_configured": true,
|
|
258
|
+
"skills_loaded": ["test-driven-development"],
|
|
259
|
+
"context_bounded": true
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
"id": "ralph-016",
|
|
264
|
+
"name": "首次 REQ,无 test-utils.ts — dispatch test-infra 子任务",
|
|
265
|
+
"description": "验证首个 REQ 执行时,若 test-utils.ts 不存在,先 dispatch 测试基础设施 subagent,不直接 dispatch 业务代码",
|
|
266
|
+
"input": {
|
|
267
|
+
"req": "REQ-001",
|
|
268
|
+
"test_utils_exists": false,
|
|
269
|
+
"infra_check_result": "missing"
|
|
270
|
+
},
|
|
271
|
+
"expected": {
|
|
272
|
+
"test_infra_dispatched": true,
|
|
273
|
+
"business_code_dispatched": false,
|
|
274
|
+
"infra_action": "generate_new",
|
|
275
|
+
"infra_max_retries": 2
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
"id": "ralph-017",
|
|
280
|
+
"name": "后续 REQ,test-utils.ts 已存在且接口完整 — 跳过 test-infra",
|
|
281
|
+
"description": "验证后续 REQ 执行时,若 test-utils.ts 已存在且导出 createTestApp() 和 withTestDb(),直接 dispatch 业务代码",
|
|
282
|
+
"input": {
|
|
283
|
+
"req": "REQ-003",
|
|
284
|
+
"test_utils_exists": true,
|
|
285
|
+
"exports": ["createTestApp", "withTestDb"],
|
|
286
|
+
"infra_check_result": "complete"
|
|
287
|
+
},
|
|
288
|
+
"expected": {
|
|
289
|
+
"test_infra_dispatched": false,
|
|
290
|
+
"business_code_dispatched": true,
|
|
291
|
+
"infra_summary_injected": true
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
"id": "ralph-018",
|
|
296
|
+
"name": "test-utils.ts 存在但接口不完整 — dispatch test-infra 增量补充",
|
|
297
|
+
"description": "验证 test-utils.ts 存在但缺少必需接口(如只有 createTestApp 缺少 withTestDb)时,dispatch test-infra 增量补充",
|
|
298
|
+
"input": {
|
|
299
|
+
"req": "REQ-002",
|
|
300
|
+
"test_utils_exists": true,
|
|
301
|
+
"exports": ["createTestApp"],
|
|
302
|
+
"missing_exports": ["withTestDb"],
|
|
303
|
+
"infra_check_result": "partial"
|
|
304
|
+
},
|
|
305
|
+
"expected": {
|
|
306
|
+
"test_infra_dispatched": true,
|
|
307
|
+
"business_code_dispatched": false,
|
|
308
|
+
"infra_action": "incremental_add_missing_exports"
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
]
|