newbee-sdd 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/README.md +167 -0
- package/SKILL.md +128 -0
- package/bin/newbee-sdd.js +120 -0
- package/lib/index.js +12 -0
- package/lib/installer.js +178 -0
- package/lib/updater.js +40 -0
- package/lib/verifier.js +197 -0
- package/package.json +39 -0
- package/references/architecture-guide.md +45 -0
- package/references/checklists.md +75 -0
- package/references/schemes.md +54 -0
- package/references/stages.md +75 -0
- package/scripts/newbee-sdd-check.ps1 +242 -0
- package/templates/CONVENTIONS.md +23 -0
- package/templates/INDEX.md +11 -0
- package/templates/plan.md +74 -0
- package/templates/spec.md +59 -0
- package/templates/tasks.md +28 -0
- package/upgrade.md +46 -0
package/lib/verifier.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const FUZZY_WORDS = ['快速', '适当地', '必要时', '尽量', '合理地', '等等', '及时', '高效', '适当', '合理'];
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 寻找项目中的 specs 目录或 spec.md 文件
|
|
8
|
+
*/
|
|
9
|
+
function findSpecsDir(baseDir) {
|
|
10
|
+
// 1. 检查 .newbee-specs-path 指针
|
|
11
|
+
const pointerFile = path.join(baseDir, '.newbee-specs-path');
|
|
12
|
+
if (fs.existsSync(pointerFile)) {
|
|
13
|
+
const raw = fs.readFileSync(pointerFile, 'utf8').trim();
|
|
14
|
+
if (raw && fs.existsSync(raw)) {
|
|
15
|
+
return raw;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// 2. 候选目录列表
|
|
20
|
+
const candidates = [
|
|
21
|
+
path.join(baseDir, 'newbee-specs'),
|
|
22
|
+
path.join(baseDir, 'specs'),
|
|
23
|
+
path.join(baseDir, 'docs', 'sdd'),
|
|
24
|
+
path.join(baseDir, 'spec')
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
for (const cand of candidates) {
|
|
28
|
+
if (fs.existsSync(cand) && fs.statSync(cand).isDirectory()) {
|
|
29
|
+
return cand;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 3. 根目录单文件 spec.md
|
|
34
|
+
const singleSpec = path.join(baseDir, 'spec.md');
|
|
35
|
+
if (fs.existsSync(singleSpec)) {
|
|
36
|
+
return singleSpec;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 递归读取所有 markdown 文件
|
|
44
|
+
*/
|
|
45
|
+
function getMarkdownFiles(targetPath) {
|
|
46
|
+
if (!fs.existsSync(targetPath)) return [];
|
|
47
|
+
if (fs.statSync(targetPath).isFile()) {
|
|
48
|
+
return [targetPath];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const results = [];
|
|
52
|
+
const entries = fs.readdirSync(targetPath, { withFileTypes: true });
|
|
53
|
+
for (const entry of entries) {
|
|
54
|
+
const fullPath = path.join(targetPath, entry.name);
|
|
55
|
+
if (entry.isDirectory()) {
|
|
56
|
+
// 排除 node_modules 和 .git
|
|
57
|
+
if (entry.name !== 'node_modules' && entry.name !== '.git') {
|
|
58
|
+
results.push(...getMarkdownFiles(fullPath));
|
|
59
|
+
}
|
|
60
|
+
} else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
61
|
+
results.push(fullPath);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return results;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 核心校验逻辑
|
|
69
|
+
*/
|
|
70
|
+
function verify(projectDir = process.cwd()) {
|
|
71
|
+
const specsTarget = findSpecsDir(projectDir);
|
|
72
|
+
console.log(`\n🔍 [newbee-sdd] 正在扫描工程规格...`);
|
|
73
|
+
console.log(`📁 基准目录: ${projectDir}`);
|
|
74
|
+
|
|
75
|
+
if (!specsTarget) {
|
|
76
|
+
console.log(`⚠️ 未发现任何 specs 目录或 spec.md (已扫描 newbee-specs/, specs/, docs/sdd/, spec.md)`);
|
|
77
|
+
console.log(`💡 提示: 可运行 \`npx newbee-sdd init\` 初始化规格目录。\n`);
|
|
78
|
+
return { ok: false, message: '未找到规格文件' };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log(`📄 锁定规格路径: ${specsTarget}\n`);
|
|
82
|
+
|
|
83
|
+
const files = getMarkdownFiles(specsTarget);
|
|
84
|
+
if (files.length === 0) {
|
|
85
|
+
console.log(`⚠️ 规格路径下没有发现 .md 文件。\n`);
|
|
86
|
+
return { ok: false, message: '空规格目录' };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const reqs = new Set();
|
|
90
|
+
const rules = new Set();
|
|
91
|
+
const tcs = new Set();
|
|
92
|
+
const tasks = new Set();
|
|
93
|
+
const tcCoveredReqs = new Set();
|
|
94
|
+
const tcCoveredRules = new Set();
|
|
95
|
+
const untrackedItems = [];
|
|
96
|
+
const fuzzyHits = [];
|
|
97
|
+
|
|
98
|
+
const reqRegex = /\b(REQ-[A-Z0-9_-]+)\b/g;
|
|
99
|
+
const ruleRegex = /\b(RULE-[A-Z0-9_-]+)\b/g;
|
|
100
|
+
const tcRegex = /\b(TC-[A-Z0-9_-]+)\b/g;
|
|
101
|
+
const taskRegex = /\b(TASK-[A-Z0-9_-]+)\b/g;
|
|
102
|
+
|
|
103
|
+
for (const file of files) {
|
|
104
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
105
|
+
const relFile = path.relative(projectDir, file);
|
|
106
|
+
const lines = content.split('\n');
|
|
107
|
+
|
|
108
|
+
lines.forEach((line, idx) => {
|
|
109
|
+
const lineNum = idx + 1;
|
|
110
|
+
|
|
111
|
+
// 检查 [untracked]
|
|
112
|
+
if (line.includes('[untracked]')) {
|
|
113
|
+
untrackedItems.push({ file: relFile, line: lineNum, text: line.trim() });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// 检查模糊词
|
|
117
|
+
for (const word of FUZZY_WORDS) {
|
|
118
|
+
if (line.includes(word) && !line.startsWith('#') && !line.includes('FUZZY_WORDS')) {
|
|
119
|
+
fuzzyHits.push({ file: relFile, line: lineNum, word, text: line.trim() });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// 收集定义与引用
|
|
124
|
+
let m;
|
|
125
|
+
while ((m = reqRegex.exec(line)) !== null) reqs.add(m[1]);
|
|
126
|
+
while ((m = ruleRegex.exec(line)) !== null) rules.add(m[1]);
|
|
127
|
+
while ((m = tcRegex.exec(line)) !== null) tcs.add(m[1]);
|
|
128
|
+
while ((m = taskRegex.exec(line)) !== null) tasks.add(m[1]);
|
|
129
|
+
|
|
130
|
+
// 简单关联捕获:同行内同时出现 TC 与 REQ/RULE
|
|
131
|
+
const lineTcs = line.match(tcRegex);
|
|
132
|
+
if (lineTcs) {
|
|
133
|
+
const lineReqs = line.match(reqRegex);
|
|
134
|
+
const lineRules = line.match(ruleRegex);
|
|
135
|
+
if (lineReqs) lineReqs.forEach(r => tcCoveredReqs.add(r));
|
|
136
|
+
if (lineRules) lineRules.forEach(r => tcCoveredRules.add(r));
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
console.log(`📊 【ID 统计清单】`);
|
|
142
|
+
console.log(` • REQ (需求项): ${reqs.size} 个`);
|
|
143
|
+
console.log(` • RULE (业务规则): ${rules.size} 个`);
|
|
144
|
+
console.log(` • TC (测试用例): ${tcs.size} 个`);
|
|
145
|
+
console.log(` • TASK (拆解任务): ${tasks.size} 个`);
|
|
146
|
+
console.log('────────────────────────────────────────');
|
|
147
|
+
|
|
148
|
+
let hasErrors = false;
|
|
149
|
+
|
|
150
|
+
// 1. 检查 untracked
|
|
151
|
+
if (untrackedItems.length > 0) {
|
|
152
|
+
console.log(`\n❌ [FAIL] 发现 ${untrackedItems.length} 处未追溯项 [untracked]:`);
|
|
153
|
+
untrackedItems.forEach(item => {
|
|
154
|
+
console.log(` - ${item.file}:${item.line} -> ${item.text.slice(0, 80)}`);
|
|
155
|
+
});
|
|
156
|
+
hasErrors = true;
|
|
157
|
+
} else {
|
|
158
|
+
console.log(`✅ 追溯标签检查: 无孤立 [untracked] 标记`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// 2. 检查模糊词
|
|
162
|
+
if (fuzzyHits.length > 0) {
|
|
163
|
+
console.log(`\n⚠️ [WARN] 发现 ${fuzzyHits.length} 处可能引发歧义的模糊词:`);
|
|
164
|
+
fuzzyHits.slice(0, 10).forEach(hit => {
|
|
165
|
+
console.log(` - [${hit.word}] ${hit.file}:${hit.line} -> ${hit.text.slice(0, 60)}`);
|
|
166
|
+
});
|
|
167
|
+
if (fuzzyHits.length > 10) {
|
|
168
|
+
console.log(` ... 以及其余 ${fuzzyHits.length - 10} 处`);
|
|
169
|
+
}
|
|
170
|
+
} else {
|
|
171
|
+
console.log(`✅ 规格严谨度: 未发现常见模糊词汇`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 3. 检查覆盖闭环
|
|
175
|
+
const uncoveredReqs = [...reqs].filter(r => !tcCoveredReqs.has(r));
|
|
176
|
+
if (reqs.size > 0 && tcs.size > 0 && uncoveredReqs.length > 0) {
|
|
177
|
+
console.log(`\n⚠️ [WARN] 以下 REQ 未在行内显式关联 TC 映射 (需确认是否有单独 RTM 矩阵覆盖):`);
|
|
178
|
+
uncoveredReqs.slice(0, 5).forEach(r => console.log(` - ${r}`));
|
|
179
|
+
if (uncoveredReqs.length > 5) console.log(` ... 等共 ${uncoveredReqs.length} 个需求`);
|
|
180
|
+
} else if (reqs.size > 0 && tcs.size > 0) {
|
|
181
|
+
console.log(`✅ 闭环追溯: 所有 REQ 均已有关联 TC`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
console.log('\n════════════════════════════════════════');
|
|
185
|
+
if (hasErrors) {
|
|
186
|
+
console.log(`🚫 校验未通过,请修复上述问题后再次执行。\n`);
|
|
187
|
+
return { ok: false };
|
|
188
|
+
} else {
|
|
189
|
+
console.log(`🎉 [PASS] SDD 规格追溯检查全部通过!\n`);
|
|
190
|
+
return { ok: true };
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
module.exports = {
|
|
195
|
+
verify,
|
|
196
|
+
findSpecsDir
|
|
197
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "newbee-sdd",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "规格驱动开发(SDD)工作流与多工具适配套件 - 支持 dsh, OpenCode, Claude Code, Cursor, Codex",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"newbee-sdd": "bin/newbee-sdd.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"lib",
|
|
12
|
+
"SKILL.md",
|
|
13
|
+
"references",
|
|
14
|
+
"templates",
|
|
15
|
+
"scripts",
|
|
16
|
+
"upgrade.md",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"test": "node bin/newbee-sdd.js --help"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"sdd",
|
|
24
|
+
"spec-driven-development",
|
|
25
|
+
"opencode",
|
|
26
|
+
"claude-code",
|
|
27
|
+
"cursor",
|
|
28
|
+
"deepseek-harness",
|
|
29
|
+
"dsh",
|
|
30
|
+
"codex",
|
|
31
|
+
"agent-skills",
|
|
32
|
+
"prompt-engineering"
|
|
33
|
+
],
|
|
34
|
+
"author": "qieb",
|
|
35
|
+
"license": "MIT",
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=16.0.0"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# 架构设计与防御性工程指南(architecture-guide)
|
|
2
|
+
|
|
3
|
+
> 本文件为 L 轨深度技术方案(`plan.md`)的核心设计指引,融合 C4 模型、单一职责模块切分与外部集成失败模式设计。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. C4 架构分层设计原则
|
|
8
|
+
|
|
9
|
+
在 `plan.md` 中画系统架构图时,采用 C4 模型的自顶向下视角:
|
|
10
|
+
|
|
11
|
+
1. **Context(系统上下文图)**:明确本系统与外部用户、第三方系统之间的边界与核心数据流。
|
|
12
|
+
2. **Container(容器与进程图)**:展示服务、前端单页、API 网关、数据库、消息队列之间的通信协议(HTTP/gRPC/Kafka)。
|
|
13
|
+
3. **Component(组件/模块图)**:将业务拆解为具有单一职责的逻辑模块(MOD-###)。
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 2. 模块切分规范(MOD-###)
|
|
18
|
+
|
|
19
|
+
- **单一职责原则**:每个模块只负责一个清晰的业务域(如 `MOD-010 订单状态机`、`MOD-020 库存预扣器`)。
|
|
20
|
+
- **无环依赖铁律**:模块间的依赖关系必须保持严格的单向流动,禁止任何双向循环依赖(A 依赖 B,B 依赖 A)。
|
|
21
|
+
- **REQ 承载映射**:每一个在 `spec.md` 中定义的 Must REQ,在技术方案中必须能明确找到至少一个承载它的 MOD 模块。
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 3. 外部依赖集成与失败模式设计(必填项)
|
|
26
|
+
|
|
27
|
+
对于任何外部系统依赖(第三方 API、外部数据库、外部 RPC),在技术方案中**必须显式提供以下 5 项防御性设计**:
|
|
28
|
+
|
|
29
|
+
| 防御维度 | 设计标准与要求 | 示例 |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| **超时机制 (Timeout)** | 显式定义连接超时与读取超时,杜绝线程挂起与级联雪崩 | `ConnectTimeout: 1000ms`, `ReadTimeout: 3000ms` |
|
|
32
|
+
| **重试策略 (Retry)** | 必须采用指数退避(Exponential Backoff)与抖动(Jitter),且仅对幂等操作重试 | 重试 3 次,间隔 `100ms, 200ms, 400ms` |
|
|
33
|
+
| **幂等性保证 (Idempotency)** | 写入与扣减操作必须带业务唯一流水号或幂等 Token | 请求头带 `X-Idempotency-Key: UUID`,数据库唯一索引兜底 |
|
|
34
|
+
| **熔断与降级 (Fallback)** | 当失败率超过阈值时触发熔断,并提供确定性降级返回值 | 熔断后返回本地二级缓存数据或友好降级提示 |
|
|
35
|
+
| **数据补偿机制 (Compensation)** | 出现网络分区或最终不一致时的对账与补偿手段 | 发送异步重试消息队列,人工核对工作流 |
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 4. NFR(非功能需求)架构建模映射
|
|
40
|
+
|
|
41
|
+
任何一条 NFR 需求不得凭空悬挂,必须在架构方案中找到对应的实现手段:
|
|
42
|
+
|
|
43
|
+
* **性能 NFR**(如响应时间 P99 ≤ 200ms)→ 必须映射为:索引优化、Redis 缓存穿透防范、批量批处理拉取。
|
|
44
|
+
* **高可用 NFR**(如可用性 99.9%)→ 必须映射为:主从多可用区容灾、健康检查探针、优雅停机(Graceful Shutdown)。
|
|
45
|
+
* **安全 NFR**(如防 SQL 注入、合规脱敏)→ 必须映射为:ORM 参数化绑定、敏感日志掩码拦截器。
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# 审查清单(checklists)
|
|
2
|
+
|
|
3
|
+
> Fresh-Context 复审指南:在支持 Subagent 的宿主中,将对应阶段的审查清单连同工件文件路径一同输入给独立子代理;审者逐项给出 PASS / FAIL / N.A. 结论与 FIND 清单,不省略任何检查项。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. 规格审查(spec 五项)
|
|
8
|
+
|
|
9
|
+
| # | 检查维度 | FAIL 判定标准 |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| 1 | **需求完整性** | 用户已确认的澄清结论未被 spec 吸纳;需求歧义被模型私自静默拍板 |
|
|
12
|
+
| 2 | **可验证性** | REQ 缺少 Given/When/Then 验收条件;NFR 缺少可量化数值或量测方式;出现模糊词(快速/适当地/必要时/尽量/合理地/等等) |
|
|
13
|
+
| 3 | **覆盖率闭环** | TC 未 100% 覆盖 REQ 与 RULE(以机器校验脚本输出为准);存在孤儿 RULE(无 REQ 引用或无 TC 对应) |
|
|
14
|
+
| 4 | **契约一致性** | 接口/数据契约与需求描述中的字段、类型、必填性产生冲突;需求前后矛盾或职责重叠 |
|
|
15
|
+
| 5 | **全链路追溯性** | 存在未标记来源的孤立内容([untracked]);DEC 决策缺少上下文与后果说明(Context/Consequences) |
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 2. 方案与架构审查(plan & architecture 六项)
|
|
20
|
+
|
|
21
|
+
| # | 检查维度 | FAIL 判定标准 |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| 1 | **选型依据** | 架构选型结论未回链到具体 NFR-### 或 DEC-###;以“我比较熟”或“业界流行”作为唯一技术选型理由 |
|
|
24
|
+
| 2 | **Scope 对齐** | 方案涉及了 spec 之外的未经批准的端点或数据实体(范围蔓延 scope creep),或遗漏了 spec 内已声明的范围 |
|
|
25
|
+
| 3 | **C4 模块单一职责** | MOD-### 模块职责模糊、存在循环依赖(依赖图有环);Must REQ 未能 100% 映射到承载模块 |
|
|
26
|
+
| 4 | **失败模式防御** | 新增的外部系统依赖缺少超时、重试、幂等、熔断/降级、补偿机制中的任何一项 |
|
|
27
|
+
| 5 | **接口契约一致** | 模块对外接口或 API 定义与数据模型字段类型、必填项、错误码不一致 |
|
|
28
|
+
| 6 | **技术假设验证** | 存在高风险的关键技术假设但未制定 PoC / Spike 探针验证任务 |
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 3. 代码审查(code 四维)
|
|
33
|
+
|
|
34
|
+
| 审查维度 | 检查重点与判定标准 |
|
|
35
|
+
|---|---|
|
|
36
|
+
| **Bug 与正确性** | 逻辑错误、边界条件越界、并发安全与死锁、异常捕获缺失、连接与文件资源泄露 |
|
|
37
|
+
| **性能表现** | N+1 查询、大结果集未分页、不必要的全局同步锁、重复序列化与计算(对照 NFR 目标核查) |
|
|
38
|
+
| **系统安全** | SQL/代码注入漏洞、越权访问、敏感信息/秘钥打印到日志、输入参数未校验 |
|
|
39
|
+
| **代码可维护性** | 命名晦涩、大段重复代码、违反单一职责原则、缺少单元测试、硬编码魔法值 |
|
|
40
|
+
|
|
41
|
+
> **规格符合性附加项**:逐条核对代码是否严格遵循对应 TASK 所指派的 REQ/RULE 业务验收条件,任何偏离均记录为 Blocker 或 Major FIND。
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 4. 任务与 RTM 审查(tasks & RTM 三项)
|
|
46
|
+
|
|
47
|
+
| # | 检查维度 | FAIL 判定标准 |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| 1 | **任务粒度** | 单个任务工作量超过 2 天,或职责不单一无法独立验证 |
|
|
50
|
+
| 2 | **RTM 全覆盖** | 存在 Must REQ 未被任何 TASK 承接;存在 TC 未被测试任务覆盖 |
|
|
51
|
+
| 3 | **无环依赖** | 任务拓扑排序存在死锁循环依赖(A 依赖 B,B 依赖 A) |
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 5. 收尾与发布审查(release 四项)
|
|
56
|
+
|
|
57
|
+
| # | 检查维度 | FAIL 判定标准 |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| 1 | **RTM 状态真实性** | 存在“代码已实现(done)但关联 TC 未实际运行/未通过”的条目被计入完成 |
|
|
60
|
+
| 2 | **核心需求达成率** | Must REQ 完成率未达到 100%(且缺口未逐项取得书面豁免) |
|
|
61
|
+
| 3 | **遗留缺陷闭环** | 存在未处理的开放 FIND,未转为后续跟踪 ID 也未取得负责人书面豁免 |
|
|
62
|
+
| 4 | **版本与索引一致** | `INDEX.md` 全局索引表中的状态与功能夹层 spec.md 的 frontmatter 状态不一致 |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 统一 FIND 报告标准输出格式
|
|
67
|
+
|
|
68
|
+
复审者输出统一采用结构化格式:
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
FIND-### | 严重级别(Blocker/Major/Minor)| 位置(文件:行号 或 章节名)| 缺陷描述 | 建议修复方案 | 处置结论(转正为 DEC-/TASK-###,或豁免:理由+决策人)
|
|
72
|
+
|
|
73
|
+
审查裁定:APPROVE / REQUEST-CHANGES
|
|
74
|
+
(存在任何一条 Blocker 级别问题时,结论一律强制判定为 REQUEST-CHANGES)
|
|
75
|
+
```
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# 方案识别与共存(schemes)
|
|
2
|
+
|
|
3
|
+
> Stage 0 阶段的识别字典。newbee-sdd 与其他 SDD 方案共存的原则:**一仓一案、物理隔离、身份行判别、保护存量**。
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. 识别特征表
|
|
8
|
+
|
|
9
|
+
| 方案类别 | 默认正本路径 | 核心识别特征 | 状态枚举 |
|
|
10
|
+
|---|---|---|---|
|
|
11
|
+
| **newbee-sdd** | `newbee-specs/`(或 `.newbee-specs-path` 覆盖处) | 工件头部 `scheme: newbee-sdd v1`;夹层 `NNN-name/`;`INDEX.md` | draft / approved / implementing / done / blocked / deprecated |
|
|
12
|
+
| **原 SDD Pack (gen2)** | `docs/sdd/` | 固定文件名组(`clarification.md`、`review-report.md` 等七件套);Verdict 判定行 | PASS / PASS-WITH-FIXES / FAIL |
|
|
13
|
+
| **Spec Kit 风格 (gen3)**| `specs/` | `constitution.md` + `NNN-feature/`;frontmatter 含 id/status/owner | draft / in-review / approved / implementing / done / deprecated |
|
|
14
|
+
| **轻量/未知方案** | 根目录 `spec.md` 或任意 | 存在规格文档但无统一约束标记 | — |
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 2. 优先级链(规则冲突时自顶向下生效)
|
|
19
|
+
|
|
20
|
+
1. **项目既有流程与资产**:项目已有工单系统、CI 质量门禁、已有的自有 SDD 正本、既有 Code Review 流程 —— 具有最高权威,永不暴力覆盖。
|
|
21
|
+
2. **`newbee-specs/CONVENTIONS.md`**:项目针对 newbee-sdd 声明的定制规则(可附加、可加严)。
|
|
22
|
+
3. **newbee-sdd 核心默认值**:兜底规则。
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 3. 共存与保护决策(检测到存量工件时)
|
|
27
|
+
|
|
28
|
+
| 检测场景 | newbee-sdd 处理策略 |
|
|
29
|
+
|---|---|
|
|
30
|
+
| **项目已有自有 SDD 方案,且用户未显式点名 newbee** | **主动礼让**:输出提示「检测到项目存在自有规格正本,newbee-sdd 待命并让位」,不擅自创建新结构。 |
|
|
31
|
+
| **用户明确点名启用 newbee(房客模式)** | 工件收敛在 `newbee-specs/` 中,绝不破坏原有正本文件;工件中通过超链接引用原项目既有规范。 |
|
|
32
|
+
| **存量旧版工件(如已有 `docs/sdd/` 或 `specs/`)需要继续演进** | **向后兼容模式**:直接读取现存的 `requirements.md`、`plan.md` 等文件并继承上下文,在已有 ID 体系上继续扩展,无需推倒重来。 |
|
|
33
|
+
| **用户明确要求将旧方案工件统一迁移到 newbee** | 执行平滑迁移:为旧工件补充 `scheme: newbee-sdd v1` 头,并按照状态映射表对齐状态,旧正本原地保留或归档。 |
|
|
34
|
+
| **无法归类的未知工程规范** | 停下向用户确认意图,绝不擅自猜测覆盖。 |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 4. 状态映射与向下兼容
|
|
39
|
+
|
|
40
|
+
| 存量来源状态 | newbee-sdd 对齐状态 |
|
|
41
|
+
|---|---|
|
|
42
|
+
| draft | draft |
|
|
43
|
+
| in-review / approved | approved |
|
|
44
|
+
| in-progress / implementing | implementing |
|
|
45
|
+
| implemented / done | done |
|
|
46
|
+
| archived / deprecated | deprecated |
|
|
47
|
+
| blocked | blocked |
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 5. ID 标号向前兼容性
|
|
52
|
+
|
|
53
|
+
- 迁入或继承的旧工件中,现有的 `REQ-###`、`RULE-###`、`TC-###` **完全保留原编号**(遵循 ID 终身不可变更的铁律)。
|
|
54
|
+
- 在头部加上 `scheme: newbee-sdd v1` 后,全链路机器校验脚本(`npx newbee-sdd verify`)即可无缝完成追溯链对账。
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# 阶段细则(stages)
|
|
2
|
+
|
|
3
|
+
> 各阶段的输入、输出与验证细则。入口流程与闸门见 SKILL.md,本文展开工程细节。
|
|
4
|
+
|
|
5
|
+
## Stage 0 — 方案地图(任何写入之前必做)
|
|
6
|
+
|
|
7
|
+
| 检查项 | 规则与行为 |
|
|
8
|
+
|---|---|
|
|
9
|
+
| **扫描点** | 项目根:`newbee-specs/`、`.newbee-specs-path`、`specs/`、`spec/`、`docs/sdd/`、`constitution.md`;项目 AGENTS.md 中的方案声明 |
|
|
10
|
+
| **产出报告** | 三行报告:自有正本(不碰)/`CONVENTIONS.md` 定制(按它执行)/newbee 默认值(其余) |
|
|
11
|
+
| **工件根解析** | `.newbee-specs-path` 存在 → 只认绝对路径,指向不存在/为空 → **报错停下**;无声明 → `<项目根>\newbee-specs\`(或项目既有 specs 目录) |
|
|
12
|
+
| **续跑机制** | 已有夹层 → 编号 = 现有最大 NNN + 1(建夹层前扫描,防并行撞号);孤儿工件按 `scheme:` 行领地认领 |
|
|
13
|
+
| **脚本执行** | 运行 `npx newbee-sdd verify` 或本地脚本进行机器对账 |
|
|
14
|
+
|
|
15
|
+
## Stage 1 — 澄清 + 规格(spec.md 一档闭环)
|
|
16
|
+
|
|
17
|
+
**输入**:用户原始描述(口语即可)、现有代码/schema(可选)。
|
|
18
|
+
|
|
19
|
+
**流程**:
|
|
20
|
+
1. **需求澄清**:区分「已明确」与「有歧义」;歧义逐条向用户提问(一次最多 5 题、按风险高低排序),绝不静默替用户拍板。
|
|
21
|
+
2. **编写规格**:按 `templates/spec.md` 撰写:REQ(GWT 验收条件)→ RULE(来源 REQ)→ DEC(取舍即记录)→ TC(100% 覆盖 REQ 与 RULE)。
|
|
22
|
+
3. **自检规范**:比对 `references/checklists.md` 中的 spec 五项;运行 `npx newbee-sdd verify`。
|
|
23
|
+
4. **Fresh-Context 复审**:在支持 Subagent 的宿主中(如 OpenCode/Claude Code),启动全新子会话进行独立复审;不支持时进行结构化自查。
|
|
24
|
+
|
|
25
|
+
**验证指标**:常见模糊词零命中;TC 100% 覆盖 REQ 与 RULE;每条 NFR 均有定量数值与量测方式;无未决 `[untracked]`。
|
|
26
|
+
|
|
27
|
+
## Stage 2 — 人审冻结
|
|
28
|
+
|
|
29
|
+
- 向用户呈现 spec 摘要(REQ 数量、RULE 数量、TC 数量、复审发现与处置),请求用户批准。
|
|
30
|
+
- 用户批准后 → frontmatter 状态更新为 `status: approved`(需求正式冻结)。此后的任何改动走变更管理铁律。
|
|
31
|
+
|
|
32
|
+
## Stage 3 — 技术方案与架构设计(plan.md,仅 L 轨)
|
|
33
|
+
|
|
34
|
+
**输入**:已冻结的 spec.md(特别是 NFR 与优先级)、现有技术栈/团队/运维约束。
|
|
35
|
+
|
|
36
|
+
**产出**(`templates/plan.md`):
|
|
37
|
+
1. **约束与技术调研**:候选方案与依据(引用官方文档,不凭印象)。
|
|
38
|
+
2. **评分矩阵**:维度 × 权重 × 候选打分 → 结论回链 NFR-### 与 DEC-###。
|
|
39
|
+
3. **架构设计**:C4 架构组件划分图、模块职责清单(MOD-###)、关键流程时序图。
|
|
40
|
+
4. **防御性设计**:每个外部依赖必填失败模式(超时、重试、幂等、熔断/降级、补偿)。
|
|
41
|
+
|
|
42
|
+
**验证指标**:每个技术选择必须回链 NFR-### 或 DEC-###;“我比较熟”不得作为选型理由;关键技术假设附 PoC/spike 安排。
|
|
43
|
+
|
|
44
|
+
## Stage 4 — 任务拆解(tasks.md)
|
|
45
|
+
|
|
46
|
+
**产出**(`templates/tasks.md`):
|
|
47
|
+
- **Part 1 任务清单**:`TASK-### | 标题 | 来源(REQ-/RULE-/DEC-/MOD-)| 类型(code/test/infra/doc/spike)| 依赖 | 验收条件`。任务粒度保持在 0.5~2 天,职责单一、可独立验收。
|
|
48
|
+
- **Part 2 需求追溯矩阵(RTM)**:`REQ → RULE → DEC → TC → TASK → Implementation(待回填) → Release(状态)`;如有外部工单系统挂接 External ID。
|
|
49
|
+
- **Part 3 [untracked] 清单**:无明确来源的任务绝不静默保留,由用户裁决转正补 ID 或直接废弃。
|
|
50
|
+
|
|
51
|
+
**验证指标**:100% Must REQ 映射至少 1 个任务;100% TC 映射至少 1 个测试任务;依赖无环。
|
|
52
|
+
|
|
53
|
+
## Stage 5 — 实施与代码审查
|
|
54
|
+
|
|
55
|
+
- 严格按照 tasks.md 拆解的依赖顺序实施开发。
|
|
56
|
+
- 任务完成后进行代码审查(四维:Bug、性能、安全、可维护性 + 规格符合性),审查通过后方可回填 RTM 中的 Implementation(commit/PR)。
|
|
57
|
+
- 审查者不得建议违反规格的修改;若发现规格缺陷,记录 Minor FIND 指向规格层。
|
|
58
|
+
|
|
59
|
+
## Stage 6 — 收尾对账与发布
|
|
60
|
+
|
|
61
|
+
- **RTM 全链路对账**:杜绝“实现代码已合并但 TC 未执行通过”的情况;Must REQ 完成率达到 100%。
|
|
62
|
+
- **豁免项闭环**:所有豁免均有一行书面理由与决策人。
|
|
63
|
+
- **状态归档**:更新 frontmatter `status: done`;更新 `INDEX.md` 索引表。
|
|
64
|
+
|
|
65
|
+
## FIND 闭环机制(所有阶段审查通用)
|
|
66
|
+
|
|
67
|
+
审查中发现的每条问题(FIND-###)必须二选一闭环,严禁口头承诺:
|
|
68
|
+
1. **转正 ID**:修改规格的转为 DEC 或规格修订;修改代码的转为 TASK。
|
|
69
|
+
2. **显式豁免**:记录一行明确理由 + 决策人。
|
|
70
|
+
|
|
71
|
+
## 变更管理铁律(approved 之后的修改)
|
|
72
|
+
|
|
73
|
+
- REQ/RULE/TC 编号不可变更、不可复用;废弃条目标注 `superseded by REQ-###`,绝不直接物理删行。
|
|
74
|
+
- `approved` 之后修改 spec:必须在文档内变更记录(change-log)中记录一行(日期/原因/影响范围),受影响的任务在 RTM 中标明回归影响。
|
|
75
|
+
- 状态机旁路:`blocked`(阻断,标明原因)、`deprecated`(废弃,保留历史记录)。
|