@namewta/speculo 0.6.0 → 0.7.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.
Files changed (116) hide show
  1. package/README.md +11 -11
  2. package/dist/src/cli.js +36 -128
  3. package/dist/src/cli.js.map +1 -1
  4. package/dist/src/index.d.ts +2 -4
  5. package/dist/src/index.js +173 -151
  6. package/dist/src/index.js.map +1 -1
  7. package/package.json +6 -4
  8. package/template/.speculo/README.md +4 -0
  9. package/template/canonical/canonical-specdev-engineering-cognitive-mentor.md +133 -141
  10. package/template/canonical/canonical-specdev-goal-plan.md +394 -377
  11. package/template/canonical/canonical-specdev-grill-with-docs.md +241 -178
  12. package/template/canonical/canonical-specdev-spec.md +132 -122
  13. package/template/canonical/canonical-specdev-tickets.md +176 -156
  14. package/template/canonical/canonical-specdev-wayfinder.md +106 -108
  15. package/template/commands/archive-and-consolidate.md +10 -8
  16. package/template/commands/handoff.md +2 -0
  17. package/template/commands/retro.md +3 -3
  18. package/template/commands/status.md +5 -4
  19. package/template/skills/archive-and-consolidate/SKILL.md +5 -9
  20. package/template/skills/archive-and-consolidate/assets/archive-plan-template.md +1 -1
  21. package/template/skills/archive-and-consolidate/references/archive-rules.md +4 -4
  22. package/template/skills/archive-and-consolidate/references/consolidation-rules.md +7 -8
  23. package/template/skills/archive-and-consolidate/references/knowledge-graduation.md +5 -2
  24. package/template/skills/github-npm-ops/SKILL.md +4 -2
  25. package/template/skills/github-npm-ops/references/issue-transport.md +26 -0
  26. package/template/skills/github-npm-ops/references/preflight-checklist.md +1 -1
  27. package/template/skills/github-npm-ops/scripts/issue-transport.mjs +227 -0
  28. package/template/workflows/specdev/A-archive-and-consolidate/A-archive-and-consolidate.md +31 -145
  29. package/template/workflows/specdev/A-archive-and-consolidate/consolidation-interview.md +4 -6
  30. package/template/workflows/specdev/C-code-review/C-code-review.md +42 -0
  31. package/template/workflows/specdev/C-code-review/code-review-template.md +42 -0
  32. package/template/workflows/specdev/D-diagnose-bugs/D-diagnose-bugs.md +45 -48
  33. package/template/workflows/specdev/D-diagnose-bugs/diagnosis-template.md +44 -40
  34. package/template/workflows/specdev/D-diagnose-bugs/feedback-loop.md +41 -0
  35. package/template/workflows/specdev/D-diagnose-bugs/hypothesis-and-instrumentation.md +32 -0
  36. package/template/workflows/specdev/D-diagnose-bugs/scripts/hitl-loop.template.sh +26 -0
  37. package/template/workflows/specdev/E-engineering-cognitive-mentor/E-engineering-cognitive-mentor.md +3 -3
  38. package/template/workflows/specdev/E-engineering-cognitive-mentor/persistence-and-resume.md +5 -20
  39. package/template/workflows/specdev/G-grill-with-docs/G-grill-with-docs.md +17 -10
  40. package/template/workflows/specdev/G-grill-with-docs/adr-format.md +31 -17
  41. package/template/workflows/specdev/G-grill-with-docs/context-format.md +9 -29
  42. package/template/workflows/specdev/G-grill-with-docs/domain-modeling-rules.md +10 -5
  43. package/template/workflows/specdev/G-grill-with-docs/stakeholder-questionnaire.md +45 -0
  44. package/template/workflows/specdev/I-implement/I-implement.md +29 -14
  45. package/template/workflows/specdev/I-implement/delegated-evidence-template.md +11 -0
  46. package/template/workflows/specdev/I-implement/evidence-template.md +24 -10
  47. package/template/workflows/specdev/I-implement/execution-preflight.md +4 -4
  48. package/template/workflows/specdev/I-implement/merge-conflict-protocol.md +20 -0
  49. package/template/workflows/specdev/I-implement/tdd-mocking.md +19 -0
  50. package/template/workflows/specdev/I-implement/tdd-rules.md +14 -12
  51. package/template/workflows/specdev/I-implement/tdd-test-design.md +25 -0
  52. package/template/workflows/specdev/I-init-setup/I-init-setup.md +12 -9
  53. package/template/workflows/specdev/I-init-setup/config-template.json +1 -1
  54. package/template/workflows/specdev/I-init-setup/domain-layout-template.md +2 -2
  55. package/template/workflows/specdev/I-init-setup/status-template.json +2 -3
  56. package/template/workflows/specdev/I-init-setup/tracking-template.md +3 -0
  57. package/template/workflows/specdev/INDEX.md +64 -26
  58. package/template/workflows/specdev/P-goal-plan/P-goal-plan.md +48 -38
  59. package/template/workflows/specdev/P-goal-plan/completion-control.md +19 -53
  60. package/template/workflows/specdev/P-goal-plan/delegated-execution-template.md +33 -0
  61. package/template/workflows/specdev/P-goal-plan/delegated-execution.md +53 -0
  62. package/template/workflows/specdev/P-goal-plan/goal-plan-template.md +9 -40
  63. package/template/workflows/specdev/P-goal-plan/orchestration-protocol.md +16 -68
  64. package/template/workflows/specdev/P-goal-plan/planning-modes.md +20 -48
  65. package/template/workflows/specdev/P-prototype/P-prototype.md +46 -0
  66. package/template/workflows/specdev/P-prototype/logic-prototype.md +24 -0
  67. package/template/workflows/specdev/P-prototype/prototype-record-template.md +46 -0
  68. package/template/workflows/specdev/P-prototype/ui-prototype.md +21 -0
  69. package/template/workflows/specdev/R-review-architecture/R-review-architecture.md +1 -1
  70. package/template/workflows/specdev/S-spec/S-spec.md +2 -1
  71. package/template/workflows/specdev/T-tickets/T-tickets.md +3 -2
  72. package/template/workflows/specdev/T-tickets/ticket-readiness.md +1 -1
  73. package/template/workflows/specdev/T-tickets/ticket-template.md +1 -1
  74. package/template/workflows/specdev/T-tickets/tickets-map-template.md +1 -1
  75. package/template/workflows/specdev/T-triage/T-triage.md +65 -26
  76. package/template/workflows/specdev/T-triage/intake-protocol.md +32 -0
  77. package/template/workflows/specdev/T-triage/reconcile-protocol.md +34 -0
  78. package/template/workflows/specdev/T-triage/source-template.md +30 -0
  79. package/template/workflows/specdev/T-triage/triage-template.md +38 -24
  80. package/template/workflows/specdev/W-wayfinder/W-wayfinder.md +3 -1
  81. package/template/workflows/specdev/_state/status.json +2 -3
  82. package/template/workflows/specdev/common/README.md +9 -2
  83. package/template/workflows/specdev/common/rules/artifact-contract.md +20 -9
  84. package/template/workflows/specdev/common/rules/change-completion.md +33 -0
  85. package/template/workflows/specdev/common/rules/deviation-control.md +2 -2
  86. package/template/workflows/specdev/common/rules/evidence-and-verification.md +1 -1
  87. package/template/workflows/specdev/common/rules/path-ownership.md +3 -3
  88. package/template/workflows/specdev/common/schemas/change-status.schema.json +43 -0
  89. package/template/workflows/specdev/common/schemas/code-review.schema.json +22 -0
  90. package/template/workflows/specdev/common/schemas/diagnosis.schema.json +19 -0
  91. package/template/workflows/specdev/common/schemas/prototype-record.schema.json +24 -0
  92. package/template/workflows/specdev/common/schemas/source.schema.json +20 -0
  93. package/template/workflows/specdev/common/schemas/status.schema.json +20 -78
  94. package/template/workflows/specdev/common/schemas/triage.schema.json +21 -0
  95. package/template/workflows/specdev/common/skills/code-review/SKILL.md +49 -0
  96. package/template/workflows/specdev/common/skills/code-review/references/fowler-smells.md +18 -0
  97. package/template/workflows/specdev/common/skills/code-review/references/reviewer-contracts.md +13 -0
  98. package/template/workflows/specdev/common/skills/code-review/references/source-discovery.md +22 -0
  99. package/template/workflows/specdev/common/skills/dev-worktree/SKILL.md +12 -9
  100. package/template/workflows/specdev/common/skills/dev-worktree/references/create.md +18 -13
  101. package/template/workflows/specdev/common/skills/dev-worktree/references/finalize.md +8 -6
  102. package/template/workflows/specdev/common/skills/research/SKILL.md +38 -26
  103. package/template/workflows/specdev/common/skills/subagent-delivery/SKILL.md +3 -5
  104. package/template/workflows/specdev/common/tools/README.md +3 -0
  105. package/template/workflows/specdev/common/tools/validate-specdev.mjs +496 -30
  106. package/dist/src/migrate.d.ts +0 -38
  107. package/dist/src/migrate.js +0 -642
  108. package/dist/src/migrate.js.map +0 -1
  109. package/dist/src/skills-mirror.d.ts +0 -38
  110. package/dist/src/skills-mirror.js +0 -160
  111. package/dist/src/skills-mirror.js.map +0 -1
  112. package/template/workflows/specdev/A-archive-and-consolidate/archive-checklist.md +0 -15
  113. package/template/workflows/specdev/A-archive-and-consolidate/knowledge-promotion-rules.md +0 -32
  114. package/template/workflows/specdev/I-implement/code-review-process.md +0 -17
  115. package/template/workflows/specdev/I-implement/tdd-examples.md +0 -14
  116. package/template/workflows/specdev/I-init-setup/status-labels-template.md +0 -55
@@ -0,0 +1,227 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execFile } from "node:child_process";
4
+ import { readFile } from "node:fs/promises";
5
+ import { promisify } from "node:util";
6
+
7
+ const execFileAsync = promisify(execFile);
8
+
9
+ function parseArgs(argv) {
10
+ const [operation, ...rest] = argv;
11
+ const options = { labels: [] };
12
+ for (let index = 0; index < rest.length; index += 1) {
13
+ const token = rest[index];
14
+ if (token === "--apply") {
15
+ options.apply = true;
16
+ continue;
17
+ }
18
+ if (!token.startsWith("--")) throw new Error(`unexpected argument: ${token}`);
19
+ const key = token.slice(2).replaceAll("-", "_");
20
+ const value = rest[index + 1];
21
+ if (value === undefined || value.startsWith("--")) {
22
+ throw new Error(`${token} requires a value`);
23
+ }
24
+ index += 1;
25
+ if (key === "label") options.labels.push(value);
26
+ else options[key] = value;
27
+ }
28
+ return { operation, options };
29
+ }
30
+
31
+ function requireOptions(options, keys) {
32
+ const missing = keys.filter((key) => !String(options[key] ?? "").trim());
33
+ if (missing.length) throw new Error(`missing options: ${missing.map((key) => `--${key.replaceAll("_", "-")}`).join(", ")}`);
34
+ }
35
+
36
+ async function gh(args) {
37
+ try {
38
+ const { stdout } = await execFileAsync("gh", args, {
39
+ maxBuffer: 16 * 1024 * 1024,
40
+ encoding: "utf8",
41
+ });
42
+ return stdout.trim();
43
+ } catch (error) {
44
+ const detail = String(error?.stderr || error?.message || error).trim();
45
+ throw new Error(`gh ${args[0]} failed: ${detail}`);
46
+ }
47
+ }
48
+
49
+ async function readIssue(repo, number) {
50
+ return JSON.parse(
51
+ await gh([
52
+ "issue",
53
+ "view",
54
+ number,
55
+ "--repo",
56
+ repo,
57
+ "--json",
58
+ "number,title,body,state,url,author,labels,createdAt,updatedAt,comments",
59
+ ]),
60
+ );
61
+ }
62
+
63
+ async function issueRead(options) {
64
+ requireOptions(options, ["repo", "number"]);
65
+ const issue = await readIssue(options.repo, options.number);
66
+ return {
67
+ operation: "issue-read",
68
+ provider: "github",
69
+ repo: options.repo,
70
+ kind: "issue",
71
+ ...issue,
72
+ };
73
+ }
74
+
75
+ async function prRead(options) {
76
+ requireOptions(options, ["repo", "number"]);
77
+ const pull = JSON.parse(
78
+ await gh([
79
+ "pr",
80
+ "view",
81
+ options.number,
82
+ "--repo",
83
+ options.repo,
84
+ "--json",
85
+ "number,title,body,state,url,author,labels,createdAt,updatedAt,comments,baseRefName,baseRefOid,headRefName,headRefOid,files",
86
+ ]),
87
+ );
88
+ return {
89
+ operation: "pr-read",
90
+ provider: "github",
91
+ repo: options.repo,
92
+ kind: "pull-request",
93
+ ...pull,
94
+ };
95
+ }
96
+
97
+ async function issueSearch(options) {
98
+ requireOptions(options, ["repo", "query"]);
99
+ const issues = JSON.parse(
100
+ await gh([
101
+ "issue",
102
+ "list",
103
+ "--repo",
104
+ options.repo,
105
+ "--search",
106
+ options.query,
107
+ "--state",
108
+ options.state || "all",
109
+ "--limit",
110
+ options.limit || "20",
111
+ "--json",
112
+ "number,title,state,url,labels,updatedAt",
113
+ ]),
114
+ );
115
+ return { operation: "issue-search", provider: "github", repo: options.repo, issues };
116
+ }
117
+
118
+ async function issueCreate(options) {
119
+ requireOptions(options, ["repo", "title", "body_file"]);
120
+ const plan = {
121
+ operation: "issue-create",
122
+ provider: "github",
123
+ repo: options.repo,
124
+ title: options.title,
125
+ body_file: options.body_file,
126
+ labels: options.labels,
127
+ mode: options.apply ? "apply" : "dry-run",
128
+ };
129
+ if (!options.apply) return plan;
130
+
131
+ await readFile(options.body_file, "utf8");
132
+ const args = [
133
+ "issue",
134
+ "create",
135
+ "--repo",
136
+ options.repo,
137
+ "--title",
138
+ options.title,
139
+ "--body-file",
140
+ options.body_file,
141
+ ];
142
+ for (const label of options.labels) args.push("--label", label);
143
+ return { ...plan, url: await gh(args), status: "created" };
144
+ }
145
+
146
+ async function issueCommentClose(options) {
147
+ requireOptions(options, ["repo", "number", "comment_file", "marker"]);
148
+ const marker = `<!-- ${options.marker} -->`;
149
+ const comment = (await readFile(options.comment_file, "utf8")).trim();
150
+ const before = await readIssue(options.repo, options.number);
151
+ const markerExists = (before.comments ?? []).some((item) =>
152
+ String(item?.body ?? "").includes(marker),
153
+ );
154
+ const plan = {
155
+ operation: "issue-comment-close",
156
+ provider: "github",
157
+ repo: options.repo,
158
+ number: Number(options.number),
159
+ url: before.url,
160
+ mode: options.apply ? "apply" : "dry-run",
161
+ state_before: before.state,
162
+ comment_required: !markerExists,
163
+ close_required: String(before.state).toUpperCase() !== "CLOSED",
164
+ marker: options.marker,
165
+ steps: [],
166
+ };
167
+ if (!options.apply) return plan;
168
+
169
+ if (!markerExists) {
170
+ await gh([
171
+ "issue",
172
+ "comment",
173
+ options.number,
174
+ "--repo",
175
+ options.repo,
176
+ "--body",
177
+ `${comment}\n\n${marker}`,
178
+ ]);
179
+ plan.steps.push("commented");
180
+ } else {
181
+ plan.steps.push("comment-already-present");
182
+ }
183
+ if (String(before.state).toUpperCase() !== "CLOSED") {
184
+ await gh([
185
+ "issue",
186
+ "close",
187
+ options.number,
188
+ "--repo",
189
+ options.repo,
190
+ "--reason",
191
+ options.reason || "completed",
192
+ ]);
193
+ plan.steps.push("closed");
194
+ } else {
195
+ plan.steps.push("already-closed");
196
+ }
197
+
198
+ const after = await readIssue(options.repo, options.number);
199
+ if (String(after.state).toUpperCase() !== "CLOSED") {
200
+ throw new Error(`issue remained ${after.state} after close operation`);
201
+ }
202
+ return { ...plan, state_after: after.state, status: "closed" };
203
+ }
204
+
205
+ function usage() {
206
+ return `Usage:
207
+ issue-transport.mjs issue-read --repo OWNER/REPO --number N
208
+ issue-transport.mjs pr-read --repo OWNER/REPO --number N
209
+ issue-transport.mjs issue-search --repo OWNER/REPO --query TEXT [--state all] [--limit 20]
210
+ issue-transport.mjs issue-create --repo OWNER/REPO --title TEXT --body-file PATH [--label LABEL] [--apply]
211
+ issue-transport.mjs issue-comment-close --repo OWNER/REPO --number N --comment-file PATH --marker ID [--reason completed] [--apply]`;
212
+ }
213
+
214
+ try {
215
+ const { operation, options } = parseArgs(process.argv.slice(2));
216
+ if (!operation || ["help", "--help", "-h"].includes(operation)) {
217
+ console.log(usage());
218
+ } else {
219
+ const handlers = { issueRead, prRead, issueSearch, issueCreate, issueCommentClose };
220
+ const handler = handlers[operation.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase())];
221
+ if (!handler) throw new Error(`unknown operation: ${operation}\n${usage()}`);
222
+ console.log(JSON.stringify(await handler(options), null, 2));
223
+ }
224
+ } catch (error) {
225
+ console.error(`ERROR: ${error.message}`);
226
+ process.exitCode = 1;
227
+ }
@@ -3,168 +3,54 @@ id: specdev/archive-and-consolidate
3
3
  type: workflow-entry
4
4
  workflow: specdev
5
5
  name: 归档与沉淀
6
- description: 双模式沉淀 Work——归档已验证完成的 change 并提升其知识,或在没有可归档 change 时以当前代码为基本事实深度访谈用户,把经验证的架构决策与领域术语提升为永久知识。
6
+ description: 校验本地完成与远程 reconcile 门,复用全局归档能力移动 completed change 并提升当前知识,或从代码访谈形成可归档知识 change
7
7
  keywords: [归档, consolidation, ADR, context, research, knowledge, 代码库访谈]
8
8
  ---
9
9
 
10
10
  # 归档与沉淀
11
11
 
12
- Work 的唯一目的:让**永久知识**只保存“当前仍真实、超出单个 change 仍有用、已有实现证据”的结论,同时保留历史与 supersedes 关系。
12
+ A SpecDev 的归档 wrapper:它拥有模式选择、SpecDev 完成门和代码访谈;机械扫描、dry-run、知识毕业、合并、清理、移动与重读由 `<Path>{roots.skills}/archive-and-consolidate/SKILL.md</Path>` 单一维护。
13
13
 
14
- 它有两个入口模式,最终收束到同一条“评估 → 提升 → 归档”尾部:
14
+ ## 模式
15
15
 
16
- - **archive 模式**:存在已验证完成、用户授权归档的 change 时,归档该 change 并提升其内部产物中的知识。
17
- - **consolidate-from-code 模式**:没有可归档 change,或用户明确要求“基于当前代码沉淀知识”时,以当前代码库为基本事实,一次一问深度访谈用户,把结论沉淀为永久领域上下文与架构决策。**这次访谈运行本身也是一个 change**:所有访谈轨迹、LOG、CONTEXT、ADR 先落在该 change 内,经代码验证后再提升到永久 store,最后归档该 change。
16
+ - **archive**:处理用户指定或唯一的 completed change
17
+ - **consolidate-from-code**:用户明确要求从当前代码沉淀知识,或没有可归档 change;本次访谈本身创建一个 change,形成、验证、完成后再归档。
18
18
 
19
- 归档不是把整个 change 无差别复制到永久知识库;访谈也不是把用户随口结论直接写成永久 ADR。两条路径都必须先有代码或实现证据,再提升。
19
+ 多个候选或模式冲突时请求消歧,不猜测。
20
20
 
21
- ## 输入
21
+ ## Archive 模式
22
22
 
23
- ### 共同输入
23
+ 1. 读取全局/change 状态、Ticket、Map、Goal Plan、Evidence、ADR、CONTEXT、LOG、triage 和项目验证事实。
24
+ 2. 加载 `<Path>{roots.workflows}/specdev/common/rules/change-completion.md</Path>`,确认 `change_status: completed`、完成 owner 已写入时间和证据、无 blocker/deviation。
25
+ 3. 检查 `<Path>{roots.state}/specdev/changes/{change}/triage.md</Path>` 的 `external_action`:`pending-close` 或 `close-failed` 返回 `<Path>{roots.workflows}/specdev/T-triage/T-triage.md</Path>`;只有 `closed | waived | not-applicable` 继续。
26
+ 4. 调用 `<Path>{roots.skills}/archive-and-consolidate/SKILL.md</Path>` 的 `archive-single + dry-run`,传入已解析 workflow/state/changes/archive/knowledge roots。展示完整移动、提升和清理计划。
27
+ 5. 只有用户明确批准该计划后调用 `confirmed`。移动、知识写入和清理均使用计划内路径;计划后出现 drift 时停止。
28
+ 6. 重读源、归档目标、全局索引、归档 `<Path>{roots.state}/specdev/archive/YYYY-MM/{change}/.status.json</Path>` 和永久知识;运行 `--stage complete` 及包级校验,报告每个提升/跳过结论。
24
29
 
25
- - 全局状态:`<Path>{roots.state}/specdev/status.json</Path>`
26
- - 全局配置:`<Path>{roots.state}/specdev/config.json</Path>`
27
- - 永久架构决策:`<Path>{roots.state}/specdev/adr/</Path>`
28
- - 永久领域上下文:`<Path>{roots.state}/specdev/context/</Path>`
29
- - 永久研究:`<Path>{roots.state}/specdev/research/</Path>`
30
- - 工件职责规则:`<Path>{roots.workflows}/specdev/common/rules/artifact-contract.md</Path>`
30
+ ## Consolidate-from-code 模式
31
31
 
32
- ### archive 模式输入
32
+ 1. 创建 `<Path>{roots.state}/specdev/changes/{change}/</Path>`、change 状态、LOG、CONTEXT 和 ADR,并登记 `current_work`。
33
+ 2. 加载 `<Path>{roots.workflows}/specdev/A-archive-and-consolidate/consolidation-interview.md</Path>`,每轮先探索代码/配置/测试并陈述证据,再一次只问一个真正影响长期理解的问题。
34
+ 3. 按 LOG → CONTEXT → ADR 顺序写入:CONTEXT 只保存项目规范术语;ADR 只有同时满足难逆转、令人意外和真实权衡时才创建。
35
+ 4. 用户结论必须由当前代码或实际行为验证;未验证内容留在 LOG,不提升。
36
+ 5. 按 change completion 规则由本 Work 关闭该非实现型 change,再进入 Archive 模式的 dry-run/确认流程。
33
37
 
34
- - change 根:`<Path>{roots.state}/specdev/changes/{change}/</Path>`
35
- - change 状态:`<Path>{roots.state}/specdev/changes/{change}/.status.json</Path>`
36
- - 该 change 内的实现产物(存在即读,不存在静默跳过):
37
- - `<Path>{roots.state}/specdev/changes/{change}/ADR.md</Path>`
38
- - `<Path>{roots.state}/specdev/changes/{change}/CONTEXT.md</Path>`
39
- - `<Path>{roots.state}/specdev/changes/{change}/LOG.md</Path>`
40
- - `<Path>{roots.state}/specdev/changes/{change}/spec.md</Path>`
41
- - `<Path>{roots.state}/specdev/changes/{change}/tickets-map.md</Path>`
42
- - `<Path>{roots.state}/specdev/changes/{change}/goal-plan.md</Path>`
43
- - `<Path>{roots.state}/specdev/changes/{change}/evidence/</Path>`
38
+ ## 副作用
44
39
 
45
- ### consolidate-from-code 模式输入
46
-
47
- - 项目代码、配置、接口、schema、测试与经验证文档——这是本模式的**基本事实源**。
48
- - 可选参考:与访谈主题相关的历史 change(`<Path>{roots.state}/specdev/changes/</Path>` 或 `<Path>{roots.state}/specdev/archive/</Path>`)。存在则读取以避免重复结论;不存在时直接以代码为事实访谈,不把“无相关 change”当作缺陷。
49
-
50
- 不存在的可选输入静默跳过,不把缺失文件伪装成已确认事实。
51
-
52
- ## 流程
53
-
54
- ### 0. 判定模式
55
-
56
- 读取 `<Path>{roots.state}/specdev/status.json</Path>` 并判定:
57
-
58
- - 用户或调用方**显式指定模式**时以其为准。
59
- - 存在唯一 `change_status: completed` 且已获授权归档的 change → **archive 模式**,`{change}` 即该 change。
60
- - 没有可归档 change → **consolidate-from-code 模式**。
61
- - 同时存在多个可归档候选,或既有可归档 change 又收到“基于代码沉淀”请求 → 停止并请用户消歧,不猜测。
62
-
63
- 判定结果记入本次运行的状态摘要。archive 模式进入 §1a;consolidate-from-code 模式进入 §1b。
64
-
65
- ---
66
-
67
- ### 1a. archive 模式 · 完成检查
68
-
69
- 加载 `<Path>{roots.workflows}/specdev/A-archive-and-consolidate/archive-checklist.md</Path>`,检查 Ticket、Evidence、Spec 合同、Goal Gate、偏差、迁移、状态和用户授权。
70
-
71
- 未完成、验证失败、存在未批准 deviation 或用户未授权时停止,不得标 completed 或 archived。
72
-
73
- ### 2a. archive 模式 · 冻结归档快照
74
-
75
- 记录:
76
-
77
- - 归档时间;
78
- - 最终基线、提交或 PR;
79
- - 全局验证摘要;
80
- - 已知残余风险;
81
- - 被批准的 cancelled/deferred 条目;
82
- - 归档目标 `<Path>{roots.state}/specdev/archive/YYYY-MM/{change}/</Path>`。
83
-
84
- 归档前不得删除设计日志、Evidence 或被替代 ADR。完成后进入 §3(共同的知识评估)。
85
-
86
- ---
87
-
88
- ### 1b. consolidate-from-code 模式 · 建立访谈 change
89
-
90
- 创建承载本次沉淀运行的 change:`<Path>{roots.state}/specdev/changes/{change}/</Path>`,`{change}` 使用 `<YYYY-MM-DD>-<topic>`(topic 为访谈主题,如 `consolidate-auth-domain`)。
91
-
92
- 首次创建:
93
-
94
- - 生命周期状态:`<Path>{roots.state}/specdev/changes/{change}/.status.json</Path>`,使用 `<Path>{roots.workflows}/specdev/I-init-setup/change-status-template.json</Path>`;
95
- - 设计日志:`<Path>{roots.state}/specdev/changes/{change}/LOG.md</Path>`;
96
- - 领域上下文:`<Path>{roots.state}/specdev/changes/{change}/CONTEXT.md</Path>`;
97
- - 架构决策:`<Path>{roots.state}/specdev/changes/{change}/ADR.md</Path>`。
98
-
99
- 在 `<Path>{roots.state}/specdev/status.json</Path>` 的 `active` 中登记该 change,`current_work` 设为 `specdev/archive-and-consolidate`,并在 `work_history` 追加一条未完成记录。恢复已有访谈 change 时先读取三份文档与最后一条 LOG,不重复询问已确认结论。
100
-
101
- ### 2b. consolidate-from-code 模式 · 代码为事实的深度访谈
102
-
103
- 加载 `<Path>{roots.workflows}/specdev/A-archive-and-consolidate/consolidation-interview.md</Path>`,以当前代码库为基本事实一次一问访谈。每轮:先只读探索相关代码/配置/测试并陈述证据 → 提出唯一关键问题 → 给出选项、权衡与推荐 → 等待用户 confirmed/deferred/rejected → 立即把结果追加到 `<Path>{roots.state}/specdev/changes/{change}/LOG.md</Path>`。
104
-
105
- 按固定顺序同步 change 内文档:先写 LOG,再把当前仍真实的术语/不变量/代码映射写入 `<Path>{roots.state}/specdev/changes/{change}/CONTEXT.md</Path>`,最后把满足条件的长期架构决策写入 `<Path>{roots.state}/specdev/changes/{change}/ADR.md</Path>`。历史轨迹不进 CONTEXT,未确认选项不写成已接受 ADR。
106
-
107
- 访谈收束后进入 §3(共同的知识评估)。此时该 change 视为“已完成访谈、可提升与归档”。
108
-
109
- ---
110
-
111
- ### 3. 评估长期知识(共同)
112
-
113
- 加载 `<Path>{roots.workflows}/specdev/A-archive-and-consolidate/knowledge-promotion-rules.md</Path>`,逐条评估 change 内(archive 模式来自实现产物,consolidate-from-code 模式来自访谈结论)的架构决策、领域术语和研究结论。
114
-
115
- 每条结论执行:`create | update | merge | supersede | deprecate | skip`。无法判断当前真相时不提升,创建治理问题或新 change。consolidate-from-code 模式下,未获代码或实际行为验证的结论一律 `skip`,只留在 change 内。
116
-
117
- ### 4. 提升与冲突处理(共同)
118
-
119
- - 架构决策提升到 `<Path>{roots.state}/specdev/adr/</Path>`;
120
- - 领域术语提升到 `<Path>{roots.state}/specdev/context/</Path>`;
121
- - 经实现验证、长期有效的研究提升到 `<Path>{roots.state}/specdev/research/</Path>`;
122
- - 冲突 ADR 建立 supersedes 双向引用,不静默覆盖;
123
- - 历史结论保留状态和来源,不通过删除历史制造一致性。
124
-
125
- ### 5. 移动归档并更新状态(共同)
126
-
127
- 将 `<Path>{roots.state}/specdev/changes/{change}/</Path>` 移动到 `<Path>{roots.state}/specdev/archive/YYYY-MM/{change}/</Path>`。
128
-
129
- 更新 `<Path>{roots.state}/specdev/status.json</Path>`:从 active 移除,追加 completed/archived 记录,并把当前 `work_history` 记录标记完成;归档内 `<Path>{roots.state}/specdev/archive/YYYY-MM/{change}/.status.json</Path>` 写入完成时间、归档路径和 promotion 摘要。
130
-
131
- 任何删除、移动或 Git 副作用均需用户授权。
132
-
133
- ### 6. 校验与汇报(共同)
134
-
135
- 运行包级和归档链接检查,确认:
136
-
137
- - 归档路径存在;
138
- - 全局状态与归档状态一致;
139
- - 永久知识引用有效;
140
- - supersedes 链无断裂;
141
- - 无敏感信息进入永久知识。
142
-
143
- 输出 promotion report:本次模式、每条候选知识、执行动作、目标路径、证据和未提升原因。
144
-
145
- ## 禁止
146
-
147
- - 未完成或验证失败的 change 标 completed;
148
- - 把临时实现细节、一次性命令或未经验证假设提升为永久知识;
149
- - consolidate-from-code 模式下把用户未经代码验证的结论直接写成永久 ADR/context;
150
- - 静默覆盖冲突 ADR;
151
- - 删除历史以制造一致性;
152
- - 在归档或永久知识中写入秘密、令牌、敏感日志或个人隐私;
153
- - 未经用户授权移动、删除、提交或推送。
40
+ Dry-run 不修改文件。归档移动、知识 merge/rewrite/delete、Git 动作均在计划展示后单独确认。归档目录完成后只读;后续纠正通过新 change 和 supersedes 链完成。
154
41
 
155
42
  ## 完成标准
156
43
 
157
- - 模式已明确判定;
158
- - archive 模式:`<Path>{roots.workflows}/specdev/A-archive-and-consolidate/archive-checklist.md</Path>` 全部适用项通过;
159
- - consolidate-from-code 模式:访谈决策树关键分支已覆盖,LOG/CONTEXT/ADR 与代码事实一致;
160
- - change 已移动到 `<Path>{roots.state}/specdev/archive/YYYY-MM/{change}/</Path>`;
161
- - 全局和归档状态一致;
162
- - 长期知识已按证据处理,未验证结论未被提升;
163
- - promotion report 已向用户汇报;
164
- - 无未批准副作用。
44
+ - 模式与唯一 change 已确定;
45
+ - 本地完成和 external reconcile 门通过;
46
+ - 机械归档与知识规则只有全局 skill 一个事实源;
47
+ - dry-run confirmed 执行严格分离;
48
+ - 源不存在、目标完整、active/archived 无重叠、归档状态正确;
49
+ - 永久知识只包含当前、跨 change 有用且有实现证据的结论;
50
+ - 无未批准移动、删除、改写或 Git 副作用。
165
51
 
166
52
  ## 子文件引用
167
53
 
168
- - 归档检查:`<Path>{roots.workflows}/specdev/A-archive-and-consolidate/archive-checklist.md</Path>`
169
- - 知识提升规则:`<Path>{roots.workflows}/specdev/A-archive-and-consolidate/knowledge-promotion-rules.md</Path>`
170
- - 代码库沉淀访谈协议:`<Path>{roots.workflows}/specdev/A-archive-and-consolidate/consolidation-interview.md</Path>`
54
+ - 全局归档 Skill:`<Path>{roots.skills}/archive-and-consolidate/SKILL.md</Path>`
55
+ - Change 完成:`<Path>{roots.workflows}/specdev/common/rules/change-completion.md</Path>`
56
+ - 代码访谈:`<Path>{roots.workflows}/specdev/A-archive-and-consolidate/consolidation-interview.md</Path>`
@@ -17,11 +17,9 @@
17
17
 
18
18
  1. 领域边界与限界上下文:系统由哪些领域构成,各自职责与边界;
19
19
  2. 规范术语与语义:代码中的类型/模块名对应什么业务概念,别名与禁用词;
20
- 3. 核心不变量与约束:始终成立、可被验证、跨 change 有效的规则;
21
- 4. 概念关系:聚合、生命周期、依赖、拥有关系与状态转换;
22
- 5. 已固化的架构决策:现有代码体现了哪些长期决策、其驱动因素与替代方案;
23
- 6. 实现映射与差距:领域概念到模块/接口/存储/事件的映射,以及已知偏离;
24
- 7. 历史缘由:为什么当前这样,哪些是有意决策、哪些是历史负担。
20
+ 3. Context Map:多个 bounded context 之间需要明确的关系;
21
+ 4. 已固化的架构决策:现有代码体现了哪些难逆转、令人意外且来自真实权衡的决定;
22
+ 5. 历史缘由:为什么当前这样,哪些是有意决策、哪些只是可从代码即时发现的实现事实。
25
23
 
26
24
  ## 3. 每轮只关闭一个关键结论
27
25
 
@@ -48,7 +46,7 @@ change 内三份文档复用 grill 的既有格式,避免重复发明:
48
46
 
49
47
  ## 5. 停止条件
50
48
 
51
- - 目标主题的领域术语、不变量、关系与架构决策已覆盖,足以提升为永久知识;或
49
+ - 目标主题的规范术语、Context Map 与符合准入条件的架构决策已覆盖,足以提升为永久知识;或
52
50
  - 用户明确延后,且该延后不伪装成已确认真相;或
53
51
  - 缺少必要外部信息或权限,change 标 blocked;或
54
52
  - 继续提问只会产生低影响或纯实现细节,交给对应实现阶段决定。
@@ -0,0 +1,42 @@
1
+ ---
2
+ id: specdev/code-review
3
+ type: workflow-entry
4
+ workflow: specdev
5
+ name: 代码审查
6
+ description: 将 commit、branch、tag、merge-base 或 PR 解析为本地不可变固定点,执行隔离的标准轴与规范轴审查并持久化可恢复报告。
7
+ keywords: [code-review, review, diff, fixed-point, PR, 标准, 规范]
8
+ ---
9
+
10
+ # 代码审查
11
+
12
+ C 是独立 review 入口,不实施修复。它拥有 `<Path>{roots.state}/specdev/changes/{change}/reviews/</Path>`;I 的最终审查由 I 写入 Evidence,不写本目录。
13
+
14
+ ## 输入
15
+
16
+ - 用户提供的 commit、branch、tag、merge-base 或 PR locator;缺失时只询问固定点。
17
+ - 可选 source、Spec、Ticket、ADR 和 Goal Plan。
18
+ - 当前仓库代码、commit log 和编码标准。
19
+
20
+ ## 流程
21
+
22
+ 1. **解析固定点**:使用 `git rev-parse` 把固定点和 HEAD 固定为 SHA;PR 先通过 `<Path>{roots.skills}/github-npm-ops/SKILL.md</Path>` 的 `pr-read` 获得 base/head SHA,并确保对应对象可在本地解析。
23
+ 2. **冻结输入**:记录 `git diff <fixed>...<head>` 和 `git log <fixed>..<head> --oneline`。引用无效或 diff 为空时失败,不创建报告。
24
+ 3. **发现来源**:调用 `<Path>{roots.workflows}/specdev/common/skills/code-review/SKILL.md</Path>`;规范来源缺失时经确认跳过规范轴,标准轴继续。
25
+ 4. **隔离审查**:平台支持时并行 reviewer,否则用两个独立完整输入包顺序执行。两轴不得读取对方 finding。
26
+ 5. **持久化**:选择下一个未占用 `CR-###`,使用模板写入 `<Path>{roots.state}/specdev/changes/{change}/reviews/CR-###.md</Path>`,原子重读。
27
+ 6. **验证与路由**:使用 `<Path>{roots.workflows}/specdev/common/tools/validate-specdev.mjs</Path>` 的 `--stage review` 校验当前 change。无阻塞 finding 时返回完成或 I;局部修复生成/修订 Ticket;规范冲突返回 S/G;无法确定的 blocker 保持 C 可恢复状态。
28
+
29
+ ## 完成标准
30
+
31
+ - fixed point/head 是本地不可变 SHA,三点 diff 非空;
32
+ - 规范和标准来源发现顺序有记录;
33
+ - 两轴隔离、固定顺序、未合并排名;
34
+ - 每个 finding 有路径、风险、依据和满足条件;
35
+ - 报告、状态、验证结果和下一 Work 路径一致;
36
+ - C 未修改项目代码或远程状态。
37
+
38
+ ## 子文件引用
39
+
40
+ - 公共审查 Skill:`<Path>{roots.workflows}/specdev/common/skills/code-review/SKILL.md</Path>`
41
+ - 报告模板:`<Path>{roots.workflows}/specdev/C-code-review/code-review-template.md</Path>`
42
+ - 报告 Schema:`<Path>{roots.workflows}/specdev/common/schemas/code-review.schema.json</Path>`
@@ -0,0 +1,42 @@
1
+ ---
2
+ schema_version: 1
3
+ artifact: code-review
4
+ change: <YYYY-MM-DD-topic>
5
+ review_id: CR-001
6
+ fixed_point: <sha>
7
+ head: <sha>
8
+ status: request-changes
9
+ standards_result: request-changes
10
+ specification_result: skipped
11
+ spec_sources: []
12
+ standards_sources: []
13
+ created_at: <ISO-8601>
14
+ ---
15
+
16
+ # Code Review CR-001
17
+
18
+ ## Fixed Input
19
+
20
+ - **Diff:** `git diff <fixed_point>...<head>`
21
+ - **Commits:** `git log <fixed_point>..<head> --oneline`
22
+ - **Scope:**
23
+
24
+ ## 标准
25
+
26
+ | Severity | Path / block | Finding | Authority | Satisfied when |
27
+ |---|---|---|---|---|
28
+
29
+ ## 规范
30
+
31
+ | Severity | Requirement | Finding | Source | Satisfied when |
32
+ |---|---|---|---|---|
33
+
34
+ 规范不存在时写 `skipped:no-spec`,不伪造通过。
35
+
36
+ ## Summary
37
+
38
+ - **Standards findings:**
39
+ - **Specification findings:**
40
+ - **Most severe standards finding:** none / ...
41
+ - **Most severe specification finding:** none / ...
42
+ - **Next Work:** completed / `<Path>{roots.workflows}/specdev/T-tickets/T-tickets.md</Path>` / `<Path>{roots.workflows}/specdev/S-spec/S-spec.md</Path>`