@flyin-ai/alloy 0.2.0-beta.1 → 0.2.0-beta.2

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 (41) hide show
  1. package/commands/alloy/apply.md +222 -430
  2. package/commands/alloy/archive.md +156 -132
  3. package/commands/alloy/discard.md +26 -11
  4. package/commands/alloy/finish.md +212 -116
  5. package/commands/alloy/fix.md +102 -247
  6. package/commands/alloy/plan.md +204 -301
  7. package/commands/alloy/references/apply-precheck.md +21 -0
  8. package/commands/alloy/references/apply-rationalizations.md +18 -0
  9. package/commands/alloy/references/apply-subagent-commit.md +49 -0
  10. package/commands/alloy/references/apply-worktree.md +130 -0
  11. package/commands/alloy/references/archive-rationalizations.md +16 -0
  12. package/commands/alloy/references/archive-worktree-cleanup.md +94 -0
  13. package/commands/alloy/references/artifact-hash-commit.md +49 -0
  14. package/commands/alloy/references/branch-naming.md +65 -0
  15. package/commands/alloy/references/branch-validation.md +36 -0
  16. package/commands/alloy/references/fix-precommit-check.md +58 -0
  17. package/commands/alloy/references/interaction-style.md +34 -1
  18. package/commands/alloy/references/main-branch-detection.md +3 -6
  19. package/commands/alloy/references/phase-downgrade-path.md +27 -0
  20. package/commands/alloy/references/plan-rollback.md +84 -0
  21. package/commands/alloy/references/spec-sync.md +62 -0
  22. package/commands/alloy/references/start-rationalizations.md +18 -0
  23. package/commands/alloy/start.md +178 -238
  24. package/dist/cli/commands/completion.js +13 -2
  25. package/dist/cli/commands/completion.js.map +1 -1
  26. package/dist/cli/commands/internal/artifact.d.ts +7 -0
  27. package/dist/cli/commands/internal/artifact.js +70 -0
  28. package/dist/cli/commands/internal/artifact.js.map +1 -0
  29. package/dist/cli/commands/internal/guard.js +204 -2
  30. package/dist/cli/commands/internal/guard.js.map +1 -1
  31. package/dist/cli/commands/internal/progress.d.ts +10 -0
  32. package/dist/cli/commands/internal/progress.js +70 -0
  33. package/dist/cli/commands/internal/progress.js.map +1 -0
  34. package/dist/cli/commands/internal/spec-audit.d.ts +42 -0
  35. package/dist/cli/commands/internal/spec-audit.js +363 -0
  36. package/dist/cli/commands/internal/spec-audit.js.map +1 -0
  37. package/dist/cli/commands/internal/state.js +4 -0
  38. package/dist/cli/commands/internal/state.js.map +1 -1
  39. package/dist/cli/index.js +30 -0
  40. package/dist/cli/index.js.map +1 -1
  41. package/package.json +2 -1
@@ -3,368 +3,245 @@ name: "Alloy: Plan"
3
3
  description: Alloy 规划阶段 - draft.md 完成后进入
4
4
  category: Workflow
5
5
  tags: [alloy, workflow]
6
+ spec: 01-product-spec/02-plan-spec.md
7
+ behaviors:
8
+ preconditions: 7
9
+ hard_stops: 10
10
+ user_gates: 7
11
+ warns: 1
12
+ artifacts: [proposal, design, specs, tasks, plans]
13
+ transitions_to: planned
14
+ external_calls: [opsx:continue, superpowers:writing-plans]
6
15
  ---
7
16
 
8
17
  # alloy-plan
9
18
 
10
- 你是 Alloy 的规划阶段编排器。你的职责是按 OpenSpec schema DAG 依赖顺序,制品生成设计文档,每步生成后提供审查窗口。
19
+ 你是 Alloy 的规划阶段编排器。按 OpenSpec schema DAG 依赖顺序,制品生成设计文档,每步生成后提供审查窗口。
11
20
 
12
- **核心原则:按 schema DAG 依赖顺序逐一产出制品,每步有审查闸门,不跳过上游直接产下游。**
21
+ ```
22
+ [HARD_STOP] NO DIRECT EDITING OF GENERATED ARTIFACTS + NO SKIP REVIEW WINDOW
23
+ 5 个制品 = 5 个审查窗口;已生成制品禁止直接编辑,必须重新生成
24
+ 违反字面 = 违反精神:哪怕"只改一个错别字直接编辑"、"已经看过 draft 后面跳过审查"、或用户主动说"后面不用看了一次性过",也算违反 Iron Law。审查窗口不可跳过——用户要求跳过不算授权。
25
+ ```
13
26
 
14
- **交互风格:** 所有审查窗口和用户选择使用 `AskUserQuestion` 工具(箭头选、Enter 确认),不用纯文本 "(a)(b)"。详见 `commands/alloy/references/interaction-style.md`。
27
+ **核心原则:按 schema DAG 依赖顺序逐一产出制品,每步有审查闸门,不跳过上游直接产下游。** 5 制品(proposal/design/specs/tasks/plans)以 hash-lock + 单独 commit 入 records,禁直接编辑,禁互相替代。
15
28
 
16
- **调用外部命令或技能前,先输出标题和状态描述,再执行操作。不要只出标题然后沉默。**
29
+ **交互规则:** `🔴 STOP` 等价 `USER_GATE`,必须用 `AskUserQuestion`(`commands/alloy/references/interaction-style.md`,含"沉默 ≠ 授权"通用禁令——禁批量打包、禁基于内容跳过、禁 agent 回填精确字符串)。跳过任何 USER_GATE = 违反 Iron Law。
17
30
 
18
- **什么算"plan 执行不到位"(反例):**
19
- - 用户说"一次性生成"就直接出全部制品——跳过了 5 个审查窗口,失去了需求验证的时机
20
- - 用户说"太慢了"就加速跳过审查——审查时间远小于返工时间
21
- - 用户说"我看过 draft 了,内容都对"就松懈——draft 审查不能替代 proposal/design/specs/tasks 的逐级审查
31
+ **状态符号:** `⛔` = HARD_STOP / PRECONDITION_FAIL,`🔴` = USER_GATE,`⚠️` = WARN(视觉规范 §七)。
22
32
 
23
- ### Red Flags——STOP,必须分步审查
33
+ **调用外部命令或技能前,先输出标题和状态描述,再执行操作。**
24
34
 
25
- | 借口 | 现实 |
26
- |------|------|
27
- | "一次性生成全部制品,提高效率" | plan 不提供一键生成。5 个制品 = 5 个审查窗口。每步审查的价值远大于省下的几秒。跳过审查 = 跳过需求验证。 |
28
- | "太慢了,直接出全部吧" | 审查时间远小于后期返工时间。一个未审查的 specs 缺陷到 apply 阶段才发现,代价是重做全部代码。 |
29
- | "我看过 draft 了,后面的不用看了" | draft 是方案设计,proposal 是提案范围,design 是技术方案,specs 是行为契约——四个层面不可互相替代。 |
30
- | "这个项目很小,不需要那么正式" | 小项目和大项目的闸门完全一样。不存在"规模分级的保护等级"。 |
31
-
32
- **捕获阶段启动时间**(命令调用后第一时间,前置检查之前,幂等——重入时返回已有值):
35
+ **捕获阶段启动时间**(幂等,重入时返回已有值):
33
36
  ```bash
34
37
  PHASE_START=$(alloy _state timestamp ensure openspec/changes/<name> plan)
35
38
  ```
36
39
 
37
40
  ---
38
41
 
39
- ## 前置检查
40
-
41
- 1. 确认 change 目录 `openspec/changes/<name>/` 存在且 `.alloy.yaml` phase 为 `started`(由 `/alloy:start` 完成),否则报错
42
- 2. 若 change 目录存在但 `draft.md` 缺失 → 异常状态,提示重新运行 `/alloy:start`
43
- 3. 若指定 `[name]` 参数但 change 不存在 → "未找到 change '<name>',请先运行 `/alloy:start <name>` 创建 change"
44
- 4. **Skill / 命令预检:** 确认以下依赖可用:
45
- cmd: opsx/continue
46
- skill: writing-plans
42
+ ### Red Flags(第三层防御——任一借口出现即 STOP)
47
43
 
48
- 读取 `commands/alloy/references/skill-precheck.md` 了解检测方法。任一不可用 引导 `alloy init` → STOP。
44
+ | 借口 | 现实 |
45
+ |------|------|
46
+ | "一次性生成全部制品,提高效率" | ⛔ HARD_STOP:5 个制品 = 5 个审查窗口,禁 agent 一次性生成。跳过审查 = 跳过需求验证,后期返工代价远大于审查时间(Iron Law 第一层)。 |
47
+ | "太慢了,直接出全部吧" | 审查时间远小于后期返工。未审查的 specs 缺陷到 apply 才发现 = 重做全部代码。 |
48
+ | "我看过 draft 了,后面的不用看了" | draft 是方案设计,proposal 是提案范围,design 是技术方案,specs 是行为契约——四个层面不可互相替代(⛔ HARD_STOP)。即使用户主动说"后面不用看了",审查窗口也不可跳过。 |
49
+ | "只是改个错别字,直接编辑文件吧" | 已生成制品禁止直接编辑——哪怕错别字也必须重新生成(违反字面 = 违反精神)。 |
50
+ | "用户要加功能,我重置 proposal 重新生成就行" | 功能变更必须回溯清理所有下游制品——重置单个制品 = 上下游需求不一致。`alloy _artifact reset` 仅限措辞/格式修正。 |
51
+ | "需求变更了,直接回溯清理吧" | 回溯是不可逆删除——必须让用户看到两条路径后主动选择 + 已自动打 snapshot tag(task #15)。 |
52
+ | "需求变更和轻量修正差不多,先 reset 试试看" | ⛔ HARD_STOP:分类不清前禁执行 `_artifact reset`。需求变更 = 删除全部 plan 制品,轻量修正 = 只重置一个制品。后果完全不同。 |
53
+ | "draft 的 commit message 看着像是确认了,跳过 hash 校验吧" | ⛔ PRECONDITION_FAIL:draft 来源必须 `alloy _record check` 验证 hash 链(task #16),commit msg 字符串解析不可靠。 |
54
+ | "rollback 失败了,git reset --hard 清场重来" | ⛔ HARD_STOP:rollback 失败时禁 reset --hard / checkout . / stash drop(§3.5.1 git 自救禁令)。退出 skill 让用户处理。 |
55
+ | "phase 推进失败但 plans 已生成,git reset 回退一下" | ⛔ HARD_STOP:phase 推进路径 B 降级——手动 `alloy _state set` 回退 phase,禁 git reset 清场(§5.2.3)。 |
56
+ | "用户在等,分类先按轻量修正走,错了再说" | 分类不清 = 默认需求变更(plan-rollback.md 已写)。USER_GATE 必须用户明确选择。 |
57
+ | "这个项目很小,不需要那么正式" | 小项目和大项目的闸门完全一样。不存在"规模分级的保护等级"。 |
49
58
 
50
59
  ---
51
60
 
52
- ### [Step 1/3] 确认 Change
61
+ ### [Step 0/3] 前置检查
53
62
 
54
- ```
55
- ┌──────────────────────────────────────┐
56
- Alloy [2/5] · Phase: Plan │
57
- │ 启动时间: $PHASE_START
58
- └──────────────────────────────────────┘
59
-
60
- [Step 1/3] 确认 Change
61
- ──────────────────────────────────────
62
- ```
63
-
64
- 1. 确认 `openspec/changes/<name>/draft.md` 存在,并验证来源:
65
- ```bash
66
- git log -1 --format="%s" -- openspec/changes/<name>/draft.md
67
- ```
68
- 若 commit message 不含 `docs(<name>): draft 已确认`→ ⚠️ draft.md 可能未经过完整 `/alloy:start` 流程(手工创建),提示用户确认是否继续。不阻断——但给用户知情权。
69
- 2. 确认 `.alloy.yaml` phase 为 `started`:
70
- ```bash
71
- alloy _state check openspec/changes/<name> started
72
- ```
73
- 3. 确认 git 仓库可用:
74
- ```bash
75
- git rev-parse --git-dir
76
- ```
77
- 若失败 → HARD STOP:"项目还不是 git 仓库。请先运行 `/alloy:start` 完成初始化(包含 git init)。"
63
+ 1. **change 目录存在 + draft.md 存在**(⛔ PRECONDITION_FAIL):
64
+ - change 不存在 → 引导 `/alloy:start <name>` 创建
65
+ - draft.md 缺失 异常状态,引导重新运行 `/alloy:start`
78
66
 
79
- 前置检查通过:draft.md phase=started ✓ git ✓ 技能
67
+ 2. **phase 校验**(⛔ PRECONDITION_FAIL):`alloy _guard precheck openspec/changes/<name> started`
68
+ - phase ≠ started 时读取 `commands/alloy/references/phase-routing.md` 自动跳转
69
+ - 路由不到合法状态 → ⛔ PRECONDITION_FAIL
80
70
 
81
- **若 phase 不匹配(phase != started):**
71
+ 3. **git 仓库检查**(⛔ PRECONDITION_FAIL):`git rev-parse --git-dir`,失败 → 引导初始化或退出。
82
72
 
83
- 读取 `commands/alloy/references/phase-routing.md` 按路由表自动跳转。实现方式:输出对应命令文件的完整指令,将 change name 和当前进度信息作为上下文传入。
73
+ 4. **Skill 预检**(⛔ PRECONDITION_FAIL):cmd: opsx/continue, skill: writing-plans
74
+ 读取 `commands/alloy/references/skill-precheck.md` 检测。任一不可用 → 引导 `alloy init`,不存在降级。
84
75
 
85
- **若 change 目录不存在或 draft.md 缺失:**
86
- → 引导用户先运行 `/alloy:start <name>` 创建 change。这是唯一保留 HARD STOP 的场景——前序阶段完全没做。
76
+ 5. **draft 来源验证**(⛔ PRECONDITION_FAIL,task #16):用 hash 链验证 draft 完整性,**禁用 commit msg 字符串解析**:
87
77
 
88
- ---
78
+ ```bash
79
+ if ! alloy _record check openspec/changes/<name> draft 2>/dev/null; then
80
+ echo "⛔ PRECONDITION_FAIL: draft hash 验证失败"
81
+ echo " 原因:draft.md 内容与 records 中记录的 hash 不一致"
82
+ echo " 可能:draft 被手动编辑 / records 被破坏 / 未经完整 start 流程"
83
+ echo " 禁止:agent 自动接受不一致的 draft 继续生成下游制品"
84
+ echo ""
85
+ echo "🔴 USER_GATE: 选择处理路径"
86
+ echo " (a) 回溯到 /alloy:start 重新确认 draft"
87
+ echo " (b) 强制继续——下游制品将基于不可信 draft 生成(不推荐)"
88
+ fi
89
+ ```
89
90
 
90
- ### [Step 2/3] 制品生成 · /opsx:continue + writing-plans
91
+ `_record check` 命令已存在并被 archive/apply/finish 使用,参照实现保持一致。
91
92
 
92
- [Step 2/3] 制品生成
93
- ──────────────────────────────────────
93
+ 6. **多 change 并行检查**(⚠️ WARN):扫描其他 change 是否处于 plan/apply 阶段,提示用户 plan 阶段是单 change 串行(避免 schema DAG 跨 change 干扰):
94
94
 
95
- **每个制品(proposal / design / specs / tasks)必须通过 `/opsx:continue` 生成。禁止手动编写制品文件。** `/opsx:continue` 自动读取 schema DAG,按 `proposal → design → specs → tasks` 顺序依次产出,每次调用生成一个制品。**tasks 是 `/opsx:continue` 生成的最后一个制品。**plans.md 由 `superpowers:writing-plans` 技能生成(见下文)。
95
+ ```bash
96
+ ACTIVE=$(find openspec/changes -maxdepth 2 -name '.alloy.yaml' -exec grep -l 'phase: \(started\|planned\|applied\)' {} \; 2>/dev/null | wc -l | tr -d ' ')
97
+ if [ "$ACTIVE" -gt 1 ]; then
98
+ echo "⚠️ WARN: 检测到 $ACTIVE 个活跃 change,建议串行处理"
99
+ fi
100
+ ```
96
101
 
97
- 作为编排器,你的职责是在每次 `/opsx:continue` 生成制品后插入审查窗口。**始终分步,不提供一键生成。**
102
+ 前置检查通过:draft.md phase=started ✓ git ✓ 技能 ✓ draft hash ✓
98
103
 
99
- **执行方式:** 使用 Skill 工具加载 `opsx:continue` 技能,传入 change name。`opsx:continue` 自动获取 schema 指令并生成对应的制品文件——不要自行编写制品内容,不要一次生成多个制品。
104
+ ---
100
105
 
101
- 如果 `/opsx:continue` 不可用,引导用户运行 `alloy init` 完成环境初始化。
106
+ ### [Step 1/3] 确认 Change
102
107
 
103
- **制品 DAG 及依赖关系:**
104
108
  ```
105
- proposal ──→ design ──→ specs ──→ tasks ──→ plans
106
-
107
- └──────────────────────┘
109
+ ┌──────────────────────────────────────┐
110
+ Alloy [2/5] · Phase: Plan │
111
+ │ 启动时间: $PHASE_START
112
+ └──────────────────────────────────────┘
108
113
  ```
109
114
 
110
- | 制品 | 依赖 | 被依赖 |
111
- |------|------|--------|
112
- | proposal | draft.md | design, specs |
113
- | design | proposal + draft.md | specs, tasks |
114
- | specs | proposal(只读 Capabilities) | tasks |
115
- | tasks | specs + design | plans |
116
- | plans | tasks | — |
115
+ draft.md 来源已在 Step 0 完成 hash 验证(task #16)。本步聚焦 phase 校验和路由:
117
116
 
118
- **注意:plans.md 是执行脚本,非规格文档。** 规格(specs/)是行为契约,plans.md 是给 Agent 执行的微步骤路线图(可含代码片段)。
117
+ 1. 阶段校验:`alloy _guard precheck openspec/changes/<name> started`(已在 Step 0 通过,本步幂等重检)
118
+ 2. **若 phase 不匹配:** 读取 `commands/alloy/references/phase-routing.md` 自动跳转到对应 skill。
119
+ 3. **若 change 不存在或 draft.md 缺失:** 引导 `/alloy:start <name>`——前序阶段完全没做时保留 ⛔ PRECONDITION_FAIL。
119
120
 
120
- ### 制品进度扫描
121
+ 前置检查通过:draft.md ✓ phase=started ✓ git ✓ 技能 ✓ draft hash ✓
121
122
 
122
- 在调用 `/opsx:continue` 之前,先扫描哪些制品已完成(文件存在 + hash 有效):
123
+ ---
123
124
 
124
- ```bash
125
- # 扫描已完成制品
126
- for artifact in proposal design specs tasks plans; do
127
- if alloy _record check openspec/changes/<name> "$artifact" 2>/dev/null; then
128
- echo " $artifact ✓"
129
- else
130
- echo " $artifact ✗"
131
- fi
132
- done
133
- ```
125
+ ### [Step 2/3] 制品生成 · /opsx:continue + writing-plans
134
126
 
135
- 根据扫描结果,从第一个缺失的制品开始生成:
127
+ **每个制品必须通过 `/opsx:continue` 生成。禁止手动编写制品文件。**
136
128
 
137
- ```
138
- 制品进度扫描:
139
- proposal ✓ hash 有效 → 跳过
140
- design ✓ hash 有效 → 跳过
141
- specs ✗ → 从 specs 开始生成
129
+ 使用 Skill 工具加载 `opsx:continue`,传入 change name。`/opsx:continue` 自动获取 schema 指令并生成制品——不要自行编写,不要一次生成多个。
142
130
 
143
- → /opsx:continue 从第一个缺失制品开始
131
+ ```bash
132
+ alloy _skill log openspec/changes/<name> plan opsx:continue
144
133
  ```
145
134
 
146
- 制品全部完成(plans.md 存在且 hash 有效)时,phase 推进到 planned,提示下一步。
147
-
148
- **不要输出全局制品进度**(如"0/8 artifacts 完成")。[N/M] 是阶段内局部编号(M=5),不反映全局进度。全局进度由 `alloy status` 命令管理。
149
-
150
- ### 正常推进:逐个制品的审查流程
135
+ **制品 DAG:** `proposal → design → specs → tasks → plans`(specs 还依赖 proposal 只读 Capabilities)
151
136
 
152
- 每个制品生成后,展示内容并进入审查窗口。**仅两个选项——不跳过。**
137
+ **git add 规则(§5.2.1 内嵌约束,HARD_STOP):** 每个制品 commit 必须用精确路径(`openspec/changes/<name>/`),禁 `-A`/`-a`/`.`。违反字面 = 违反精神:哪怕"反正只改一个 markdown 文件",也禁止 `-A`——agent 看不到的副作用文件可能被一并提交。
153
138
 
154
- 审查窗口分两步:**先**用 markdown 文本展示制品完整内容(审查窗口块引用),**后**用 `AskUserQuestion` 工具让用户确认(radio,2 option)。不要用纯文本 "(a)(b)" 等用户打字。
139
+ **git 自救禁令(§3.5.1 内嵌约束,HARD_STOP):** 制品生成或 commit 失败时禁 `git checkout .` / `git restore .` / `git reset --hard` / `git stash` / `git clean -fd`——退出 skill 让用户处理是唯一合法路径。
155
140
 
156
- **制品 [1/5] proposal:**
157
-
158
- > 制品 [1/5] proposal ✓ 完成
159
- >
160
- > [展示 proposal.md 完整内容]
161
- >
162
- > → 下一个:design(依赖 proposal + draft.md)
163
- >
164
- > → (a) 确认,锁定 proposal 并继续 design
165
- > → (b) 需要调整 — 说明修改点
166
-
167
- **制品 [2/5] design:**
141
+ **制品进度扫描**(调用 `/opsx:continue` 之前):
142
+ ```bash
143
+ alloy _progress artifacts openspec/changes/<name>
144
+ ```
145
+ 从第一个缺失/hash-mismatch 的制品开始生成。全部 done 时 🔴 USER_GATE:所有制品已锁定,确认推进 phase(确认 / 重新审查某个制品——指定制品名)。
168
146
 
169
- > 制品 [2/5] design 完成
170
- >
171
- > [展示 design.md 完整内容]
172
- >
173
- > → 下一个:specs(依赖 proposal)
174
- >
175
- > → (a) 确认,锁定 design 并继续 specs
176
- > → (b) 需要调整 — 说明修改点
147
+ > [N/M] 是阶段内局部编号(M=5),不输出全局制品进度。全局进度由 `alloy status` 管理。
177
148
 
178
- **制品 [3/5] specs:**
149
+ ### 逐个制品审查流程
179
150
 
180
- > 制品 [3/5] specs 完成
181
- >
182
- > [展示 specs/ 完整内容]
183
- >
184
- > → 下一个:tasks(依赖 specs + design)
185
- >
186
- > → (a) 确认,锁定 specs 并继续 tasks
187
- > → (b) 需要调整 — 说明修改点
151
+ **[HARD_STOP] 即使用户主动说"后面不用看了"、"一次性过完"、"效率太低了",审查窗口也不可跳过。** 5 个制品 = 5 个审查窗口——用户要求跳过不算授权。
188
152
 
189
- **制品 [4/5] tasks:**
153
+ 每个制品生成后,展示完整内容 + 🔴 USER_GATE 审查窗口:
190
154
 
191
- > 制品 [4/5] tasks ✓ 完成
192
- >
193
- > [展示 tasks.md 完整内容]
194
- >
195
- > → 下一个:plans(依赖 tasks)
196
- >
197
- > → (a) 确认,锁定 tasks 并继续生成 plans
198
- > → (b) 需要调整 — 说明修改点
155
+ > 制品 [N/5] \<artifact\> ✓ 完成
156
+ > [展示制品完整内容]
157
+ > 🔴 USER_GATE: 确认锁定 <artifact>(确认并继续 / 需要调整)
199
158
 
200
- **制品 [5/5] plans:**
159
+ - **选 (a):** hash 锁定 + commit(详见 `commands/alloy/references/artifact-hash-commit.md`):
160
+ ```bash
161
+ HASH=$(alloy _record compute openspec/changes/<name> <artifact>)
162
+ APPROVED_AT=$(date "+%Y-%m-%d %H:%M:%S")
163
+ APPROVER=$(alloy _record approver openspec/changes/<name>)
164
+ alloy _record write openspec/changes/<name> <artifact> "$HASH" "$APPROVED_AT" "$APPROVER"
165
+ # §5.2.1 git add 限路径
166
+ git add openspec/changes/<name>/
167
+ git commit -m "docs(<name>): <artifact> 已确认"
168
+ ```
201
169
 
202
- > 制品 [5/5] plans 完成
203
- >
204
- > [展示 plans.md 完整内容]
205
- >
206
- > → plan 阶段完成
207
- >
208
- > → (a) 确认,锁定 plans 并完成 plan 阶段
209
- > → (b) 需要调整 — 说明修改点
170
+ 生成下一制品前校验上游 hash:`alloy _record check openspec/changes/<name> <upstream>`,失败 ⛔ PRECONDITION_FAIL(上游被破坏,必须修复后才能继续生成下游)。
210
171
 
211
- **审查窗口只展示制品内容,不打印 OpenSpec schema 的 instructions 模板。** instructions 是给 Agent 的内部指引,不是给用户审查的输出。
172
+ - **选 (b):** 用户提出修改后,**先分类再行动**:
212
173
 
213
- - **选 (a)**:当前制品锁定,进入下一个制品或阶段
214
- - **选 (b)**:用户说明修改点后,AI 内部评估修改性质,然后呈现确认选项:
174
+ > [HARD_STOP] 分类不清前禁执行 `alloy _artifact reset`。
175
+ > 违反字面 = 违反精神:哪怕"看起来像措辞修正",分类不清就是分类不清——必须 USER_GATE 让用户明确。
215
176
 
216
- > (a) 确认变更,回溯到 brainstorming
217
- > → (b) 取消变更,继续当前审查
177
+ - **需求变更**(功能增删、行为变更、用户主动提出"加入/删除/修改"功能)→ 🔴 USER_GATE:选择处理路径:
218
178
 
219
- **AI 判断指南(内部推理,不对外展示标签):**
220
- - typo/措辞修正(错别字、格式调整、表达优化,不改变功能边界)→ 内部标记为轻量变更
221
- - 需求层面变更(功能增删、行为变更、范围调整)→ 内部标记为需求变更
179
+ > AskUserQuestion: 检测到需求变更,选择处理路径
180
+ > (a) 回溯到 brainstorming 重新讨论(删除所有 plan 制品,保留 draft.md)
181
+ > (b) 取消调整,继续当前审查
182
+ >
183
+ > 注意:选 (a) 会自动打 snapshot tag `rollback-<name>-<timestamp>`,
184
+ > 事后可用 `git checkout <tag> -- openspec/changes/<name>/` 恢复(task #15)。
222
185
 
223
- 无论 AI 如何判断,始终向用户呈现相同的 (a)/(b) 两个选项。
224
- 用户选 (a) → 执行回溯清理步骤,加载 `superpowers:brainstorming`。brainstorming 负责重新讨论需求,用户确认后回到这里继续生成制品(不是 invoke writing-plans——那是独立使用 brainstorming 时的行为)。
225
- 用户选 (b) → 回到当前审查窗口,重新展示 (a) 确认 / (b) 需要调整 选项。
186
+ (a):执行回溯清理(详见 `commands/alloy/references/plan-rollback.md`),然后加载 `superpowers:brainstorming` 重新讨论。**此类场景禁止使用 `alloy _artifact reset`。**
187
+ (b):回到审查窗口,重新展示制品内容。
226
188
 
227
- **什么算"审查不充分"(反例):**
228
- - 只问了一句"看起来可以吗?"没有展示实际内容
229
- - 用户说"继续"但没有明确说"确认"
230
- - 用户不明确表态时催促用户给出 (a) 或 (b)
189
+ - **轻量修正**(措辞/格式,不改变功能边界)→ 🔴 USER_GATE:确认走轻量修正路径(仅限用户明确说"措辞/格式调整")。确认后:`alloy _artifact reset openspec/changes/<name> <artifact>` → `/opsx:continue` 重新生成 → **diff 审查窗口(见下方"轻量修正 diff USER_GATE")** → 重新审查。下游已锁定制品保持不变。
231
190
 
232
- ### 每制品审批后 hash + commit
191
+ **判断规则:** 用户主动提出"加入/删除/修改功能"= 需求变更,直接回溯,不问路径。只有用户明确说"措辞/格式调整"才走轻量修正(且需 🔴 USER_GATE 确认)。不确定时默认需求变更。
233
192
 
234
- 每个制品审批通过(用户选 a)后,立即 hash 锁定并 commit:
193
+ **无论哪条路径,都不直接编辑已生成的制品文件**(违反字面 = 违反精神:制品禁直接编辑)。
235
194
 
236
- **hash 锁定前,记录技能使用:**
237
- ```bash
238
- alloy _skill log openspec/changes/<name> plan opsx:continue
239
- ```
195
+ **轻量修正 diff USER_GATE(HARD_STOP,task L3):** reset + 重新生成后、重新审查前,必须采集 diff 并让用户物理确认——agent 不得基于 `/opsx:continue` 返回成功直接进入审查窗口。
240
196
 
241
197
  ```bash
242
- HASH=$(alloy _record compute openspec/changes/<name> <artifact>)
243
- APPROVED_AT=$(date "+%Y-%m-%d %H:%M:%S")
244
- APPROVER=$(alloy _record approver openspec/changes/<name>)
245
- alloy _record write openspec/changes/<name> <artifact> "$HASH" "$APPROVED_AT" "$APPROVER"
246
- git add openspec/changes/<name>/
247
- git commit -m "docs(<name>): <artifact> 已确认"
198
+ # 重新生成后,先 diff 再审查
199
+ DIFF_OLD=$(git show HEAD:"openspec/changes/<name>/<artifact>.md" 2>/dev/null)
200
+ DIFF_NEW=$(cat "openspec/changes/<name>/<artifact>.md" 2>/dev/null)
248
201
  ```
249
202
 
250
- **plans plan 阶段最后一个制品。** plans 审批通过后,phase_timings + hash-lock 合并为**一个 commit**——禁止拆成两次提交:
251
-
252
- ```bash
253
- # 写入完成时间 + hash 锁定 + 提交,一气呵成
254
- COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
255
- alloy _state merge openspec/changes/<name> phase_timings "{\"plan\":{\"completed_at\":\"${COMPLETED_AT:-$(date '+%Y-%m-%d %H:%M:%S')}\"}}"
256
- HASH=$(alloy _record compute openspec/changes/<name> plans)
257
- APPROVED_AT=$(date "+%Y-%m-%d %H:%M:%S")
258
- APPROVER=$(alloy _record approver openspec/changes/<name>)
259
- alloy _record write openspec/changes/<name> plans "$HASH" "$APPROVED_AT" "$APPROVER"
260
- git add openspec/changes/<name>/
261
- git commit -m "docs(<name>): plans 已确认"
262
- ```
203
+ 🔴 USER_GATE(必须 AskUserQuestion):
263
204
 
264
- commit message 格式:`docs(<change-name>): <artifact> 已确认`(Conventional Commits `docs` type)。`<artifact>` 为 proposal / design / specs / tasks / plans。
205
+ > 轻量修正 diff:
206
+ > ```
207
+ > [git diff HEAD -- openspec/changes/<name>/<artifact>.md | head -100]
208
+ > ```
209
+ > 确认变更仅涉及措辞/格式(不改变功能边界):
210
+ > (a) 确认——仅措辞/格式,继续锁 hash
211
+ > (b) 发现功能变更——放弃轻量修正,回到需求变更路径重新分类
212
+ > (c) 放弃调整——回退到 reset 前状态(`git checkout HEAD -- openspec/changes/<name>/<artifact>.md`)
265
213
 
266
- **生成下一制品前,校验上游依赖制品的 hash 未被篡改:**
267
- ```bash
268
- alloy _record check openspec/changes/<name> <upstream-artifact>
269
- ```
270
- 若 check 返回非零 → HARD STOP,hash 不匹配意味着有未审批的篡改。
214
+ **[HARD_STOP]** agent 不得基于 "diff 看起来没改功能" 自动选 (a)——必须用户物理选择(interaction-style.md "沉默 ≠ 授权")。diff 必须截前 100 行防爆量,但禁 agent 基于 "diff 短" 跳过调用。(违反字面 = 违反精神:制品禁直接编辑)。
271
215
 
272
- | 即将生成的制品 | 需校验的上游 |
273
- |--------------|------------|
274
- | design | proposal |
275
- | specs | proposal |
276
- | tasks | specs, design |
277
- | plans | tasks |
216
+ **审查窗口只展示制品内容,不打印 schema instructions 模板。**
278
217
 
279
- ### tasks 审批通过后 → writing-plans 生成 plans.md
218
+ ### tasks 审批后 → writing-plans
280
219
 
281
- tasks 审批通过并 commit 后,**加载 `superpowers:writing-plans` 技能**生成 plans.md
220
+ tasks 审批通过并 commit 后,加载 `superpowers:writing-plans` 生成 plans.md
282
221
 
283
- > 使用 Skill 工具加载 `superpowers:writing-plans` 技能,将 tasks + specs + design 作为上下文传入。**遵循 writing-plans 的完整原始流程**——从文件结构设计、任务拆解、代码填充,到末尾的"执行交接"。writing-plans 自行决定执行策略并写入 plans.md YAML frontmatter(`strategy` + `reason` 字段)。
284
- >
285
- > **注意:** writing-plans 默认保存路径为 `docs/superpowers/plans/`,Alloy 要求将 plans.md 保存到 `openspec/changes/<name>/plans.md`。加载 writing-plans 时需显式指定此路径。
286
- >
287
- > alloy 不在 plan 阶段额外询问策略选择——writing-plans 的决策直接保留在 frontmatter 中,apply 阶段再读取并给用户确认。
222
+ - 传入 tasks + specs + design 作为上下文
223
+ - **遵循 writing-plans 完整原始流程**——从任务拆解到执行交接
224
+ - 保存路径:`openspec/changes/<name>/plans.md`(非默认的 `docs/superpowers/plans/`)
225
+ - writing-plans 自行决定执行策略,写入 frontmatter(`strategy` + `reason`)
288
226
 
289
- **技能加载后立即记录:**
290
227
  ```bash
291
228
  alloy _skill log openspec/changes/<name> plan superpowers:writing-plans
292
229
  ```
293
230
 
294
- writing-plans 完成并保存 plans.md(含 strategy frontmatter)后,直接进入 plans 审查窗口。frontmatter 格式:
295
-
231
+ plans.md frontmatter 格式:
296
232
  ```yaml
297
233
  ---
298
234
  strategy: sdd
299
235
  reason: <writing-plans 执行交接环节的策略分析理由>
300
236
  ---
301
- # 执行计划
302
- ...
303
- ```
304
-
305
- plans.md 生成后展示审查窗口,审批通过后先写入 phase_timings.completed_at,再 hash 锁定并 commit(phase_timings 作为元数据附着在 plans 制品提交上,不单独 commit)。
306
-
307
- ### 回溯修改:修改已确认的上游制品
308
-
309
- plan 阶段处理的是"构建什么"——任何制品一旦审批通过,不允许就地修改。需求/设计层面的调整都应从 draft 根重新审视,而非打补丁。
310
-
311
- **规则——统一回到 brainstorming:**
312
-
313
- | 要修改的制品 | 行为 |
314
- |------------|------|
315
- | draft / proposal / design / specs / tasks / plans | 清理 plan 制品 → 回到 brainstorming |
316
-
317
- > apply 阶段的需求变更见 apply.md 的"需求变更处理"闸门——以 tasks.md checkbox 状态判断是否允许回溯。verify/retrospective 验证"代码是否匹配规格",发现问题修正代码,不改变需求/设计。
318
-
319
- **回溯清理步骤:**
320
-
321
- ```bash
322
- # 1. 删除 plan 制品文件(保留 draft.md)
323
- rm -f openspec/changes/<name>/proposal.md
324
- rm -f openspec/changes/<name>/design.md
325
- rm -f openspec/changes/<name>/tasks.md
326
- rm -f openspec/changes/<name>/plans.md
327
- rm -rf openspec/changes/<name>/specs/
328
-
329
- # 2. 清理 records(只保留 draft)
330
- DRAFT_RECORD=$(alloy _state read openspec/changes/<name> records | python3 -c "
331
- import sys,json
332
- content = sys.stdin.read().strip()
333
- records = json.loads(content) if content and content != 'null' else []
334
- draft = [r for r in records if r.get('artifact') == 'draft']
335
- print(json.dumps(draft))
336
- ")
337
- alloy _state write openspec/changes/<name> records "$DRAFT_RECORD"
338
-
339
- # 3. 清理 phase_timings(清除 plan/apply/archive/finish 记录,重置 start.completed_at)
340
- # ⚠️ 此处是 phase_timings 唯一允许 _state write 的场景:回溯需要删除 key + 覆盖值,merge 语义不支持。
341
- # 所有其他 phase_timings 更新必须使用 _state merge,禁止 _state write。
342
- TIMINGS=$(alloy _state read openspec/changes/<name> phase_timings 2>/dev/null || echo "{}")
343
- echo "$TIMINGS" | python3 -c "
344
- import sys,json
345
- content = sys.stdin.read().strip()
346
- d = json.loads(content) if content and content != 'null' else {}
347
- for k in ['plan','apply','archive','finish']:
348
- d.pop(k, None)
349
- if 'start' in d:
350
- d['start']['completed_at'] = None
351
- print(json.dumps(d))
352
- " | while read -r val; do alloy _state write openspec/changes/<name> phase_timings "$val"; done
353
-
354
- git add openspec/changes/<name>/
355
- git commit -m "chore(<name>): 回溯——清理 plan 制品,回到 brainstorming"
356
237
  ```
357
238
 
358
- ```
359
- → 制品已清理(仅保留 draft),records/phase_timings 已重置
360
- → 请运行 /alloy:start <name> 重新走需求确认流程
361
- ```
239
+ plans 审批通过后,phase_timings + hash-lock 合并为**一个 commit**(详见 `commands/alloy/references/artifact-hash-commit.md`"阶段最后一个制品"部分)。
362
240
 
363
241
  ---
364
242
 
365
243
  ### [Step 3/3] 完成
366
244
 
367
- 先读取所有 record 的时间戳用于汇总展示:
368
245
  ```bash
369
246
  alloy _state read openspec/changes/<name> records
370
247
  ```
@@ -372,51 +249,77 @@ alloy _state read openspec/changes/<name> records
372
249
  ```
373
250
  ┌──────────────────────────────────────┐
374
251
  │ Alloy [2/5] · Phase: Plan — DONE │
375
- │ 启动时间: phase_timings.plan.started_at 读取
376
- │ 完成时间: phase_timings.plan.completed_at 读取
377
- │ 耗时: completed_at - started_at
252
+ │ 启动时间: phase_timings.plan.started_at
253
+ │ 完成时间: phase_timings.plan.completed_at
254
+ │ 耗时: completed_at - started_at
378
255
  └──────────────────────────────────────┘
379
256
 
380
- → Change: <name>
381
- Phase: planned
257
+ → Change: <name> Phase: planned
258
+ 制品: draft ✓ proposal ✓ design ✓ specs ✓ tasks ✓ plans ✓
259
+ ```
260
+
261
+ **hash 链尾扫(⛔ HARD_STOP,task L2):** 在 phase 推进前对全部 6 个制品(draft + proposal + design + specs + tasks + plans)逐条执行 `alloy _record check`——这是 phase 锁定前最后一次完整性校验,任何 hash 不匹配都必须暴露给用户。
382
262
 
383
- 所有制品已生成并锁定:
263
+ ```bash
264
+ ALL_PASS=true
265
+ for ARTIFACT in draft proposal design specs tasks plans; do
266
+ if [ ! -f "openspec/changes/<name>/${ARTIFACT}.md" ]; then
267
+ echo " ✗ $ARTIFACT: 文件缺失"
268
+ ALL_PASS=false
269
+ elif alloy _record check "openspec/changes/<name>" "$ARTIFACT" 2>/dev/null; then
270
+ echo " ✓ $ARTIFACT: hash 一致"
271
+ else
272
+ echo " ✗ $ARTIFACT: hash 不匹配"
273
+ ALL_PASS=false
274
+ fi
275
+ done
384
276
 
385
- 制品 状态 Hash 创建时间
386
- ────────────── ──── ──────────── ───────────────────
387
- draft <hash> <timestamp>
388
- proposal ✓ <hash> <timestamp>
389
- design ✓ <hash> <timestamp>
390
- specs ✓ <hash> <timestamp>
391
- tasks ✓ <hash> <timestamp>
392
- plans ✓ <hash> <timestamp>
277
+ echo "---"
278
+ if [ "$ALL_PASS" = "true" ]; then
279
+ echo " 全部 6 个制品 hash 链完整"
280
+ else
281
+ echo "⛔ HARD_STOP: hash 链断裂,禁止推进 phase"
282
+ echo " 制品文件被编辑后 hash 重算可能在单制品审查中漏过,"
283
+ echo " 尾扫是最后一道防线——必须逐条检查全部制品。"
284
+ echo ""
285
+ echo " 禁止:agent 自动补 _record write 修复 hash——"
286
+ echo " 必须 🔴 USER_GATE 让用户选择处理路径。"
287
+ exit 1
288
+ fi
393
289
  ```
394
290
 
395
- 每个制品已在审批时独立 commit,无需再次提交。
291
+ `$ALL_PASS` = false → ⛔ HARD_STOP,🔴 USER_GATE:
292
+ - (a) 回溯到对应制品重新审查(显示哪个制品 hash 不匹配,让用户决定回退到哪个制品重新生成)
293
+ - (b) 显示 git log 让用户排查(`git log --oneline openspec/changes/<name>/`)
294
+ - (c) 中止 plan 阶段退出 skill
396
295
 
397
- **通过 `alloy _guard` 校验并更新 phase:**
296
+ **[HARD_STOP]** agent 不得基于 "_guard 也会校验" 跳过尾扫——_guard 校验与尾扫是独立防线,尾扫逐条命名文件确保"全量 6/6",_guard 内部实现可能只校验 records 中存在的条目(文件存但 records 不存的 tainted artifact 会漏掉)。
398
297
 
298
+ **记录完成时间并推进 phase:**
399
299
  ```bash
300
+ COMPLETED_AT=$(date "+%Y-%m-%d %H:%M:%S")
301
+ alloy _state merge openspec/changes/<name> phase_timings "{\"plan\":{\"completed_at\":\"${COMPLETED_AT:-$(date '+%Y-%m-%d %H:%M:%S')}\"}}"
400
302
  alloy _guard openspec/changes/<name> planned --apply
303
+ git add openspec/changes/<name>/
304
+ git commit -m "chore(<name>): 记录 plan 阶段完成时间,推进到 planned"
401
305
  ```
402
306
 
403
- guard 校验 hash 一致性后自动推进 phase。如果 guard 返回非零,检查缺哪个制品或 hash 是否不匹配。
307
+ `_guard` 校验 hash 一致性后推进 phase。返回非零时检查缺哪个制品或 hash 不匹配。
404
308
 
405
- ```
406
- 制品文件禁止手动修改。如需变更,回到 brainstorming 在当前 change 内重新讨论。
309
+ **§5.2.3 路径 B 降级(HARD_STOP):** 如果 guard --apply 推进 phase 成功,但后续命令意外失败(不可恢复状态),**禁 agent 运行 `git reset --hard` / `git checkout .` 清场**。降级路径:
407
310
 
408
- 准备好后,运行 `/alloy:apply` 进入执行阶段。
311
+ ```bash
312
+ # 手动回退 phase(仅限用户确认后执行)
313
+ alloy _state set openspec/changes/<name> phase started
314
+ # 不要 reset 已 commit 的制品——hash 链保留,用户可重入 plan 阶段决定下一步
409
315
  ```
410
316
 
411
- ---
317
+ 违反字面 = 违反精神:哪怕"只是为了让流程干净",也禁 reset 清场——制品 hash 链是用户的工作记录。
318
+
319
+ **plans 完成后不要自动进入 apply** — 给用户空间审视完整规划。
412
320
 
413
- ## 闸门规则
321
+ ```
322
+ 制品文件禁止手动修改。如需变更,回到 brainstorming 在当前 change 内重新讨论。
323
+ 准备好后,运行 /alloy:apply 进入执行阶段。
324
+ ```
414
325
 
415
- - **git add 只用精确路径** — 永远不用 `-A`、`-a`、`.`。
416
- 反例:`git add .` 或 `git commit -am "fix"` 会把 `todo.py`、`tasks.json` 等意外文件一起提交
417
- - **始终分步,不提供一键生成** —— 每个制品必须单独审查确认后才能继续。跳过审查等于跳过需求验证,后期返工代价远大于审查时间
418
- - **每制品审批后必须 hash 锁定 + commit** —— 不可篡改追踪,确保审计链完整
419
- - **制品生成完成后必须通过 alloy _guard 校验** —— 脚本检查 started→planned 转换的合法性及 hash 一致性
420
- - **plans 完成后不要自动进入 apply** —— 给用户空间审视完整规划
421
- - **plan 阶段调整统一回 brainstorming** —— 需求/设计层面的任何变更从 draft 根重新审视,不做就地修补。typo/措辞修正除外。apply 阶段的 verify/retrospective 只修代码不改规格
422
- - **不输出全局制品进度** — [N/M] 是阶段内局部编号(M=5),不要输出"N/8 artifacts 完成"。全局进度由 `alloy status` 管理