dev-playbooks-cn 1.0.0
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/LICENSE +21 -0
- package/README.md +466 -0
- package/bin/devbooks.js +987 -0
- package/package.json +43 -0
- package/skills/Skills/344/275/277/347/224/250/350/257/264/346/230/216.md +446 -0
- package/skills/Skill/345/274/200/345/217/221/346/214/207/345/215/227.md +248 -0
- package/skills/_shared/context-detection-template.md +315 -0
- package/skills/_shared/mcp-enhancement-template.md +144 -0
- package/skills/_shared/references//351/200/232/347/224/250/345/256/210/351/227/250/345/215/217/350/256/256.md +114 -0
- package/skills/_template/config-discovery-template.md +126 -0
- package/skills/devbooks-brownfield-bootstrap/SKILL.md +167 -0
- package/skills/devbooks-brownfield-bootstrap/references//344/273/243/347/240/201/345/257/274/350/210/252/347/255/226/347/225/245.md +203 -0
- package/skills/devbooks-brownfield-bootstrap/references//345/255/230/351/207/217/351/241/271/347/233/256/345/210/235/345/247/213/345/214/226.md +96 -0
- package/skills/devbooks-brownfield-bootstrap/references//345/255/230/351/207/217/351/241/271/347/233/256/345/210/235/345/247/213/345/214/226/346/217/220/347/244/272/350/257/215.md +115 -0
- package/skills/devbooks-brownfield-bootstrap/references//346/234/257/350/257/255/350/241/250/346/250/241/346/235/277.md +42 -0
- package/skills/devbooks-brownfield-bootstrap/scripts/cod-update.sh +357 -0
- package/skills/devbooks-brownfield-bootstrap/templates/project-profile-template.md +172 -0
- package/skills/devbooks-c4-map/SKILL.md +151 -0
- package/skills/devbooks-c4-map/references/C4/346/236/266/346/236/204/345/234/260/345/233/276/346/217/220/347/244/272/350/257/215.md +33 -0
- package/skills/devbooks-c4-map/references//345/210/206/345/261/202/347/272/246/346/235/237/346/243/200/346/237/245/346/270/205/345/215/225.md +185 -0
- package/skills/devbooks-code-review/SKILL.md +175 -0
- package/skills/devbooks-code-review/references/PR/346/250/241/346/235/277/344/270/216/346/214/207/345/215/227.md +321 -0
- package/skills/devbooks-code-review/references//344/273/243/347/240/201/350/257/204/345/256/241/346/217/220/347/244/272/350/257/215.md +100 -0
- package/skills/devbooks-code-review/references//345/235/217/345/221/263/351/201/223/351/200/237/346/237/245/350/241/250.md +495 -0
- package/skills/devbooks-code-review/references//350/265/204/346/272/220/347/256/241/347/220/206/345/256/241/346/237/245/346/270/205/345/215/225.md +311 -0
- package/skills/devbooks-coder/SKILL.md +219 -0
- package/skills/devbooks-coder/references//344/273/243/347/240/201/345/256/236/347/216/260/346/217/220/347/244/272/350/257/215.md +70 -0
- package/skills/devbooks-coder/references//344/275/216/351/243/216/351/231/251/346/224/271/345/212/250/346/212/200/346/234/257.md +275 -0
- package/skills/devbooks-coder/references//346/227/245/345/277/227/350/247/204/350/214/203.md +329 -0
- package/skills/devbooks-coder/references//347/274/226/347/240/201/351/243/216/346/240/274/347/273/206/345/210/231.md +351 -0
- package/skills/devbooks-coder/references//351/224/231/350/257/257/347/240/201/350/247/204/350/214/203.md +463 -0
- package/skills/devbooks-delivery-workflow/SKILL.md +217 -0
- package/skills/devbooks-delivery-workflow/references//344/272/244/344/273/230/351/252/214/346/224/266/345/267/245/344/275/234/346/265/201.md +256 -0
- package/skills/devbooks-delivery-workflow/references//345/216/237/345/236/213-/347/224/237/344/272/247/345/217/214/350/275/250/346/250/241/345/274/217.md +168 -0
- package/skills/devbooks-delivery-workflow/references//345/217/230/346/233/264/351/252/214/350/257/201/344/270/216/350/277/275/346/272/257/346/250/241/346/235/277.md +133 -0
- package/skills/devbooks-delivery-workflow/scripts/ac-trace-check.sh +330 -0
- package/skills/devbooks-delivery-workflow/scripts/audit-scope.sh +262 -0
- package/skills/devbooks-delivery-workflow/scripts/change-check.sh +1040 -0
- package/skills/devbooks-delivery-workflow/scripts/change-codemod-scaffold.sh +135 -0
- package/skills/devbooks-delivery-workflow/scripts/change-evidence.sh +152 -0
- package/skills/devbooks-delivery-workflow/scripts/change-scaffold.sh +442 -0
- package/skills/devbooks-delivery-workflow/scripts/change-spec-delta-scaffold.sh +136 -0
- package/skills/devbooks-delivery-workflow/scripts/constitution-check.sh +237 -0
- package/skills/devbooks-delivery-workflow/scripts/env-match-check.sh +128 -0
- package/skills/devbooks-delivery-workflow/scripts/fitness-check.sh +387 -0
- package/skills/devbooks-delivery-workflow/scripts/guardrail-check.sh +519 -0
- package/skills/devbooks-delivery-workflow/scripts/handoff-check.sh +141 -0
- package/skills/devbooks-delivery-workflow/scripts/hygiene-check.sh +340 -0
- package/skills/devbooks-delivery-workflow/scripts/migrate-from-openspec.sh +385 -0
- package/skills/devbooks-delivery-workflow/scripts/migrate-to-v2-gates.sh +202 -0
- package/skills/devbooks-delivery-workflow/scripts/progress-dashboard.sh +319 -0
- package/skills/devbooks-delivery-workflow/scripts/prototype-promote.sh +341 -0
- package/skills/devbooks-delivery-workflow/scripts/spec-preview.sh +203 -0
- package/skills/devbooks-delivery-workflow/scripts/spec-promote.sh +118 -0
- package/skills/devbooks-delivery-workflow/scripts/spec-rollback.sh +124 -0
- package/skills/devbooks-delivery-workflow/scripts/spec-stage.sh +117 -0
- package/skills/devbooks-delivery-workflow/scripts/verify-all.sh +78 -0
- package/skills/devbooks-delivery-workflow/scripts/verify-npm-package.sh +123 -0
- package/skills/devbooks-delivery-workflow/scripts/verify-openspec-free.sh +81 -0
- package/skills/devbooks-delivery-workflow/scripts/verify-slash-commands.sh +146 -0
- package/skills/devbooks-delivery-workflow/templates/handoff.md +50 -0
- package/skills/devbooks-design-backport/SKILL.md +73 -0
- package/skills/devbooks-design-backport/references//345/233/236/345/206/231/350/256/276/350/256/241/346/226/207/346/241/243/346/217/220/347/244/272/350/257/215.md +196 -0
- package/skills/devbooks-design-doc/SKILL.md +121 -0
- package/skills/devbooks-design-doc/references//345/276/256/346/234/215/345/212/241/350/256/276/350/256/241/346/270/205/345/215/225.md +149 -0
- package/skills/devbooks-design-doc/references//350/256/276/350/256/241/346/226/207/346/241/243/346/217/220/347/244/272/350/257/215.md +189 -0
- package/skills/devbooks-design-doc/references//351/232/220/347/247/201/345/220/210/350/247/204/346/243/200/346/237/245/346/270/205/345/215/225.md +240 -0
- package/skills/devbooks-entropy-monitor/SKILL.md +188 -0
- package/skills/devbooks-entropy-monitor/references//347/206/265/345/272/246/351/207/217/346/226/271/346/263/225/350/256/272.md +223 -0
- package/skills/devbooks-entropy-monitor/scripts/entropy-measure.sh +449 -0
- package/skills/devbooks-entropy-monitor/scripts/entropy-report.sh +303 -0
- package/skills/devbooks-entropy-monitor/templates/thresholds.json +99 -0
- package/skills/devbooks-federation/SKILL.md +264 -0
- package/skills/devbooks-federation/scripts/federation-check.sh +144 -0
- package/skills/devbooks-federation/templates/federation.yaml +89 -0
- package/skills/devbooks-impact-analysis/SKILL.md +135 -0
- package/skills/devbooks-impact-analysis/references//345/275/261/345/223/215/345/210/206/346/236/220/346/217/220/347/244/272/350/257/215.md +82 -0
- package/skills/devbooks-impact-analysis/scripts/graph-cache.sh +214 -0
- package/skills/devbooks-implementation-plan/SKILL.md +83 -0
- package/skills/devbooks-implementation-plan/references//347/274/226/347/240/201/350/256/241/345/210/222/346/217/220/347/244/272/350/257/215.md +99 -0
- package/skills/devbooks-index-bootstrap/SKILL.md +240 -0
- package/skills/devbooks-proposal-author/SKILL.md +83 -0
- package/skills/devbooks-proposal-author/references//346/217/220/346/241/210/346/222/260/345/206/231/346/217/220/347/244/272/350/257/215.md +66 -0
- package/skills/devbooks-proposal-challenger/SKILL.md +86 -0
- package/skills/devbooks-proposal-challenger/references//344/274/246/347/220/206/344/270/216/345/220/210/350/247/204/346/243/200/346/237/245/346/270/205/345/215/225.md +176 -0
- package/skills/devbooks-proposal-challenger/references//346/217/220/346/241/210/350/264/250/347/226/221/346/217/220/347/244/272/350/257/215.md +57 -0
- package/skills/devbooks-proposal-debate-workflow/SKILL.md +78 -0
- package/skills/devbooks-proposal-debate-workflow/references//346/217/220/346/241/210/345/257/271/350/276/251/345/267/245/344/275/234/346/265/201.md +24 -0
- package/skills/devbooks-proposal-debate-workflow/references//346/217/220/346/241/210/345/257/271/350/276/251/346/250/241/346/235/277.md +35 -0
- package/skills/devbooks-proposal-debate-workflow/scripts/proposal-debate-check.sh +102 -0
- package/skills/devbooks-proposal-judge/SKILL.md +78 -0
- package/skills/devbooks-proposal-judge/references//346/217/220/346/241/210/350/243/201/345/206/263/346/217/220/347/244/272/350/257/215.md +37 -0
- package/skills/devbooks-router/SKILL.md +346 -0
- package/skills/devbooks-spec-contract/SKILL.md +191 -0
- package/skills/devbooks-spec-contract/references/API/350/256/276/350/256/241/346/214/207/345/215/227.md +349 -0
- package/skills/devbooks-spec-contract/references//345/245/221/347/272/246/344/270/216/346/225/260/346/215/256/345/256/232/344/271/211/346/217/220/347/244/272/350/257/215.md +85 -0
- package/skills/devbooks-spec-contract/references//350/247/204/346/240/274/345/217/230/346/233/264/346/217/220/347/244/272/350/257/215.md +63 -0
- package/skills/devbooks-spec-contract/references//351/232/220/345/274/217/345/217/230/346/233/264/346/243/200/346/265/213/346/217/220/347/244/272/350/257/215.md +183 -0
- package/skills/devbooks-spec-contract/scripts/implicit-change-detect.sh +378 -0
- package/skills/devbooks-spec-gardener/SKILL.md +72 -0
- package/skills/devbooks-spec-gardener/references//350/247/204/346/240/274/345/233/255/344/270/201/346/217/220/347/244/272/350/257/215.md +41 -0
- package/skills/devbooks-test-owner/SKILL.md +172 -0
- package/skills/devbooks-test-owner/references//345/217/230/346/233/264/351/252/214/350/257/201/344/270/216/350/277/275/346/272/257/346/250/241/346/235/277.md +228 -0
- package/skills/devbooks-test-owner/references//345/274/202/346/255/245/347/263/273/347/273/237/346/265/213/350/257/225/347/255/226/347/225/245.md +316 -0
- package/skills/devbooks-test-owner/references//346/265/213/350/257/225/344/273/243/347/240/201/346/217/220/347/244/272/350/257/215.md +208 -0
- package/skills/devbooks-test-owner/references//346/265/213/350/257/225/345/210/206/345/261/202/347/255/226/347/225/245.md +281 -0
- package/skills/devbooks-test-owner/references//346/265/213/350/257/225/351/251/261/345/212/250.md +394 -0
- package/skills/devbooks-test-owner/references//350/247/243/344/276/235/350/265/226/346/212/200/346/234/257/351/200/237/346/237/245/350/241/250.md +432 -0
- package/skills/devbooks-test-reviewer/SKILL.md +189 -0
- package/templates/.devbooks/config.yaml +88 -0
- package/templates/claude-commands/devbooks/apply.md +38 -0
- package/templates/claude-commands/devbooks/archive.md +33 -0
- package/templates/claude-commands/devbooks/backport.md +19 -0
- package/templates/claude-commands/devbooks/bootstrap.md +19 -0
- package/templates/claude-commands/devbooks/c4.md +19 -0
- package/templates/claude-commands/devbooks/challenger.md +19 -0
- package/templates/claude-commands/devbooks/code.md +19 -0
- package/templates/claude-commands/devbooks/debate.md +19 -0
- package/templates/claude-commands/devbooks/delivery.md +19 -0
- package/templates/claude-commands/devbooks/design.md +19 -0
- package/templates/claude-commands/devbooks/entropy.md +19 -0
- package/templates/claude-commands/devbooks/federation.md +19 -0
- package/templates/claude-commands/devbooks/gardener.md +19 -0
- package/templates/claude-commands/devbooks/impact.md +19 -0
- package/templates/claude-commands/devbooks/index.md +19 -0
- package/templates/claude-commands/devbooks/judge.md +19 -0
- package/templates/claude-commands/devbooks/plan.md +19 -0
- package/templates/claude-commands/devbooks/proposal.md +19 -0
- package/templates/claude-commands/devbooks/quick.md +42 -0
- package/templates/claude-commands/devbooks/review.md +19 -0
- package/templates/claude-commands/devbooks/router.md +19 -0
- package/templates/claude-commands/devbooks/spec.md +19 -0
- package/templates/claude-commands/devbooks/test-review.md +19 -0
- package/templates/claude-commands/devbooks/test.md +19 -0
- package/templates/dev-playbooks/README.md +458 -0
- package/templates/dev-playbooks/changes/.gitkeep +1 -0
- package/templates/dev-playbooks/constitution.md +116 -0
- package/templates/dev-playbooks/project.md +96 -0
- package/templates/dev-playbooks/scripts/.gitkeep +1 -0
- package/templates/dev-playbooks/specs/_meta/anti-patterns/.gitkeep +2 -0
- package/templates/dev-playbooks/specs/_meta/glossary.md +47 -0
- package/templates/dev-playbooks/specs/_meta/project-profile.md +79 -0
- package/templates/dev-playbooks/specs/architecture/fitness-rules.md +95 -0
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
# 解依赖技术速查表(8 种高频技术)
|
|
2
|
+
|
|
3
|
+
> 来源:《修改代码的艺术》第 25 章(从 24 种精选)
|
|
4
|
+
> 适用角色:Test Owner / Coder
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 速查索引
|
|
9
|
+
|
|
10
|
+
| # | 技术 | 一句话描述 | 频率 | 适用场景 |
|
|
11
|
+
|---|------|----------|------|---------|
|
|
12
|
+
| 1 | Extract Interface | 提取接口隔离外部依赖 | ⭐⭐⭐ | 外部服务/数据库/第三方 API |
|
|
13
|
+
| 2 | Parameterize Constructor | 通过构造器注入依赖 | ⭐⭐⭐ | 硬编码依赖、new 操作在构造器 |
|
|
14
|
+
| 3 | Subclass and Override | 子类化并覆写方法 | ⭐⭐⭐ | 需要替换部分行为、无法修改原类 |
|
|
15
|
+
| 4 | Introduce Static Setter | 为静态依赖提供 setter | ⭐⭐ | 单例、全局对象、静态工厂 |
|
|
16
|
+
| 5 | Extract and Override Getter | 提取 getter 并覆写 | ⭐⭐ | 字段依赖、延迟初始化 |
|
|
17
|
+
| 6 | Break Out Method Object | 将方法提取为对象 | ⭐⭐ | 过长方法、复杂算法 |
|
|
18
|
+
| 7 | Adapt Parameter | 为参数创建适配器 | ⭐ | 难以 mock 的参数类型 |
|
|
19
|
+
| 8 | Encapsulate Global References | 封装全局变量 | ⭐ | 全局状态、环境变量 |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 1. Extract Interface(提取接口)
|
|
24
|
+
|
|
25
|
+
### 问题场景
|
|
26
|
+
```python
|
|
27
|
+
class OrderService:
|
|
28
|
+
def __init__(self):
|
|
29
|
+
self._payment = PaymentGateway() # 硬编码依赖真实支付网关
|
|
30
|
+
self._inventory = InventoryDB() # 硬编码依赖真实数据库
|
|
31
|
+
|
|
32
|
+
def process(self, order):
|
|
33
|
+
self._payment.charge(order.total) # 无法测试:会真实扣款
|
|
34
|
+
self._inventory.deduct(order.items)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### 解决方案
|
|
38
|
+
```python
|
|
39
|
+
# 1. 提取接口
|
|
40
|
+
class PaymentGatewayInterface(Protocol):
|
|
41
|
+
def charge(self, amount: Decimal) -> bool: ...
|
|
42
|
+
|
|
43
|
+
class InventoryInterface(Protocol):
|
|
44
|
+
def deduct(self, items: list[Item]) -> None: ...
|
|
45
|
+
|
|
46
|
+
# 2. 原类实现接口(可选)
|
|
47
|
+
class PaymentGateway(PaymentGatewayInterface):
|
|
48
|
+
def charge(self, amount): ...
|
|
49
|
+
|
|
50
|
+
# 3. 通过构造器注入
|
|
51
|
+
class OrderService:
|
|
52
|
+
def __init__(self, payment: PaymentGatewayInterface, inventory: InventoryInterface):
|
|
53
|
+
self._payment = payment
|
|
54
|
+
self._inventory = inventory
|
|
55
|
+
|
|
56
|
+
# 4. 测试时注入 Mock
|
|
57
|
+
def test_order_service():
|
|
58
|
+
mock_payment = Mock(spec=PaymentGatewayInterface)
|
|
59
|
+
mock_inventory = Mock(spec=InventoryInterface)
|
|
60
|
+
service = OrderService(mock_payment, mock_inventory)
|
|
61
|
+
service.process(order)
|
|
62
|
+
mock_payment.charge.assert_called_once_with(order.total)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 要点
|
|
66
|
+
- 接口定义"契约",实现可替换
|
|
67
|
+
- 测试时用 Mock 实现接口
|
|
68
|
+
- 生产时用真实实现
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 2. Parameterize Constructor(参数化构造器)
|
|
73
|
+
|
|
74
|
+
### 问题场景
|
|
75
|
+
```python
|
|
76
|
+
class ReportGenerator:
|
|
77
|
+
def __init__(self):
|
|
78
|
+
self._db = DatabaseConnection() # 构造器中 new 依赖
|
|
79
|
+
self._logger = FileLogger("/var/log/app.log")
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 解决方案
|
|
83
|
+
```python
|
|
84
|
+
class ReportGenerator:
|
|
85
|
+
def __init__(self, db=None, logger=None):
|
|
86
|
+
self._db = db or DatabaseConnection() # 默认值保持向后兼容
|
|
87
|
+
self._logger = logger or FileLogger("/var/log/app.log")
|
|
88
|
+
|
|
89
|
+
# 测试时
|
|
90
|
+
def test_report_generator():
|
|
91
|
+
mock_db = Mock()
|
|
92
|
+
mock_logger = Mock()
|
|
93
|
+
generator = ReportGenerator(db=mock_db, logger=mock_logger)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 要点
|
|
97
|
+
- 保留默认值,不破坏现有调用方
|
|
98
|
+
- 生产代码无需修改
|
|
99
|
+
- 测试代码可注入 Mock
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 3. Subclass and Override(子类化并覆写)
|
|
104
|
+
|
|
105
|
+
### 问题场景
|
|
106
|
+
```python
|
|
107
|
+
class PaymentProcessor:
|
|
108
|
+
def process(self, payment):
|
|
109
|
+
gateway = self._get_gateway() # 受保护方法获取真实网关
|
|
110
|
+
return gateway.charge(payment)
|
|
111
|
+
|
|
112
|
+
def _get_gateway(self):
|
|
113
|
+
return RealPaymentGateway() # 无法在测试中替换
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 解决方案
|
|
117
|
+
```python
|
|
118
|
+
# 测试时创建子类
|
|
119
|
+
class TestablePaymentProcessor(PaymentProcessor):
|
|
120
|
+
def __init__(self, mock_gateway):
|
|
121
|
+
self._mock_gateway = mock_gateway
|
|
122
|
+
|
|
123
|
+
def _get_gateway(self): # 覆写受保护方法
|
|
124
|
+
return self._mock_gateway
|
|
125
|
+
|
|
126
|
+
# 测试
|
|
127
|
+
def test_payment_processor():
|
|
128
|
+
mock_gateway = Mock()
|
|
129
|
+
processor = TestablePaymentProcessor(mock_gateway)
|
|
130
|
+
processor.process(payment)
|
|
131
|
+
mock_gateway.charge.assert_called_once()
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 要点
|
|
135
|
+
- 不修改原类,只在测试中扩展
|
|
136
|
+
- 适用于无法修改源码的情况
|
|
137
|
+
- 覆写的方法应尽量小
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 4. Introduce Static Setter(引入静态 Setter)
|
|
142
|
+
|
|
143
|
+
### 问题场景
|
|
144
|
+
```python
|
|
145
|
+
class ConfigManager:
|
|
146
|
+
_instance = None
|
|
147
|
+
|
|
148
|
+
@classmethod
|
|
149
|
+
def get_instance(cls):
|
|
150
|
+
if cls._instance is None:
|
|
151
|
+
cls._instance = cls._create_real_config() # 单例,无法替换
|
|
152
|
+
return cls._instance
|
|
153
|
+
|
|
154
|
+
class MyService:
|
|
155
|
+
def do_work(self):
|
|
156
|
+
config = ConfigManager.get_instance() # 依赖单例
|
|
157
|
+
return config.get("api_key")
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### 解决方案
|
|
161
|
+
```python
|
|
162
|
+
class ConfigManager:
|
|
163
|
+
_instance = None
|
|
164
|
+
|
|
165
|
+
@classmethod
|
|
166
|
+
def get_instance(cls):
|
|
167
|
+
if cls._instance is None:
|
|
168
|
+
cls._instance = cls._create_real_config()
|
|
169
|
+
return cls._instance
|
|
170
|
+
|
|
171
|
+
@classmethod
|
|
172
|
+
def set_instance_for_testing(cls, instance): # 新增测试用 setter
|
|
173
|
+
cls._instance = instance
|
|
174
|
+
|
|
175
|
+
@classmethod
|
|
176
|
+
def reset_instance(cls): # 测试清理
|
|
177
|
+
cls._instance = None
|
|
178
|
+
|
|
179
|
+
# 测试
|
|
180
|
+
def test_my_service():
|
|
181
|
+
mock_config = Mock()
|
|
182
|
+
mock_config.get.return_value = "test_api_key"
|
|
183
|
+
ConfigManager.set_instance_for_testing(mock_config)
|
|
184
|
+
try:
|
|
185
|
+
service = MyService()
|
|
186
|
+
result = service.do_work()
|
|
187
|
+
assert result == "test_api_key"
|
|
188
|
+
finally:
|
|
189
|
+
ConfigManager.reset_instance() # 清理
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### 要点
|
|
193
|
+
- 仅用于测试,生产代码不应调用 setter
|
|
194
|
+
- 必须在 teardown 中重置
|
|
195
|
+
- 考虑使用 pytest fixture 自动清理
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## 5. Extract and Override Getter(提取并覆写 Getter)
|
|
200
|
+
|
|
201
|
+
### 问题场景
|
|
202
|
+
```python
|
|
203
|
+
class OrderValidator:
|
|
204
|
+
def validate(self, order):
|
|
205
|
+
current_time = datetime.now() # 直接调用,无法控制时间
|
|
206
|
+
if order.expires_at < current_time:
|
|
207
|
+
raise OrderExpiredError()
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### 解决方案
|
|
211
|
+
```python
|
|
212
|
+
class OrderValidator:
|
|
213
|
+
def validate(self, order):
|
|
214
|
+
current_time = self._get_current_time() # 提取为方法
|
|
215
|
+
if order.expires_at < current_time:
|
|
216
|
+
raise OrderExpiredError()
|
|
217
|
+
|
|
218
|
+
def _get_current_time(self): # 可被覆写
|
|
219
|
+
return datetime.now()
|
|
220
|
+
|
|
221
|
+
# 测试
|
|
222
|
+
class TestableOrderValidator(OrderValidator):
|
|
223
|
+
def __init__(self, fixed_time):
|
|
224
|
+
self._fixed_time = fixed_time
|
|
225
|
+
|
|
226
|
+
def _get_current_time(self):
|
|
227
|
+
return self._fixed_time
|
|
228
|
+
|
|
229
|
+
def test_order_expired():
|
|
230
|
+
validator = TestableOrderValidator(datetime(2024, 1, 15))
|
|
231
|
+
expired_order = Order(expires_at=datetime(2024, 1, 10))
|
|
232
|
+
with pytest.raises(OrderExpiredError):
|
|
233
|
+
validator.validate(expired_order)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### 要点
|
|
237
|
+
- 将不可控的依赖(时间、随机数、环境)提取为方法
|
|
238
|
+
- 测试时通过子类覆写控制返回值
|
|
239
|
+
- 保持原有行为不变
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## 6. Break Out Method Object(方法对象化)
|
|
244
|
+
|
|
245
|
+
### 问题场景
|
|
246
|
+
```python
|
|
247
|
+
class ReportEngine:
|
|
248
|
+
def generate_complex_report(self, data, config, filters, formatters):
|
|
249
|
+
# 200 行复杂逻辑,使用大量局部变量
|
|
250
|
+
temp1 = ...
|
|
251
|
+
temp2 = ...
|
|
252
|
+
# 难以测试:方法太长,依赖太多
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### 解决方案
|
|
256
|
+
```python
|
|
257
|
+
# 将方法提取为独立类
|
|
258
|
+
class ComplexReportGenerator:
|
|
259
|
+
def __init__(self, data, config, filters, formatters):
|
|
260
|
+
self._data = data
|
|
261
|
+
self._config = config
|
|
262
|
+
self._filters = filters
|
|
263
|
+
self._formatters = formatters
|
|
264
|
+
# 原来的局部变量变成实例变量
|
|
265
|
+
self._temp1 = None
|
|
266
|
+
self._temp2 = None
|
|
267
|
+
|
|
268
|
+
def generate(self):
|
|
269
|
+
self._step1()
|
|
270
|
+
self._step2()
|
|
271
|
+
return self._finalize()
|
|
272
|
+
|
|
273
|
+
def _step1(self): # 可单独测试
|
|
274
|
+
self._temp1 = ...
|
|
275
|
+
|
|
276
|
+
def _step2(self): # 可单独测试
|
|
277
|
+
self._temp2 = ...
|
|
278
|
+
|
|
279
|
+
# 原类委托给新类
|
|
280
|
+
class ReportEngine:
|
|
281
|
+
def generate_complex_report(self, data, config, filters, formatters):
|
|
282
|
+
generator = ComplexReportGenerator(data, config, filters, formatters)
|
|
283
|
+
return generator.generate()
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### 要点
|
|
287
|
+
- 长方法拆分为多个可测试的小方法
|
|
288
|
+
- 局部变量变为实例变量,可在测试中检查中间状态
|
|
289
|
+
- 原类保持接口不变
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## 7. Adapt Parameter(参数适配器)
|
|
294
|
+
|
|
295
|
+
### 问题场景
|
|
296
|
+
```python
|
|
297
|
+
class DataProcessor:
|
|
298
|
+
def process(self, http_request: HttpRequest): # HttpRequest 难以 mock
|
|
299
|
+
data = http_request.get_json()
|
|
300
|
+
headers = http_request.headers
|
|
301
|
+
# ...
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### 解决方案
|
|
305
|
+
```python
|
|
306
|
+
# 创建适配器接口
|
|
307
|
+
class RequestData(Protocol):
|
|
308
|
+
def get_json(self) -> dict: ...
|
|
309
|
+
def get_headers(self) -> dict: ...
|
|
310
|
+
|
|
311
|
+
# 适配器包装真实对象
|
|
312
|
+
class HttpRequestAdapter:
|
|
313
|
+
def __init__(self, request: HttpRequest):
|
|
314
|
+
self._request = request
|
|
315
|
+
|
|
316
|
+
def get_json(self):
|
|
317
|
+
return self._request.get_json()
|
|
318
|
+
|
|
319
|
+
def get_headers(self):
|
|
320
|
+
return dict(self._request.headers)
|
|
321
|
+
|
|
322
|
+
# 修改方法签名
|
|
323
|
+
class DataProcessor:
|
|
324
|
+
def process(self, request: RequestData): # 依赖接口而非具体类
|
|
325
|
+
data = request.get_json()
|
|
326
|
+
headers = request.get_headers()
|
|
327
|
+
|
|
328
|
+
# 测试时
|
|
329
|
+
def test_data_processor():
|
|
330
|
+
mock_request = Mock(spec=RequestData)
|
|
331
|
+
mock_request.get_json.return_value = {"key": "value"}
|
|
332
|
+
mock_request.get_headers.return_value = {"Content-Type": "application/json"}
|
|
333
|
+
processor = DataProcessor()
|
|
334
|
+
processor.process(mock_request)
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### 要点
|
|
338
|
+
- 为难以 mock 的参数创建简化接口
|
|
339
|
+
- 生产代码使用适配器包装真实对象
|
|
340
|
+
- 测试代码直接 mock 接口
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## 8. Encapsulate Global References(封装全局引用)
|
|
345
|
+
|
|
346
|
+
### 问题场景
|
|
347
|
+
```python
|
|
348
|
+
# 全局变量
|
|
349
|
+
DATABASE_URL = os.environ.get("DATABASE_URL")
|
|
350
|
+
API_KEY = os.environ.get("API_KEY")
|
|
351
|
+
|
|
352
|
+
class MyService:
|
|
353
|
+
def connect(self):
|
|
354
|
+
return Database(DATABASE_URL) # 依赖全局变量
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### 解决方案
|
|
358
|
+
```python
|
|
359
|
+
# 封装为配置类
|
|
360
|
+
class AppConfig:
|
|
361
|
+
def __init__(self):
|
|
362
|
+
self._db_url = os.environ.get("DATABASE_URL")
|
|
363
|
+
self._api_key = os.environ.get("API_KEY")
|
|
364
|
+
|
|
365
|
+
@property
|
|
366
|
+
def database_url(self):
|
|
367
|
+
return self._db_url
|
|
368
|
+
|
|
369
|
+
@property
|
|
370
|
+
def api_key(self):
|
|
371
|
+
return self._api_key
|
|
372
|
+
|
|
373
|
+
# 注入配置
|
|
374
|
+
class MyService:
|
|
375
|
+
def __init__(self, config: AppConfig):
|
|
376
|
+
self._config = config
|
|
377
|
+
|
|
378
|
+
def connect(self):
|
|
379
|
+
return Database(self._config.database_url)
|
|
380
|
+
|
|
381
|
+
# 测试
|
|
382
|
+
def test_my_service():
|
|
383
|
+
mock_config = Mock(spec=AppConfig)
|
|
384
|
+
mock_config.database_url = "sqlite:///:memory:"
|
|
385
|
+
service = MyService(mock_config)
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### 要点
|
|
389
|
+
- 全局变量封装为可注入的配置对象
|
|
390
|
+
- 测试时可控制配置值
|
|
391
|
+
- 消除对环境的隐式依赖
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## 决策流程图
|
|
396
|
+
|
|
397
|
+
```
|
|
398
|
+
代码无法测试?
|
|
399
|
+
│
|
|
400
|
+
▼
|
|
401
|
+
┌─────────────────────────────┐
|
|
402
|
+
│ 依赖是什么类型? │
|
|
403
|
+
└──────────┬──────────────────┘
|
|
404
|
+
┌─────┼─────┬─────┬──────┐
|
|
405
|
+
▼ ▼ ▼ ▼ ▼
|
|
406
|
+
外部 构造器 单例 字段 全局
|
|
407
|
+
服务 中new 静态 依赖 变量
|
|
408
|
+
│ │ │ │ │
|
|
409
|
+
▼ ▼ ▼ ▼ ▼
|
|
410
|
+
Extract Para- Static Extract Encap-
|
|
411
|
+
Inter- meter- Setter Override sulate
|
|
412
|
+
face ize Getter Global
|
|
413
|
+
Constr-
|
|
414
|
+
uctor
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
## 与其他文档的关系
|
|
420
|
+
|
|
421
|
+
| 场景 | 参考文档 |
|
|
422
|
+
|------|---------|
|
|
423
|
+
| 需要在遗留代码中安全添加功能 | `低风险改动技术.md` |
|
|
424
|
+
| 需要找到最优测试点 | `测试驱动.md` § 7.2 Pinch Point |
|
|
425
|
+
| 需要评估改动影响 | `6 影响分析提示词.md` |
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
## 参考资料
|
|
430
|
+
|
|
431
|
+
- 《修改代码的艺术》第 25 章 - 解依赖技术
|
|
432
|
+
- dev-playbooks `devbooks-test-owner/SKILL.md`
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# DevBooks:测试评审(Test Reviewer)
|
|
2
|
+
|
|
3
|
+
## 前置:配置发现(协议无关)
|
|
4
|
+
|
|
5
|
+
执行前**必须**按以下顺序查找配置(找到后停止):
|
|
6
|
+
1. `.devbooks/config.yaml`(如存在)→ 解析并使用其中的映射
|
|
7
|
+
2. `dev-playbooks/project.md`(如存在)→ DevBooks 2.0 协议,使用默认映射
|
|
8
|
+
4. `project.md`(如存在)→ template 协议,使用默认映射
|
|
9
|
+
5. 若仍无法确定 → **停止并询问用户**
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 角色定义
|
|
14
|
+
|
|
15
|
+
**test-reviewer** 是 DevBooks Apply 阶段的专门测试评审角色,与 reviewer(代码评审)互补。
|
|
16
|
+
|
|
17
|
+
### 职责范围
|
|
18
|
+
|
|
19
|
+
| 维度 | test-reviewer | reviewer |
|
|
20
|
+
|------|:-------------:|:--------:|
|
|
21
|
+
| 评审对象 | `tests/`(测试代码) | `src/`(实现代码) |
|
|
22
|
+
| 覆盖率评估 | ✅ | ❌ |
|
|
23
|
+
| 边界条件检查 | ✅ | ❌ |
|
|
24
|
+
| 测试可读性 | ✅ | ❌ |
|
|
25
|
+
| 测试可维护性 | ✅ | ❌ |
|
|
26
|
+
| 规格一致性 | ✅(与 verification.md 对比) | ❌ |
|
|
27
|
+
| 逻辑/风格/依赖 | ❌ | ✅ |
|
|
28
|
+
| 修改代码权限 | ❌ | ❌ |
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 关键约束
|
|
33
|
+
|
|
34
|
+
### CON-ROLE-001:只评审 tests/ 目录
|
|
35
|
+
- **禁止**读取或评审 `src/` 目录下的实现代码
|
|
36
|
+
- 只关注测试文件:`tests/**`, `__tests__/**`, `*.test.*`, `*.spec.*`
|
|
37
|
+
|
|
38
|
+
### CON-ROLE-002:不修改任何代码
|
|
39
|
+
- 只输出评审意见,**禁止**直接修改文件
|
|
40
|
+
- 如需修改,只能提出建议由 Test Owner 执行
|
|
41
|
+
|
|
42
|
+
### CON-ROLE-003:检查测试与规格的一致性
|
|
43
|
+
- 必须对照 `verification.md` 检查测试是否覆盖所有 AC
|
|
44
|
+
- 如发现测试缺失,明确指出缺失的 AC-ID
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 评审维度
|
|
49
|
+
|
|
50
|
+
### 1. 覆盖率评估
|
|
51
|
+
- [ ] 所有 AC(验收准则)是否有对应测试
|
|
52
|
+
- [ ] 关键路径是否有端到端测试
|
|
53
|
+
- [ ] 边界条件是否覆盖(空值、极值、错误输入)
|
|
54
|
+
- [ ] 错误处理路径是否覆盖
|
|
55
|
+
|
|
56
|
+
### 2. 测试质量
|
|
57
|
+
- [ ] 测试是否独立(不依赖执行顺序)
|
|
58
|
+
- [ ] 测试是否可重复(无随机性或时间依赖)
|
|
59
|
+
- [ ] 断言是否明确(每个测试只验证一件事)
|
|
60
|
+
- [ ] 测试数据是否合理(避免魔法数字)
|
|
61
|
+
|
|
62
|
+
### 3. 可读性与可维护性
|
|
63
|
+
- [ ] 测试命名是否清晰(describe/it 描述业务意图)
|
|
64
|
+
- [ ] 测试结构是否一致(Given-When-Then 或 Arrange-Act-Assert)
|
|
65
|
+
- [ ] 是否有适当的测试工具函数(避免重复代码)
|
|
66
|
+
- [ ] 是否有必要的注释(复杂测试场景)
|
|
67
|
+
|
|
68
|
+
### 4. 规格一致性
|
|
69
|
+
- [ ] 测试是否与 `verification.md` 的 VT-ID 对应
|
|
70
|
+
- [ ] 测试场景是否与 AC 场景一致
|
|
71
|
+
- [ ] 是否有额外测试(未在规格中的行为)
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 执行流程
|
|
76
|
+
|
|
77
|
+
1. **读取规格**:打开 `<change-root>/<change-id>/verification.md`,了解测试计划
|
|
78
|
+
2. **定位测试文件**:根据 verification.md 中的追溯矩阵定位对应测试
|
|
79
|
+
3. **逐项评审**:按评审维度检查每个测试文件
|
|
80
|
+
4. **输出报告**:生成评审报告,包含问题列表和建议
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 输出格式
|
|
85
|
+
|
|
86
|
+
```markdown
|
|
87
|
+
# Test Review Report: <change-id>
|
|
88
|
+
|
|
89
|
+
## 概览
|
|
90
|
+
- 评审日期:YYYY-MM-DD
|
|
91
|
+
- 评审范围:`tests/feature-x/`
|
|
92
|
+
- 测试文件数:N
|
|
93
|
+
- 问题总数:N(Critical: N, Major: N, Minor: N)
|
|
94
|
+
|
|
95
|
+
## 覆盖率分析
|
|
96
|
+
|
|
97
|
+
| AC-ID | 测试文件 | 覆盖状态 | 备注 |
|
|
98
|
+
|-------|----------|----------|------|
|
|
99
|
+
| AC-001 | test-a.ts | ✅ 已覆盖 | - |
|
|
100
|
+
| AC-002 | - | ❌ 缺失 | 需要添加 |
|
|
101
|
+
| AC-003 | test-b.ts | ⚠️ 部分覆盖 | 缺少边界条件 |
|
|
102
|
+
|
|
103
|
+
## 问题清单
|
|
104
|
+
|
|
105
|
+
### Critical (必须修复)
|
|
106
|
+
1. **[C-001]** `test-a.ts:42` - 测试依赖外部服务,无 mock
|
|
107
|
+
- 建议:添加 mock,确保测试独立
|
|
108
|
+
|
|
109
|
+
### Major (建议修复)
|
|
110
|
+
1. **[M-001]** `test-b.ts` - 缺少错误路径测试
|
|
111
|
+
- 建议:添加 `expect(...).toThrow()` 测试
|
|
112
|
+
|
|
113
|
+
### Minor (可选修复)
|
|
114
|
+
1. **[m-001]** `test-c.ts:15` - 测试命名不清晰
|
|
115
|
+
- 建议:`it('should do X')` 改为 `it('should return Y when given X')`
|
|
116
|
+
|
|
117
|
+
## 建议
|
|
118
|
+
|
|
119
|
+
1. [建议1]
|
|
120
|
+
2. [建议2]
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
*此报告由 devbooks-test-reviewer 生成*
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## 与其他角色的交互
|
|
129
|
+
|
|
130
|
+
| 场景 | 交互方 | 动作 |
|
|
131
|
+
|------|--------|------|
|
|
132
|
+
| 发现测试缺失 | Test Owner | 提出建议,由 Test Owner 补充测试 |
|
|
133
|
+
| 发现测试与规格不一致 | Test Owner | 提出问题,确认是规格问题还是测试问题 |
|
|
134
|
+
| 发现实现问题(通过测试) | Reviewer | 通知 Reviewer 关注,不直接评审实现 |
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 元数据
|
|
139
|
+
|
|
140
|
+
| 字段 | 值 |
|
|
141
|
+
|------|-----|
|
|
142
|
+
| Skill 名称 | devbooks-test-reviewer |
|
|
143
|
+
| 阶段 | Apply |
|
|
144
|
+
| 产物 | 评审报告(不写入变更包) |
|
|
145
|
+
| 约束 | CON-ROLE-001~003 |
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 上下文感知
|
|
150
|
+
|
|
151
|
+
本 Skill 在执行前自动检测上下文,选择合适的评审范围。
|
|
152
|
+
|
|
153
|
+
检测规则参考:`skills/_shared/context-detection-template.md`
|
|
154
|
+
|
|
155
|
+
### 检测流程
|
|
156
|
+
|
|
157
|
+
1. 检测 `verification.md` 是否存在
|
|
158
|
+
2. 检测测试文件变更范围
|
|
159
|
+
3. 检测 AC 覆盖状态
|
|
160
|
+
|
|
161
|
+
### 本 Skill 支持的模式
|
|
162
|
+
|
|
163
|
+
| 模式 | 触发条件 | 行为 |
|
|
164
|
+
|------|----------|------|
|
|
165
|
+
| **完整评审** | 新变更包首次评审 | 评审所有测试文件 |
|
|
166
|
+
| **增量评审** | 已有评审报告 | 只评审新增/修改的测试 |
|
|
167
|
+
| **覆盖率检查** | 带 --coverage 参数 | 只检查 AC 覆盖情况 |
|
|
168
|
+
|
|
169
|
+
### 检测输出示例
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
检测结果:
|
|
173
|
+
- verification.md:存在
|
|
174
|
+
- 测试文件变更:5 个
|
|
175
|
+
- AC 覆盖状态:8/10
|
|
176
|
+
- 运行模式:增量评审
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## MCP 增强
|
|
182
|
+
|
|
183
|
+
本 Skill 不依赖 MCP 服务,无需运行时检测。
|
|
184
|
+
|
|
185
|
+
MCP 增强规则参考:`skills/_shared/mcp-enhancement-template.md`
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
*此 Skill 文档遵循 devbooks-* 规范。*
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# .devbooks/config.yaml
|
|
2
|
+
# DevBooks Protocol Discovery Configuration
|
|
3
|
+
#
|
|
4
|
+
# 此文件由 DevBooks 自动生成,用于让 AI 自动发现项目配置。
|
|
5
|
+
# 请勿随意删除或修改,除非你清楚每个字段的含义。
|
|
6
|
+
|
|
7
|
+
# ==================== DevBooks 配置 ====================
|
|
8
|
+
|
|
9
|
+
# 根目录
|
|
10
|
+
root: dev-playbooks/
|
|
11
|
+
|
|
12
|
+
# 宪法文件(强制加载)
|
|
13
|
+
constitution: constitution.md
|
|
14
|
+
|
|
15
|
+
# 项目上下文
|
|
16
|
+
project: project.md
|
|
17
|
+
|
|
18
|
+
# 路径配置
|
|
19
|
+
paths:
|
|
20
|
+
specs: specs/
|
|
21
|
+
changes: changes/
|
|
22
|
+
scripts: scripts/
|
|
23
|
+
staged: specs/_staged/
|
|
24
|
+
anti_patterns: specs/_meta/anti-patterns/
|
|
25
|
+
|
|
26
|
+
# ==================== 向后兼容配置 ====================
|
|
27
|
+
|
|
28
|
+
# 目录根映射(向后兼容)
|
|
29
|
+
truth_root: dev-playbooks/specs/
|
|
30
|
+
change_root: dev-playbooks/changes/
|
|
31
|
+
|
|
32
|
+
# 规则文档位置
|
|
33
|
+
agents_doc: dev-playbooks/project.md
|
|
34
|
+
|
|
35
|
+
# 项目画像(可选)
|
|
36
|
+
project_profile: dev-playbooks/specs/_meta/project-profile.md
|
|
37
|
+
|
|
38
|
+
# ==================== 协议约束 ====================
|
|
39
|
+
|
|
40
|
+
constraints:
|
|
41
|
+
# apply 阶段是否必须指定角色
|
|
42
|
+
apply_requires_role: true
|
|
43
|
+
|
|
44
|
+
# apply 阶段可用角色
|
|
45
|
+
apply_roles:
|
|
46
|
+
- test-owner
|
|
47
|
+
- coder
|
|
48
|
+
- reviewer
|
|
49
|
+
- test-reviewer
|
|
50
|
+
|
|
51
|
+
# Test Owner 与 Coder 是否必须独立对话
|
|
52
|
+
role_isolation: true
|
|
53
|
+
|
|
54
|
+
# Coder 是否禁止修改 tests/
|
|
55
|
+
coder_no_tests: true
|
|
56
|
+
|
|
57
|
+
# 是否启用结构质量守门
|
|
58
|
+
structural_guardrails: true
|
|
59
|
+
|
|
60
|
+
# 是否强制加载宪法
|
|
61
|
+
require_constitution: true
|
|
62
|
+
|
|
63
|
+
# ==================== 适应度函数配置 ====================
|
|
64
|
+
|
|
65
|
+
fitness:
|
|
66
|
+
# 适应度检查模式:error(阻断)| warn(警告)| off(关闭)
|
|
67
|
+
mode: warn
|
|
68
|
+
|
|
69
|
+
# 规则文件路径
|
|
70
|
+
rules_file: specs/architecture/fitness-rules.md
|
|
71
|
+
|
|
72
|
+
# ==================== AC 追溯配置 ====================
|
|
73
|
+
|
|
74
|
+
tracing:
|
|
75
|
+
# AC 覆盖率阈值
|
|
76
|
+
coverage_threshold: 80
|
|
77
|
+
|
|
78
|
+
# 输出格式:text | json
|
|
79
|
+
output_format: text
|
|
80
|
+
|
|
81
|
+
# ==================== 提案阶段配置 ====================
|
|
82
|
+
|
|
83
|
+
proposal:
|
|
84
|
+
# 是否启用三角对辩(Author/Challenger/Judge)
|
|
85
|
+
enable_debate: true
|
|
86
|
+
|
|
87
|
+
# 是否需要 Impact Analysis(跨模块变更)
|
|
88
|
+
require_impact_analysis: true
|