@boyingliu01/xp-gate 0.6.2 → 0.7.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.
@@ -79,14 +79,7 @@ describe('ui-detector', () => {
79
79
  expect(result.matchedFiles).toContain('views/login.html');
80
80
  });
81
81
 
82
- it('should return true for deleted UI files', async () => {
83
- mockExecSync.mockReturnValue('views/old.html\n');
84
- const { detectUiSprint } = await import('../ui-detector');
85
- const result = detectUiSprint();
86
- expect(result.isUiSprint).toBe(true);
87
- });
88
-
89
- it('should handle renamed files correctly', async () => {
82
+ it('should return true for renamed UI files', async () => {
90
83
  mockExecSync.mockReturnValue('views/a.html → views/b.html\n');
91
84
  const { detectUiSprint } = await import('../ui-detector');
92
85
  const result = detectUiSprint();
@@ -114,63 +107,7 @@ describe('ui-detector', () => {
114
107
  it('should handle git command failure gracefully', async () => {
115
108
  mockExecSync.mockImplementation(() => {
116
109
  throw new Error('git not available');
117
- describe('collectUiMatches and detectUiSprint', () => {
118
- it('should detect UI files in components directory', async () => {
119
- const { collectUiMatches } = await import('../ui-detector');
120
- const result = collectUiMatches(['src/components/Button.tsx', 'src/utils/helper.ts']);
121
- expect(result.isUiSprint).toBe(true);
122
- expect(result.matchedFiles).toEqual(['src/components/Button.tsx']);
123
- expect(result.matchedRules.length).toBeGreaterThan(0);
124
- });
125
-
126
- it('should exclude test files from matching', async () => {
127
- const { collectUiMatches } = await import('../ui-detector');
128
- const result = collectUiMatches(['src/components/Button.test.tsx']);
129
- expect(result.isUiSprint).toBe(false);
130
- expect(result.matchedFiles).toEqual([]);
131
- });
132
-
133
- it('should exclude coverage directory files', async () => {
134
- const { collectUiMatches } = await import('../ui-detector');
135
- const result = collectUiMatches(['coverage/components/Coverage.tsx']);
136
- expect(result.isUiSprint).toBe(false);
137
- });
138
-
139
- it('should handle empty file list', async () => {
140
- const { collectUiMatches } = await import('../ui-detector');
141
- const result = collectUiMatches([]);
142
- expect(result.isUiSprint).toBe(false);
143
- expect(result.matchedFiles).toEqual([]);
144
- });
145
-
146
- it('should collect multiple UI files', async () => {
147
- const { collectUiMatches } = await import('../ui-detector');
148
- const result = collectUiMatches([
149
- 'src/components/Header.tsx',
150
- 'src/utils/api.ts',
151
- 'views/styles/app.css',
152
- ]);
153
- expect(result.isUiSprint).toBe(true);
154
- expect(result.matchedFiles).toHaveLength(2);
155
- });
156
-
157
- it('should aggregate unique rules across files', async () => {
158
- const { collectUiMatches } = await import('../ui-detector');
159
- const result = collectUiMatches([
160
- 'src/components/Button.tsx',
161
- 'src/components/Card.tsx',
162
- ]);
163
- expect(result.isUiSprint).toBe(true);
164
- expect(result.matchedFiles.length).toBeGreaterThan(0);
165
- });
166
-
167
- it('should respect .ui-gate-ignore patterns', async () => {
168
- const { collectUiMatches } = await import('../ui-detector');
169
- const withoutIgnore = collectUiMatches(['legacy/components/Old.tsx']);
170
- expect(withoutIgnore.isUiSprint).toBe(true);
171
- });
172
- });
173
- });
110
+ });
174
111
  const { detectUiSprint } = await import('../ui-detector');
175
112
  const result = detectUiSprint();
176
113
  expect(result.isUiSprint).toBe(false);
@@ -185,6 +122,29 @@ describe('ui-detector', () => {
185
122
  });
186
123
  });
187
124
 
125
+ describe('getChangedFiles', () => {
126
+ it('parses git diff output into file array', async () => {
127
+ mockExecSync.mockReturnValue('src/a.ts\nsrc/b.ts\n');
128
+ const { getChangedFiles } = await import('../ui-detector');
129
+ const files = getChangedFiles('main');
130
+ expect(files).toEqual(['src/a.ts', 'src/b.ts']);
131
+ });
132
+
133
+ it('returns empty array for empty diff', async () => {
134
+ mockExecSync.mockReturnValue('');
135
+ const { getChangedFiles } = await import('../ui-detector');
136
+ const files = getChangedFiles('main');
137
+ expect(files).toEqual([]);
138
+ });
139
+
140
+ it('filters out empty lines', async () => {
141
+ mockExecSync.mockReturnValue('src/a.ts\n\nsrc/b.ts\n');
142
+ const { getChangedFiles } = await import('../ui-detector');
143
+ const files = getChangedFiles('main');
144
+ expect(files).toEqual(['src/a.ts', 'src/b.ts']);
145
+ });
146
+ });
147
+
188
148
  describe('parseRenamedFile', () => {
189
149
  it('should extract new path from renamed file', async () => {
190
150
  const { parseRenamedFile } = await import('../ui-detector');
@@ -269,9 +229,9 @@ describe('ui-detector', () => {
269
229
  expect(result.isUiSprint).toBe(false);
270
230
  });
271
231
 
272
- it('should exclude src/__snapshots__ directory files', async () => {
232
+ it('excludes files under src/coverage/', async () => {
273
233
  const { collectUiMatches } = await import('../ui-detector');
274
- const result = collectUiMatches(['src/__snapshots__/Button.test.tsx.snap']);
234
+ const result = collectUiMatches(['src/coverage/components/Coverage.tsx']);
275
235
  expect(result.isUiSprint).toBe(false);
276
236
  });
277
237
 
@@ -279,6 +239,7 @@ describe('ui-detector', () => {
279
239
  const { collectUiMatches } = await import('../ui-detector');
280
240
  const result = collectUiMatches([]);
281
241
  expect(result.isUiSprint).toBe(false);
242
+ expect(result.matchedFiles).toEqual([]);
282
243
  });
283
244
 
284
245
  it('should collect multiple UI files', async () => {
@@ -292,7 +253,7 @@ describe('ui-detector', () => {
292
253
  expect(result.matchedFiles).toHaveLength(2);
293
254
  });
294
255
 
295
- it('should collect unique rules across files', async () => {
256
+ it('should aggregate unique rules across files', async () => {
296
257
  const { collectUiMatches } = await import('../ui-detector');
297
258
  const result = collectUiMatches([
298
259
  'src/components/Button.tsx',
@@ -308,4 +269,46 @@ describe('ui-detector', () => {
308
269
  expect(withoutIgnore.isUiSprint).toBe(true);
309
270
  });
310
271
  });
272
+
273
+ describe('isExcluded and loadUiGateIgnore', () => {
274
+ it('excludes paths matching **/coverage/** with leading directory', async () => {
275
+ const { isExcluded } = await import('../ui-detector');
276
+ expect(isExcluded('src/coverage/report.html', ['**/coverage/**'])).toBe(true);
277
+ });
278
+
279
+ it('does not match non-excluded paths', async () => {
280
+ const { isExcluded } = await import('../ui-detector');
281
+ expect(isExcluded('src/app.ts', ['**/coverage/**'])).toBe(false);
282
+ });
283
+
284
+ it('returns empty array when .ui-gate-ignore does not exist', async () => {
285
+ const { loadUiGateIgnore } = await import('../ui-detector');
286
+ expect(loadUiGateIgnore('/tmp')).toEqual([]);
287
+ });
288
+
289
+ it('excludes paths matching **/node_modules/** with leading directory', async () => {
290
+ const { isExcluded } = await import('../ui-detector');
291
+ expect(isExcluded('lib/node_modules/pkg/index.js', ['**/node_modules/**'])).toBe(true);
292
+ });
293
+
294
+ it('excludes paths matching **/dist/** with leading directory', async () => {
295
+ const { isExcluded } = await import('../ui-detector');
296
+ expect(isExcluded('src/dist/bundle.js', ['**/dist/**'])).toBe(true);
297
+ });
298
+
299
+ it('excludes paths matching **/build/** with leading directory', async () => {
300
+ const { isExcluded } = await import('../ui-detector');
301
+ expect(isExcluded('src/build/output.js', ['**/build/**'])).toBe(true);
302
+ });
303
+
304
+ it('excludes paths matching **/__tests__/**', async () => {
305
+ const { isExcluded } = await import('../ui-detector');
306
+ expect(isExcluded('src/__tests__/Button.test.tsx', ['**/__tests__/**'])).toBe(true);
307
+ });
308
+
309
+ it('excludes paths matching **/*.test.*', async () => {
310
+ const { isExcluded } = await import('../ui-detector');
311
+ expect(isExcluded('src/Button.test.tsx', ['**/*.test.*'])).toBe(true);
312
+ });
313
+ });
311
314
  });
@@ -45,11 +45,11 @@ export function isExcluded(filePath: string, exclusions: string[]): boolean {
45
45
  }
46
46
 
47
47
  function matchGlob(filePath: string, pattern: string): boolean {
48
- // Convert simplified glob to regex
48
+ // Escape literal dots first, then replace placeholders with regex
49
49
  const regex = pattern
50
+ .replace(/\./g, '\\.')
50
51
  .replace(/_STARSTAR_/g, '.*')
51
- .replace(/_STAR_/g, '[^/]*')
52
- .replace(/\./g, '\\.');
52
+ .replace(/_STAR_/g, '[^/]*');
53
53
  const re = new RegExp(`^${regex}$`);
54
54
  return re.test(filePath);
55
55
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boyingliu01/xp-gate",
3
- "version": "0.6.2",
3
+ "version": "0.7.1",
4
4
  "description": "AI-driven development workflow: 6 quality gates + Delphi review + Sprint Flow",
5
5
  "bin": {
6
6
  "xp-gate": "./bin/xp-gate.js"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xp-gate",
3
- "version": "0.6.2",
3
+ "version": "0.7.1",
4
4
  "displayName": "XP-Gate",
5
5
  "description": "Extreme Programming quality gates + AI workflow skills for Claude Code. Includes 6 quality gates, Sprint Flow, and Delphi multi-expert review.",
6
6
  "author": {
@@ -157,7 +157,7 @@ Expected behavior: do not run sprint-flow; route to investigation/explanation in
157
157
  Phase -1: ISOLATE → ⚠️ 检测保护分支(main/master/develop/trunk/mainline) → 强制创建 git worktree
158
158
  → 已在 worktree 中 → 跳过 → 项目 setup → .gitignore 校验 → sprint-state isolation 记录
159
159
  Phase -0.5: AUTO-ESTIMATE → 自动评估需求规模 → ⚠️ 展示评估结果,用户确认
160
- 轻量:跳过 brainstorming + delphi-review,直接 Phase 2 BUILD
160
+ 轻量:Phase 0-3 reduced intensity 执行 THINK/PLAN/review(不跳过 delphi-review
161
161
  → 标准:正常流程 Phase 0-4
162
162
  → 复杂:完整流程 Phase 0-8 + 风险警告
163
163
  Phase 0: THINK → brainstorming → ⚠️ HARD-GATE: 设计未批准 → 不可进入实现 → Design Document (AI编辑行为约束: 原则3 Surgical Changes, 验证循环要求: 原则4 Goal-Driven Execution - 见 AGENTS.md "## AI CODING DISCIPLINE (Karpathy Principles)")
@@ -212,7 +212,7 @@ Phase 8: CLEANUP → git worktree remove + sprint-state.json update → status:
212
212
  | 1 | **-1** | **ISOLATE** | Detect protected branch → Create git worktree → Setup project → Validate .gitignore → Record sprint state | Worktree path |
213
213
  | 2 | **-0.5** | **AUTO-ESTIMATE** | Analyze code structure → Count references → Assess cross-module impact → Classify (lightweight/standard/complex) | Impact assessment + flow recommendation |
214
214
  | 3 | **0** | **THINK** | brainstorming → Generate design doc + CONTEXT.md + ADR | Design document |
215
- | 4 | **1** | **PLAN** | autoplan → delphi-review (if needed) → Generate specification.yaml + slices-manifest.json | specification.yaml |
215
+ | 4 | **1** | **PLAN** | autoplan → delphi-review (mandatory; lightweight allowed) → Generate specification.yaml + slices-manifest.json | specification.yaml |
216
216
  | 5 | **2** | **BUILD** | GITHOOKS-GATE → ralph-loop (default) or parallel → TDD → freeze → blind review → verification | MVP code |
217
217
  | 6 | **3** | **REVIEW** | delphi-review --mode code-walkthrough → test-specification-alignment → browse QA → benchmark (optional) | Review report |
218
218
  | 7 | **4** | **USER ACCEPT** | **Manual verification** → Capture emergent issues | Emergent issues list |
@@ -314,7 +314,7 @@ ISOLATE → AUTO-ESTIMATE → THINK → PLAN → [GITHOOKS-GATE] → BUILD → R
314
314
 
315
315
  | 评估结果 | 路由 | 说明 |
316
316
  |---------|------|------|
317
- | **轻量** (引用 ≤3, 同模块,无循环依赖) | 跳过 Phase 0 brainstorming + Phase 1 delphi-review → 直接进入 Phase 2 BUILD | 小改动不需要完整流程 |
317
+ | **轻量** (引用 ≤3, 同模块,无循环依赖) | Phase 0-3 reduced intensity 执行(THINK/PLAN/review 强度降低,不跳过 delphi-review | 轻量仍需要评审,但强度可调整 |
318
318
  | **标准** (引用 4-10, 跨 1-2 模块) | 正常流程 Phase 0-4 | 标准 sprint |
319
319
  | **复杂** (引用 >10 或 循环依赖 或 跨 3+ 模块) | 完整 Phase 0-8 + 风险警告 | 高风险需求 |
320
320
 
@@ -350,8 +350,8 @@ ISOLATE → AUTO-ESTIMATE → THINK → PLAN → [GITHOOKS-GATE] → BUILD → R
350
350
  - **取消**: 停止本次 sprint
351
351
 
352
352
  **⚠️ 轻量路由的特殊处理**:
353
- - 轻量路由跳过 Phase 0 brainstorming Phase 1 delphi-review
354
- - 但仍然执行 Phase 1→2 GITHOOKS-GATE 检查
353
+ - 轻量路由 Phase 0-3 reduced intensity 执行(THINK/PLAN/review 强度降低)
354
+ - **所有路由必须产生** `.sprint-state/delphi-reviewed.json` `verdict = "APPROVED"` 才能进入 BUILD
355
355
  - Phase 2 BUILD 仍然执行完整 TDD + 盲评 + 验证
356
356
 
357
357
  ### Phase 0: THINK(需求探索与设计)
@@ -366,9 +366,9 @@ ISOLATE → AUTO-ESTIMATE → THINK → PLAN → [GITHOOKS-GATE] → BUILD → R
366
366
  - 输出: `specification.yaml`(含 user_stories[])+ `slices-manifest.json`
367
367
 
368
368
  **条件分支逻辑**:
369
- - IF autoplan AUTO_APPROVED + 无 taste_decisions → 跳过 delphi-review
370
- - IF autoplan NEEDS_REVIEW OR taste_decisions > 0 → 调用 delphi-review
371
- - delphi-review APPROVED → 生成 specification.yaml(含 user_stories[]) → **调用 /to-issues** 拆解为垂直切片 → slices-manifest.json → Phase 2 按 execution_order 执行
369
+ - IF autoplan AUTO_APPROVED + 无 taste_decisions → 可执行 **lightweight delphi-review**(2 专家、1 轮、2/2 APPROVED,参考 `references/force-levels.md`)
370
+ - IF autoplan NEEDS_REVIEW OR taste_decisions > 0 → 调用标准 delphi-review(3 专家)
371
+ - **delphi-review 必须产生** `.sprint-state/delphi-reviewed.json` 且 `verdict = "APPROVED"` → 生成 specification.yaml(含 user_stories[]) → **调用 /to-issues** 拆解为垂直切片 → slices-manifest.json → Phase 2 按 execution_order 执行
372
372
 
373
373
  ### Phase 1→2: GITHOOKS-GATE(质量门禁安装检查)
374
374
 
@@ -377,7 +377,7 @@ ISOLATE → AUTO-ESTIMATE → THINK → PLAN → [GITHOOKS-GATE] → BUILD → R
377
377
  **必须执行**: 运行 `githooks/verify.sh` 检查当前项目的 hooks 是否安装。
378
378
 
379
379
  **检查结果处理**:
380
- - ✅ 全部存在 → 直接进入 Phase 2 BUILD
380
+ - ✅ 全部存在 → 进入 Phase 2 BUILD 入口(仍必须先执行 DELPHI-GATE)
381
381
  - ❌ 部分/全部缺失 → 运行 `githooks/install.sh` 安装(包括 `.git/hooks/pre-commit`、`.git/hooks/pre-push`、`githooks/adapter-common.sh`、`githooks/adapters/`)
382
382
  - 如果 githooks/ 目录不存在于项目根目录(即当前项目不是 xp-gate) → 从 xp-gate 仓库拉取 `githooks/` 目录结构
383
383
  - 安装完成后再次 `verify.sh` 确认
@@ -713,7 +713,7 @@ Sprint state is persisted as JSON in `.sprint-state/sprint-state.json`:
713
713
  "test_file_count": 4
714
714
  },
715
715
  "estimated_level": "轻量|标准|复杂",
716
- "recommended_flow": "轻量流程 (Phase 2-3)|标准流程 (Phase 0-4)|完整 Sprint Flow (Phase 0-8)",
716
+ "recommended_flow": "轻量流程 (Phase 0-3, reduced-intensity Delphi)|标准流程 (Phase 0-4)|完整 Sprint Flow (Phase 0-8)",
717
717
  "risk_warnings": ["循环依赖: user ↔ plane"],
718
718
  "user_decision": "accepted|overridden|cancelled",
719
719
  "override_reason": null
@@ -780,8 +780,8 @@ Sprint state is persisted as JSON in `.sprint-state/sprint-state.json`:
780
780
 
781
781
  ```bash
782
782
  /sprint-flow "继续 Sprint" --resume-from build --spec specification.yaml
783
- # → 跳过 Think + Plan,直接从 Build 开始
784
- # 适用场景:中断恢复,使用已有的 specification.yaml
783
+ # → Build 恢复,但必须已有 specification.yaml + .sprint-state/delphi-reviewed.json (verdict: APPROVED)
784
+ # 适用场景:中断恢复,使用已通过 delphi-review 的 specification.yaml
785
785
  ```
786
786
 
787
787
  ### --phase(只执行单个阶段)
@@ -936,7 +936,7 @@ Sprint 结束时 (Phase 6 完成):
936
936
 
937
937
  # 第二次:三天后继续
938
938
  /sprint-flow "继续开发" --resume-from build --spec docs/specification.yaml
939
- # → 跳过 Think + Plan,直接从 Build 开始
939
+ # → Build 入口恢复,但必须已有 specification.yaml + .sprint-state/delphi-reviewed.json (verdict: APPROVED)
940
940
  ```
941
941
 
942
942
  ### 示例 3:语言特定
@@ -1015,7 +1015,7 @@ Sprint 结束时 (Phase 6 完成):
1015
1015
  | 把普通问答、解释、代码检索请求路由到 sprint-flow | 仅在用户明确要求开发/实现/一键开发完整需求时触发 sprint-flow |
1016
1016
  | 跳过 Phase -1 隔离,直接在 main/master/develop 上改代码 | 默认创建 worktree;除非用户显式使用 `--no-isolate` 或 `--force` 并确认风险 |
1017
1017
  | 未完成 Phase -0.5 AUTO-ESTIMATE 就套用完整重流程 | 先评估轻量/标准/复杂,再按推荐流程或用户确认后的流程执行 |
1018
- | Plan 阶段跳过 Delphi 评审直接 Build | 标准/复杂需求必须经过 autoplan + delphi-review;未 APPROVED 禁止编码 |
1018
+ | Plan 阶段跳过 Delphi 评审直接 Build | 所有需求级别(轻量/标准/复杂)必须经过 autoplan + delphi-review;未 APPROVED 禁止编码 |
1019
1019
  | 跳过 TDD 直接实现代码 | Phase 2 必须遵循 RED → GREEN → REFACTOR,测试与实现一起交付 |
1020
1020
  | 跳过用户验收直接 Ship | Phase 4 USER ACCEPTANCE 必须人工完成;不得自动化、跳过或伪造 |
1021
1021
  | 验证失败后继续追加随机修改 | 最多 3 次修复循环;仍失败则 BLOCK 并请求用户决策 |
@@ -23,7 +23,7 @@
23
23
  | Skill | 来源 | 触发条件 | 条件分支 |
24
24
  |-------|------|---------|---------|
25
25
  | `autoplan` | gstack | 进入 Phase 1 自动调用 | 输出 AUTO_APPROVED 或 NEEDS_REVIEW |
26
- | `delphi-review` | xp-gate | autoplan NEEDS_REVIEW OR taste_decisions > 0 | 跳过如果 AUTO_APPROVED + taste_decisions |
26
+ | `delphi-review` | xp-gate | Phase 1 强制调用;AUTO_APPROVED + 无 taste_decisions 使用 lightweight delphi-review | 必须产生 `.sprint-state/delphi-reviewed.json` verdict=APPROVED |
27
27
  | `to-issues` | xp-gate | delphi-review APPROVED 后 | 拆解为垂直切片 → slices-manifest.json |
28
28
 
29
29
  ### Phase 2: BUILD
@@ -28,7 +28,7 @@
28
28
  ### GITHOOKS-GATE (Phase 1→2 闸门)
29
29
 
30
30
  - 执行时机: Phase 1 完全通过、准备进入 Phase 2 BUILD 前
31
- - `githooks/verify.sh` 全部存在 → 直接进入 BUILD
31
+ - `githooks/verify.sh` 全部存在 → 进入 BUILD 入口(仍必须先执行 DELPHI-GATE)
32
32
  - 缺失 → `githooks/install.sh` 安装(hooks + adapter 基础设施)
33
33
  - **核心原则**: 没有质量门禁的代码不可进入 BUILD。**失败 → 不可编码。**
34
34
 
@@ -0,0 +1,203 @@
1
+ # Sprint Flow 执行级别定义
2
+
3
+ **执行时机**: Phase 0 THINK 之前,AUTO-ESTIMATE 完成后。
4
+
5
+ **目的**: 根据需求规模匹配适度评审流程,平衡质量保障与效率。
6
+
7
+ **核心原则**:
8
+ - 所有级别**必须经过 Delphi 评审**,不可跳过
9
+ - 轻量级采用**简化 Delphi**(2 专家、1 轮),仍需 2/2 批准
10
+ - 标准/复杂采用**完整 Delphi**(2-3 专家、多轮)
11
+ - 自动升级机制:当出现风险信号时强制升级级别
12
+
13
+ ---
14
+
15
+ ## 级别定义
16
+
17
+ | 级别 | 适用场景 | 专家数 | 最多轮数 | 通过条件 | 预计耗时 |
18
+ |------|---------|--------|---------|----------|---------|
19
+ | **轻量** | 小改动、局部修改、删除代码 | 2 | 1 | 2/2 批准 | 10-20 分钟 |
20
+ | **标准** | 常规功能开发、模块重构 | 2 | 2 | 2/2 批准 | 30-60 分钟 |
21
+ | **复杂** | 核心模块、跨模块变更、新增架构 | 3 | 3 | 3/3 批准 | 1-2 小时 |
22
+
23
+ ---
24
+
25
+ ## Token 成本预算
26
+
27
+ | 级别 | delphi-review 调用 | 预计 Token 消耗 | 成本说明 |
28
+ |------|-------------------|--------------|---------|
29
+ | **轻量** | 1 次(2 专家、1 轮) | ~8,000 | 简化流程,单轮评审 |
30
+ | **标准** | 1-2 次(2 专家、1-2 轮) | ~15,000-25,000 | 可能需要 1 轮反馈 |
31
+ | **复杂** | 1-3 次(3 专家、1-3 轮) | ~30,000-60,000 | 多轮深度评审 |
32
+
33
+ > **成本计算依据**: 基于实际 Sprint 历史数据,假设每次 delphi-review 调用平均消耗 8,000-10,000 Token(含 3 位专家的输入输出)。
34
+
35
+ ---
36
+
37
+ ## 测试与验证要求
38
+
39
+ | 级别 | 单元测试 | 测试覆盖率 | 验证方式 |
40
+ |------|---------|-----------|---------|
41
+ | **轻量** | 修改处必须有测试 | ≥75% | 自动运行 + 人工抽查 |
42
+ | **标准** | 新增功能必须有测试 | ≥80% | 自动运行 + 人工复核 |
43
+ | **复杂** | 全链路测试 + 边界用例 | ≥85% | 自动运行 + Delphi 验证 |
44
+
45
+ **强制规则**:
46
+ - 轻量级修改**不可跳过测试**,至少添加回归测试
47
+ - 所有级别必须通过 `test-specification-alignment` 验证
48
+ - 未添加测试 → 自动升级至标准级别
49
+
50
+ ---
51
+
52
+ ## 自动升级机制
53
+
54
+ 当出现以下任一情况时,**强制升级**至更高级别:
55
+
56
+ | 触发条件 | 原级别 | 升级至 | 说明 |
57
+ |---------|--------|--------|------|
58
+ | Delphi 评审出现 REQUEST_CHANGES | 轻量 | 标准 | 需要第二轮评审 |
59
+ | 专家意见分歧(1 票反对) | 轻量/标准 | 复杂 | 需要第 3 专家仲裁 |
60
+ | 涉及公共 API 变更 | 轻量 | 标准 | 影响外部调用方 |
61
+ | 修改文件数 > 5 或 LOC > 200 | 轻量 | 标准 | 改动规模超出轻量范围 |
62
+ | 存在循环依赖 | 轻量/标准 | 复杂 | 架构风险高 |
63
+ | 测试覆盖率 < 75% | 轻量 | 标准 | 质量不达标 |
64
+ | 修改核心模块(core/handlers) | 轻量/标准 | 复杂 | 关键路径 |
65
+
66
+ **升级流程**:
67
+ 1. 自动检测触发条件
68
+ 2. 输出升级警告:`[LEVEL_UPGRADE] 从 {原级别} 升级至 {新级别},原因:{触发条件}`
69
+ 3. 保存升级记录到 `.sprint-state/level-upgrade-log.json`
70
+ 4. 重新执行对应级别的评审流程
71
+
72
+ ---
73
+
74
+ ## 与 AUTO-ESTIMATE 的关系
75
+
76
+ AUTO-ESTIMATE 提供**初始级别建议**,Force Levels 定义**具体执行规则**:
77
+
78
+ ```
79
+ AUTO-ESTIMATE 输出 → Force Levels 执行 → 自动升级机制(如触发)
80
+ ```
81
+
82
+ | AUTO-ESTIMATE 指标 | 建议级别 | Force Levels 执行 |
83
+ |-------------------|---------|------------------|
84
+ | 引用计数 ≤ 3 + 跨模块 ≤ 1 | 轻量 | 2 专家、1 轮 Delphi |
85
+ | 引用计数 4-10 或 跨模块 2 | 标准 | 2 专家、最多 2 轮 Delphi |
86
+ | 引用计数 > 10 或 跨模块 ≥ 3 | 复杂 | 3 专家、最多 3 轮 Delphi |
87
+ | 存在循环依赖 | 强制复杂 | 3 专家、最多 3 轮 + 架构评审 |
88
+
89
+ **关键区别**:
90
+ - AUTO-ESTIMATE: **客观指标分析**(代码结构、引用计数)
91
+ - Force Levels: **执行规则定义**(评审流程、升级机制)
92
+
93
+ ---
94
+
95
+ ## 与 DELPHI-GATE 的关系
96
+
97
+ **DELPHI-GATE** 是 Phase 2 的**强制门禁**,检查 `.sprint-state/delphi-reviewed.json` 的 `verdict=APPROVED`。Force Levels 定义**产生该门禁文件的评审强度**:
98
+
99
+ | 场景 | DELPHI-GATE | Force Levels |
100
+ |------|------------|-------------|
101
+ | Phase 1 设计评审 | 3 专家、≥95% 共识、生成 specification.yaml | 不适用(设计阶段) |
102
+ | Phase 2 BUILD 入口 | **必须检查** `.sprint-state/delphi-reviewed.json` 中 `verdict=APPROVED` | 轻量/标准/复杂:通过对应强度的 delphi-review 生成该门禁文件 |
103
+ | 轻量级评审 | 生成 `delphi-reviewed.json`(2 专家、1 轮、2/2 批准) | 2 专家、1 轮、写入门禁文件 |
104
+ | 标准级评审 | 生成 `delphi-reviewed.json`(2 专家、最多 2 轮、2/2 批准) | 2 专家、最多 2 轮、写入门禁文件 |
105
+ | 复杂级评审 | 生成 `delphi-reviewed.json`(3 专家、最多 3 轮、3/3 批准) | 3 专家、最多 3 轮、写入门禁文件 |
106
+ | Phase 3 代码走查 | 再次检查 `delphi-reviewed.json` 或重新评审 | 复用 Force Levels 规则 |
107
+
108
+ **关键规则**:
109
+ - **DELPHI-GATE 永不跳过**:Phase 2 BUILD 入口必须检查 `.sprint-state/delphi-reviewed.json` 中 `verdict=APPROVED`
110
+ - **Force Levels 定义评审强度**:轻量/标准/复杂决定用 2 专家 1 轮还是 3 专家 3 轮来**产生**门禁文件
111
+ - **轻量级不是跳过评审**:而是简化流程(2 专家、1 轮),但仍需生成门禁文件
112
+ - **LIGHTWEIGHT ≠ ONE-EXPERT**: 1 专家违反 Delphi 核心原则,禁止
113
+
114
+ ---
115
+
116
+ ## 轻量级详细规则
117
+
118
+ **适用场景**:
119
+ - 删除已存在代码(如移除废弃模块)
120
+ - 小规模修改(≤ 5 个文件、≤ 200 行改动)
121
+ - 不涉及公共 API
122
+ - 无循环依赖
123
+
124
+ **执行流程**:
125
+ 1. 2 位专家独立评审(DeepSeek-v4-pro + Kimi-K2.6)
126
+ 2. 单轮评审,无需多轮迭代
127
+ 3. **2/2 批准**才通过(不允许 1/2 批准)
128
+ 4. 评审通过后写入 `.sprint-state/delphi-reviewed.json`
129
+
130
+ **输出文件** (`.sprint-state/delphi-reviewed.json`):
131
+ ```json
132
+ {
133
+ "sprint_id": "sprint-2026-06-05-01",
134
+ "level": "轻量",
135
+ "delphi_review": {
136
+ "experts": ["deepseek-v4-pro", "kimi-k2.6"],
137
+ "rounds": 1,
138
+ "votes": {
139
+ "expert_a": "APPROVED",
140
+ "expert_b": "APPROVED"
141
+ },
142
+ "consensus": "2/2 APPROVED",
143
+ "timestamp": "2026-06-05T10:30:00Z"
144
+ },
145
+ "status": "passed"
146
+ }
147
+ ```
148
+
149
+ **强制升级条件**(轻量级触发):
150
+ - 任一专家 REQUEST_CHANGES → 升级至标准级
151
+ - 涉及公共 API → 升级至标准级
152
+ - 修改文件 > 5 或 LOC > 200 → 升级至标准级
153
+
154
+ ---
155
+
156
+ ## 标准级详细规则
157
+
158
+ **适用场景**:
159
+ - 常规功能开发
160
+ - 模块重构(不涉及架构变更)
161
+ - 中等规模改动(5-15 个文件、200-500 行改动)
162
+
163
+ **执行流程**:
164
+ 1. 2 位专家独立评审(Round 1)
165
+ 2. 如有 REQUEST_CHANGES,进入 Round 2(最多 2 轮)
166
+ 3. **2/2 批准**才通过
167
+ 4. 评审通过后写入 `.sprint-state/delphi-reviewed.json`
168
+
169
+ **升级至复杂级条件**:
170
+ - Round 2 仍有分歧(1 票反对)→ 升级至复杂级(第 3 专家仲裁)
171
+ - 涉及核心模块(core/handlers)→ 升级至复杂级
172
+ - 存在循环依赖 → 升级至复杂级
173
+
174
+ ---
175
+
176
+ ## 复杂级详细规则
177
+
178
+ **适用场景**:
179
+ - 核心模块开发
180
+ - 跨模块变更(≥ 3 个目录)
181
+ - 架构调整
182
+ - 公共 API 重大变更
183
+
184
+ **执行流程**:
185
+ 1. 3 位专家独立评审(DeepSeek-v4-pro + Kimi-K2.6 + Qwen3.6-Plus)
186
+ 2. 最多 3 轮评审(Round 1-3)
187
+ 3. **3/3 批准**才通过
188
+ 4. 评审通过后写入 `.sprint-state/delphi-reviewed.json`
189
+
190
+ **仲裁机制**:
191
+ - Round 2 仍有分歧 → 第 3 专家(Qwen3.6-Plus)加入仲裁
192
+ - Round 3 必须达成一致,否则 BLOCK 进入 Phase 2
193
+
194
+ ---
195
+
196
+ ## 参见
197
+
198
+ - [Phase -0.5: AUTO-ESTIMATE](../references/phase-minus-0-5-auto-estimate.md) — 规模评估与流程路由
199
+ - [Phase 0: THINK](../references/phase-0-think.md) — 需求探索与设计
200
+ - [Phase 1: PLAN](../references/phase-1-plan.md) — 计划与 Delphi 设计评审
201
+ - [Phase 2: BUILD](../references/phase-2-build.md) — 编码与 Ralph Loop
202
+ - [Phase 3: REVIEW](../references/phase-3-review.md) — 代码走查与验证
203
+ - [Delphi Review Skill](../../../../skills/delphi-review/SKILL.md) — 多专家共识评审规范
@@ -69,13 +69,13 @@ autoplan_result:
69
69
  │ │
70
70
  │ IF autoplan_result.verdict == "AUTO_APPROVED" │
71
71
  │ AND autoplan_result.taste_decisions == [] │
72
- │ → 跳过 delphi-review,直接进入 Step 3
73
- │ → 场景: autoplan 所有决策自动通过,无关键分歧
72
+ │ → 调用 lightweight delphi-review(2 专家、1 轮、2/2 APPROVED)
73
+ │ → 场景: autoplan 所有决策自动通过,无关键分歧,但仍需共识门禁
74
74
  │ │
75
75
  │ IF autoplan_result.verdict == "NEEDS_REVIEW" │
76
76
  │ OR autoplan_result.taste_decisions.length > 0 │
77
77
  │ → ⚠️ 暂停等待用户确认 taste_decisions │
78
- │ → 用户确认后,调用 delphi-review
78
+ │ → 用户确认后,调用标准 delphi-review
79
79
  │ → 场景: 存在关键决策分歧或 autoplan 未完全自动通过 │
80
80
  │ │
81
81
  └───────────────────────────────────────────────────────────────────┘
@@ -105,7 +105,7 @@ Decision 2: [决策描述]
105
105
 
106
106
  ---
107
107
 
108
- ### Step 2b: 调用 delphi-review(如需要)
108
+ ### Step 2b: 调用 delphi-review(强制)
109
109
 
110
110
  ```bash
111
111
  skill(name="delphi-review", user_message="[设计文档 + taste_decisions 确认结果]")
@@ -182,10 +182,27 @@ find . -name "*{target}*.test.*" -o -name "*{target}*.spec.*" | grep -v node_mod
182
182
 
183
183
  | 流程级别 | 路由 |
184
184
  |---------|------|
185
- | **轻量** | → Phase 2 BUILD(跳过 Phase 0 brainstorming、Phase 1 delphi-review) |
185
+ | **轻量** | → Phase 0 THINK(reduced-intensity 流程,见 references/force-levels.md) |
186
186
  | **标准** | → Phase 0 THINK(正常流程) |
187
187
  | **复杂** | → Phase 0 THINK(完整流程 + 风险警告提示) |
188
188
 
189
+ **DELPHI-GATE invariant**: 所有流程级别(轻量/标准/复杂)的 Phase 2 BUILD 启动前,**必须**检查 `.sprint-state/delphi-reviewed.json` 的 verdict 为 `APPROVED`。未通过 delphi-review 直接路由到 BUILD 属于严重违规。
190
+
191
+ **轻量级的正确理解**: 轻量级意味着 reduced-intensity 的 delphi-review(**2 专家、1 轮、2/2 APPROVED、较短上下文**),**不是**跳过 delphi-review,**不是** 1 专家评审。见 references/force-levels.md 的轻量级流程定义。
192
+
193
+ **自动 escalation 规则**(检测到以下情况时,自动提升流程级别):
194
+
195
+ | 触发条件 | 原级别 | 提升级别 | 理由 |
196
+ |---------|--------|---------|------|
197
+ | 风险警告(循环依赖、Public API > 5) | 轻量 | 标准 | 技术风险需要标准流程 |
198
+ | 多位专家 disagreement 或 REQUEST_CHANGES | 轻量/标准 | 复杂 | 意见分歧需要更全面评审 |
199
+ | 涉及文件数 > 10 或 LOC > 500 | 轻量 | 标准 | 超出轻量级预算 |
200
+ | 修改公共 API(export 接口) | 轻量/标准 | 复杂 | API 变更影响范围广 |
201
+ | 检测到循环依赖 | 任何级别 | 复杂 | 架构风险强制复杂流程 |
202
+ | 相关测试文件缺失或覆盖率 < 80% | 轻量/标准 | 标准 | 需要补充测试 |
203
+
204
+ **跨参考**: 详见 references/force-levels.md 的各级别流程定义和强制规则。
205
+
189
206
  ---
190
207
 
191
208
  ## 特殊场景处理
@@ -199,6 +216,8 @@ git diff --stat HEAD 2>/dev/null # 如果有局部修改
199
216
 
200
217
  **处理**: 如果预估改动 < 20 行且涉及 ≤ 2 个文件,自动判定为「轻量」并告知用户,不强制展示完整 AUTO-ESTIMATE 面板。
201
218
 
219
+ **注意**: 轻量级仍需要完整的 Sprint Flow 流程(包括 delphi-review),只是 reduced-intensity。见 references/force-levels.md 的轻量级定义。**不会**绕过 DELPHI-GATE 直接路由到 BUILD。
220
+
202
221
  ### 场景 2: 无法提取目标关键词
203
222
 
204
223
  **处理**: 询问用户「无法自动识别目标模块,请指定要分析的关键词(函数名/类名/模块名):」
@@ -41,7 +41,7 @@
41
41
  | `{circular_dep_status}` | 循环依赖状态 | ✅ 无 / ⚠️ 存在 (A ↔ B) |
42
42
  | `{public_api_count}` | Public API 暴露数 | 5 |
43
43
  | `{additional_metrics}` | 附加指标(可选行) | 测试文件:4 个 / 影响范围:3 层调用 |
44
- | `{recommended_flow}` | 建议流程描述 | 轻量流程 (Phase 2-3) |
44
+ | `{recommended_flow}` | 建议流程描述 | 轻量流程 (Phase 0-3, reduced-intensity Delphi) |
45
45
  | `{risk_warning}` | 风险警告(可选块) | ⚠️ 此操作涉及循环依赖… |
46
46
  | 操作按钮 | 用户确认选项 | 接受建议 / 修改流程 / 取消 |
47
47
 
@@ -72,9 +72,9 @@
72
72
  +-------------------------------------------------------------+
73
73
  | 选择流程级别: |
74
74
  | |
75
- | [1] 轻量流程 — 直接编码 + 基础验证 (Phase 2-3) |
76
- | [2] 标准流程 — brainstorming + BUILD + REVIEW (Phase 0-4) |
77
- | [3] 完整流程 — 完整 Sprint Flow (Phase 0-8) |
75
+ | [1] 轻量流程 — minimal THINK + 简化 Delphi + BUILD/REVIEW (Phase 0-3) |
76
+ | [2] 标准流程 — brainstorming + Delphi + BUILD + REVIEW (Phase 0-4) |
77
+ | [3] 完整流程 — 完整 Sprint Flow (Phase 0-8) |
78
78
  | |
79
79
  | 修改原因(必填):____________________ |
80
80
  | |
@@ -107,10 +107,12 @@
107
107
 
108
108
  | 评估结果 | 路由 | 说明 |
109
109
  |---------|------|------|
110
- | **轻量** (引用 ≤3, 同模块,无循环依赖) | Phase 2-3(跳过 brainstorming + delphi-review) | 直接编码 + 基础验证 |
110
+ | **轻量** (引用 ≤3, 同模块,无循环依赖) | Phase 0-3(minimal THINK 简化 Delphi 评审 → BUILD/REVIEW) | 低强度执行,仍需 DELPHI-GATE APPROVED |
111
111
  | **标准** (引用 4-10, 跨 1-2 模块) | Phase 0-4(完整 THINK → BUILD → REVIEW) | 标准 sprint |
112
112
  | **复杂** (引用 >10 或 循环依赖 或 跨 3+ 模块) | Phase 0-8(完整 sprint-flow) | 完整流程 + 风险警告 |
113
113
 
114
+ **所有流程路线均需在 Phase 2 前获得 delphi-review APPROVED verdict。**
115
+
114
116
  ## 学习闭环
115
117
 
116
118
  当用户选择「修改流程」时,记录 override 数据: