@house365/comate 0.9.5 → 0.9.6
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/docs/COMATE_MANUAL.md +11 -9
- package/package.json +1 -1
- package/skills/comate/SKILL.md +151 -23
- package/skills/comate/reference/decision-points.md +2 -2
- package/skills/comate/scripts/comate-lib.sh +5 -1
- package/skills/comate/scripts/comate.sh +98 -16
- package/skills/comate/tests/comate.bats +96 -1
- package/skills/comate-build/SKILL.md +83 -6
- package/skills/comate-design/SKILL.md +75 -3
- package/skills/comate-fix/SKILL.md +9 -5
- package/skills/comate-gate/SKILL.md +7 -7
- package/skills/comate-open/SKILL.md +62 -9
- package/skills/comate-verify/SKILL.md +19 -10
package/docs/COMATE_MANUAL.md
CHANGED
|
@@ -368,7 +368,7 @@ bash "$COMATE" doctor
|
|
|
368
368
|
1. **进入验证与分类**:检查脏工作树,运行 guard,运行构建/测试命令。将失败分类为 SPEC、REGRESSION、COVERAGE、SECURITY、STYLE、OTHER。
|
|
369
369
|
2. **验证失败决策(决策点 4)**:验证失败时,暂停让用户决定:全部修复 / 逐项处理 / 接受偏差。包括 Spec 漂移处理(设计文档与 delta spec 冲突)。CRITICAL 级别的失败必须修复。仅在用户选择修复后才执行 `state transition <name> verify-fail` 并返回 build。
|
|
370
370
|
3. **验证通过**:全部通过或用户接受偏差后,写入 `verify_result: pass`,将验证报告路径写入 `verification_report`。
|
|
371
|
-
4. **分支收尾(决策点 5)**:调用 `superpowers:finishing-a-development-branch`。暂停让用户选择:本地合并 / 推送为 PR / 保留分支 /
|
|
371
|
+
4. **分支收尾(决策点 5)**:调用 `superpowers:finishing-a-development-branch`。暂停让用户选择:本地合并 / 推送为 PR / 保留分支 / 丢弃工作。前三项完成后写 `branch_status: handled`;丢弃写 `branch_status: discarded` 并停止,不得验证通过或归档。
|
|
372
372
|
5. **退出**:运行 `bash $COMATE guard <name> verify --apply`,通过后自动推进到 archive。
|
|
373
373
|
|
|
374
374
|
### 5.5 阶段 5:归档(/comate-archive)
|
|
@@ -432,7 +432,7 @@ bash "$COMATE" doctor
|
|
|
432
432
|
| 需新增 capability | 超出局部优化 |
|
|
433
433
|
| 需 delta spec | 影响已有规格 |
|
|
434
434
|
|
|
435
|
-
|
|
435
|
+
提问前写 `phase_step: fix.upgrade-awaiting`。用户确认后执行 `state transition <name> fix-upgrade`,原子清理 fix 默认值并进入 design。
|
|
436
436
|
|
|
437
437
|
---
|
|
438
438
|
|
|
@@ -445,14 +445,15 @@ bash "$COMATE" doctor
|
|
|
445
445
|
| 字段 | 含义 |
|
|
446
446
|
|-------|---------|
|
|
447
447
|
| `schema_version` | 状态文件格式版本(当前:1) |
|
|
448
|
-
| `workflow` | `full` / `fix` |
|
|
449
|
-
| `phase` | `open` / `design` / `build` / `verify` / `archive` |
|
|
448
|
+
| `workflow` | `full` / `fix` |
|
|
449
|
+
| `phase` | `open` / `design` / `build` / `verify` / `archive` |
|
|
450
|
+
| `phase_step` / `phase_step_data` | 当前阶段内的恢复标记和附加数据;阶段转换时自动清空 |
|
|
450
451
|
| `build_mode` | `subagent-driven-development` / `executing-plans` / `direct` |
|
|
451
452
|
| `isolation` | `branch` / `worktree`(必须在 build->verify 之前设置) |
|
|
452
453
|
| `verify_mode` | `light` / `full`(由规模评估写入) |
|
|
453
454
|
| `verify_result` | `pending` / `pass` / `fail` |
|
|
454
455
|
| `verification_report` | 验证报告路径,在 verify-pass 前必须指向真实文件 |
|
|
455
|
-
| `branch_status` | `pending` / `handled` |
|
|
456
|
+
| `branch_status` | `pending` / `handled` / `discarded` |
|
|
456
457
|
| `handoff_context` / `handoff_hash` | 设计交接包路径 + 源文件 sha256 |
|
|
457
458
|
| `impl_context` / `impl_hash` | 构建交接包路径 + plan+tasks sha256 |
|
|
458
459
|
| `direct_override` | 对于使用 `direct` 的 full 流程必须显式为 `true` |
|
|
@@ -486,9 +487,9 @@ bash "$COMATE" doctor
|
|
|
486
487
|
|
|
487
488
|
**4. 验证失败决策**(verify):验证失败时,暂停让用户决定:全部修复 / 逐项处理 / 接受偏差。包括 Spec 漂移处理(设计文档与 delta spec 冲突)。CRITICAL 级别的失败必须修复。仅在用户选择修复后才执行 `state transition <name> verify-fail` 并返回 build。
|
|
488
489
|
|
|
489
|
-
**5. 分支收尾选择**(verify/收尾开发分支):暂停让用户选择:本地合并 / 推送为 PR / 保留分支 /
|
|
490
|
+
**5. 分支收尾选择**(verify/收尾开发分支):暂停让用户选择:本地合并 / 推送为 PR / 保留分支 / 丢弃工作。前三项成功后写 `handled`;丢弃写 `discarded` 并终止当前流程。
|
|
490
491
|
|
|
491
|
-
**6. 预设升级确认**(fix -> full
|
|
492
|
+
**6. 预设升级确认**(fix -> full):当升级条件满足时,先写 `fix.upgrade-awaiting` 再暂停确认。确认后执行 `state transition <name> fix-upgrade`,由脚本清理 fix 默认构建选项并进入 design。
|
|
492
493
|
|
|
493
494
|
**7. 构建范围扩展**(build):如果实现过程揭示需要重新设计或拆分为新变更,暂停。判定标准:基于初始 tasks.md 任务数,新增任务超过总数一半(50% 阈值)视为超出范围。询问用户是否拆分。中等规模(接口变更、新组件):确认后加载 `superpowers:brainstorming` 更新设计。大规模(新能力):确认后使用 `/comate-open` 创建独立变更。
|
|
494
495
|
|
|
@@ -552,7 +553,8 @@ bash "$COMATE" doctor
|
|
|
552
553
|
| `state <name> init <full|fix>` | 初始化 `.comate.yaml` |
|
|
553
554
|
| `state <name> set <key> <value>` | 设置单个状态字段 |
|
|
554
555
|
| `state <name> get <key>` | 读取单个状态字段 |
|
|
555
|
-
| `state <name> transition <event>` | 执行状态转换 |
|
|
556
|
+
| `state <name> transition <event>` | 执行状态转换 |
|
|
557
|
+
| `dependency <name> archived` | 严格检查指定 change 已归档且状态为 `archived: true` |
|
|
556
558
|
| `state <name> check <phase> [--json]` | 检查阶段进入条件 |
|
|
557
559
|
| `state <name> recover <phase>` | 从文件状态推断并修复 `.comate.yaml` |
|
|
558
560
|
| `state <name> scale` | 评估变更规模并写入 `verify_mode` |
|
|
@@ -592,7 +594,7 @@ bash "$COMATE" doctor
|
|
|
592
594
|
|---------|-------------|
|
|
593
595
|
| `gate <prd> review` | 建/刷新 gate.yaml,钉当前 PRD sha256,回显评审报告路径。PRD 变了则状态重置为 `reviewing` |
|
|
594
596
|
| `gate <prd> set <field> <value>` | 写字段:`score` / `blocking_open` / `gate_status` 等 |
|
|
595
|
-
| `gate <prd> pass [--tbd]` |
|
|
597
|
+
| `gate <prd> pass [--tbd]` | 校验评分、拆分映射和报告。普通 pass 要求 `blocking_open=0`;`--tbd` 要求至少一个经用户接受的未解决阻断项 |
|
|
596
598
|
| `gate <prd> spawned <change>` | 记录据此 PRD 扇出的 change(逗号拼接) |
|
|
597
599
|
| `gate <prd> status [--json]` | 查状态;哈希漂移时自动判 `stale`(不改文件) |
|
|
598
600
|
| `gate <prd> check` | comate-open 建 change 前的前置守卫。PASS 要求 gate 存在、状态 ∈ {passed, passed-with-tbd}、哈希未漂移;否则退出码 1 阻塞 |
|
package/package.json
CHANGED
package/skills/comate/SKILL.md
CHANGED
|
@@ -16,24 +16,131 @@ agent 做决策只需读本节,其余参见末尾「参考附录」。决策
|
|
|
16
16
|
|
|
17
17
|
### 自动阶段探测
|
|
18
18
|
|
|
19
|
-
**Step 0:活跃 change 发现 +
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
19
|
+
**Step 0:活跃 change 发现 + 决策状态优先检查**
|
|
20
|
+
|
|
21
|
+
<CRITICAL>
|
|
22
|
+
**执行顺序不可颠倒**:先识别用户是否明确要求新建 change;否则读取状态检查明确的 `*-awaiting` 决策标记,再做普通意图过滤和 change 匹配。
|
|
23
|
+
若用户正在回答已持久化的决策问题(如"worktree + TDD"、"确认方案A"),直接路由到对应子 skill。
|
|
24
|
+
</CRITICAL>
|
|
25
|
+
|
|
26
|
+
1. **活跃 change 快速发现**:
|
|
27
|
+
|
|
28
|
+
运行 `openspec list --json` 获取所有活跃 change。
|
|
29
|
+
|
|
30
|
+
- **无活跃 change** → 跳到步骤 3(意图快速过滤 + 预设探测)
|
|
31
|
+
- **有活跃 change** → 继续步骤 2
|
|
32
|
+
|
|
33
|
+
2. **待决策状态检查**(防止决策答复被误判为新任务):
|
|
34
|
+
|
|
35
|
+
a. **确定目标 change**:
|
|
36
|
+
- 恰好 1 个活跃 change → 自动选中
|
|
37
|
+
- 多个活跃 change 且用户指定了 change 名称(`/comate <name>`)→ 选中该 change
|
|
38
|
+
- 多个活跃 change 且用户未指定 → **暂存待选列表,继续检查**(稍后在步骤 3.2 处理)
|
|
39
|
+
|
|
40
|
+
b. **读取状态(若已确定目标 change)**:
|
|
41
|
+
|
|
42
|
+
读取 `openspec/changes/<name>/.comate.yaml`,获取 `phase` 和 `phase_step`。
|
|
43
|
+
|
|
44
|
+
c. **检查是否在等待决策**:
|
|
45
|
+
|
|
46
|
+
只有 `phase_step` 是当前阶段的明确等待标记时,才说明子 skill 正在等待用户答复:
|
|
47
|
+
- `open.review-awaiting`
|
|
48
|
+
- `design.approval-awaiting`
|
|
49
|
+
- `build.options-awaiting` / `build.scope-awaiting` / `fix.upgrade-awaiting`
|
|
50
|
+
- `verify.failure-awaiting` / `verify.spec-drift-awaiting` / `verify.branch-awaiting`
|
|
51
|
+
|
|
52
|
+
兼容 `bd16c0f` 产生的活跃状态:仅在 phase 对应时,把 `open:4`、`design:1b`、`build:2` 分别视为上述等待标记;恢复后立即写入新格式。其它旧值只是普通进度。
|
|
53
|
+
|
|
54
|
+
普通进度(如 `design.brainstorm-complete`)、已确认状态和依赖阻塞状态都**不是**待决策,不得抢占用户的新请求。用户明确说“新建 change”时也优先按新建意图处理。
|
|
55
|
+
|
|
56
|
+
**立即路由到对应子 skill**(根据 `phase` 字段):
|
|
57
|
+
- `phase: open` → 调用 `/comate-open`
|
|
58
|
+
- `phase: design` → 调用 `/comate-design`
|
|
59
|
+
- `phase: build` → 调用 `/comate-build`
|
|
60
|
+
- `phase: verify` → 调用 `/comate-verify`
|
|
61
|
+
- `phase: archive` → 调用 `/comate-archive`
|
|
62
|
+
|
|
63
|
+
子 skill 的**幂等性检查**会:
|
|
64
|
+
1. 读取 `phase_step` 的值
|
|
65
|
+
2. 验证该步骤是否与当前 `phase` 匹配
|
|
66
|
+
3. 恢复到正确的步骤(跳过已完成的步骤,直接进入下一步)
|
|
67
|
+
|
|
68
|
+
**结束 Step 0,不执行后续逻辑**。
|
|
69
|
+
|
|
70
|
+
d. **若没有匹配当前阶段的等待标记**:
|
|
71
|
+
|
|
72
|
+
说明没有未完成的决策点,继续步骤 3(意图过滤)。
|
|
73
|
+
|
|
74
|
+
3. **意图快速过滤 + 幂等性匹配**:
|
|
75
|
+
|
|
76
|
+
3.1. **意图快速过滤**(仅当步骤 2 未命中时执行):
|
|
77
|
+
|
|
78
|
+
先检查用户输入是否**明确表达了希望进入某个特定阶段**。如果用户没有明确指示,则无条件自动探测当前阶段,不询问不推测。
|
|
79
|
+
|
|
80
|
+
**明确意图的识别规则**:用户消息中包含以下**动作关键词 + 阶段名**的直接组合之一时,才算明确意图:
|
|
81
|
+
|
|
82
|
+
| 阶段 | 明确意图的关键词组合(任一命中即算) |
|
|
83
|
+
|------|-------------------------------------|
|
|
84
|
+
| open | "开题"/"创建 change"/"新建 change"/"起草 proposal" |
|
|
85
|
+
| design | "设计"/"写设计文档"/"brainstorming"/"开始设计" |
|
|
86
|
+
| build | "实施"/"开始构建"/"执行计划"/"写代码"/"开始 build" |
|
|
87
|
+
| verify | "验证"/"检查实现"/"运行测试"/"开始 verify" |
|
|
88
|
+
| archive | "归档"/"完成收尾"/"合并 delta spec"/"开始 archive" |
|
|
89
|
+
|
|
90
|
+
**不算明确意图的情况**(这些都应自动探测,不询问):
|
|
91
|
+
- 仅提及问题、需求、想法,无阶段动作词:"修复这个 bug" / "优化性能" / "加个功能"
|
|
92
|
+
- 仅描述当前状态:"设计做完了" / "代码写好了" / "测试通过了"
|
|
93
|
+
- 询问式:"现在该做什么" / "下一步是什么" / "继续"
|
|
94
|
+
- 澄清式:"刚才的设计有问题" / "build 阶段遇到错误"
|
|
95
|
+
- **决策答复**:"worktree + TDD" / "选择方案 A" / "确认" / "继续构建"(这些应在步骤 2 被拦截)
|
|
96
|
+
|
|
97
|
+
**过滤结果**:
|
|
98
|
+
- **明确意图命中** → 直接跳到对应阶段的 skill(不运行后续步骤)
|
|
99
|
+
- **无明确意图** → 继续步骤 3.2
|
|
100
|
+
|
|
101
|
+
3.2. **活跃 change 匹配**(防止重复创建 change):
|
|
102
|
+
|
|
103
|
+
**前置条件**:有活跃 change 且用户输入无明确意图。
|
|
104
|
+
|
|
105
|
+
**处理逻辑**:
|
|
106
|
+
|
|
107
|
+
a. **用户输入仅为 `/comate` 无任何描述**:
|
|
108
|
+
- 恰好 1 个活跃 change → 已在步骤 2 选中,进入 Step 1
|
|
109
|
+
- 多个活跃 change → 列出所有 change 供用户选择,选中后进入 Step 1
|
|
110
|
+
|
|
111
|
+
b. **用户输入包含任务描述但未指定 change 名称**(`/comate <描述>`):
|
|
112
|
+
- **关键幂等检查**(防止重复创建 change):
|
|
113
|
+
1. 遍历所有活跃 change
|
|
114
|
+
2. 对每个 change,读取 `proposal.md` 和 `specs/*/spec.md`
|
|
115
|
+
3. 检查用户描述是否与该 change 的需求高度匹配(关键词重叠、问题域相同、目标一致)
|
|
116
|
+
4. **若找到匹配的 change**:
|
|
117
|
+
- 自动选中该 change
|
|
118
|
+
- 说明「检测到您的描述与活跃 change <name> 的需求匹配,将继续该 change」
|
|
119
|
+
- 进入 Step 1(读取该 change 的状态)
|
|
120
|
+
5. **若所有 change 都不匹配**:
|
|
121
|
+
- **AskUserQuestion 询问**:「检测到 {N} 个活跃 change:{列表及简要描述}。您的任务是:继续某个已有 change,还是新建 change?」
|
|
122
|
+
- 选项 1:「继续已有 change」→ 让用户选择具体哪个 change,进入 Step 1
|
|
123
|
+
- 选项 2:「新建 change」→ 进入步骤 4(预设探测)
|
|
124
|
+
|
|
125
|
+
4. **预设探测**(决定新 change 的入口):
|
|
126
|
+
|
|
127
|
+
当确定需要新建 change 时(无活跃 change,或用户选择新建),按以下优先级探测:
|
|
128
|
+
|
|
129
|
+
a. **fix 预设**:
|
|
130
|
+
- 用户明确描述 bug 修复或文案/配置/文档/prompt 小调整
|
|
131
|
+
- 且满足 fix 条件(见 `/comate-fix` skill)
|
|
132
|
+
- → 直接调用 `/comate-fix`,不进入普通 open 分支
|
|
133
|
+
|
|
134
|
+
b. **gate 预设**(原始 PRD 入口):
|
|
135
|
+
- 用户输入指向一份原始 PRD(给了 PRD 路径/编号,或明确说「这是 PRD / 从这份需求文档开始」)
|
|
136
|
+
- 典型路径:`docs/knowledge-base/**/PRD-*.md`
|
|
137
|
+
- **且无对应活跃 change**
|
|
138
|
+
- → 直接调用 `/comate-gate`(阶段 0:先过门禁,再拆分建 change)
|
|
139
|
+
- **不要直接调 `/comate-open`**——PRD 必须先过质量门禁
|
|
140
|
+
|
|
141
|
+
c. **普通 open**(默认):
|
|
142
|
+
- 无预设命中
|
|
143
|
+
- → 调用 `/comate-open`
|
|
37
144
|
|
|
38
145
|
<IMPORTANT>
|
|
39
146
|
用户选择「新建 change」时,**必须调用 `/comate-open`**,不要直接调 `/opsx:new`。
|
|
@@ -41,10 +148,26 @@ agent 做决策只需读本节,其余参见末尾「参考附录」。决策
|
|
|
41
148
|
直接调 `/opsx:new` 会导致 `.comate.yaml` 缺失,破坏后续阶段探测。
|
|
42
149
|
</IMPORTANT>
|
|
43
150
|
|
|
44
|
-
**Step 1:读取 `.comate.yaml`
|
|
151
|
+
**Step 1:读取 `.comate.yaml` 状态元数据**(仅在 Step 0 未直接路由时执行)
|
|
45
152
|
|
|
46
153
|
优先读 `openspec/changes/<name>/.comate.yaml`。不可用时回落到 `openspec status --change "<name>" --json`、`tasks.md`、`docs/superpowers/` 文件检查。
|
|
47
154
|
|
|
155
|
+
**关键字段**:
|
|
156
|
+
- `phase`:当前阶段(`open` / `design` / `build` / `verify` / `archive`)
|
|
157
|
+
- `phase_step`:当前阶段内的步骤标记(如 `design.approval-awaiting`、`build.options-confirmed`)
|
|
158
|
+
- `workflow`:流程类型(`full` / `fix`)
|
|
159
|
+
- `build_mode`、`isolation`、`tdd_mode`:build 阶段的决策字段
|
|
160
|
+
- `verify_result`:验证结果(`pending` / `pass` / `fail`)
|
|
161
|
+
|
|
162
|
+
**phase_step 语义说明**:
|
|
163
|
+
|
|
164
|
+
`phase_step` 记录**当前阶段**内的步骤,用于断点恢复和幂等性检查:
|
|
165
|
+
- 非空值表示"已完成到该步骤",恢复时从**下一步**开始
|
|
166
|
+
- `*-awaiting` 表示正在等待用户答复,只有这类值触发决策优先路由
|
|
167
|
+
- `*-confirmed` 表示用户已确认的决策点
|
|
168
|
+
- `build.blocked-by-<dependency>` 表示被依赖阻塞,但不是等待当前用户决策
|
|
169
|
+
- 空值或 `null` 表示该阶段尚未开始或已完成所有步骤
|
|
170
|
+
|
|
48
171
|
**断点恢复规则**:
|
|
49
172
|
- 每次上下文恢复都重跑 Step 0、Step 1;不要信任对话历史做阶段探测。
|
|
50
173
|
- 有活跃 change 且工作树有未提交改动时,按 `comate/reference/dirty-worktree.md` 协议处理。
|
|
@@ -53,6 +176,10 @@ agent 做决策只需读本节,其余参见末尾「参考附录」。决策
|
|
|
53
176
|
- 若 `phase: open` 但 proposal/design/tasks 已完成,先 `bash "$COMATE" guard <name> open --apply` 修复状态,再继续探测。
|
|
54
177
|
- 若 `phase: archive`,只调用 `/comate-archive`;归档成功后 change 移入 archive 目录,不要再对旧活跃目录跑 guard。
|
|
55
178
|
|
|
179
|
+
**phase_step 生命周期**:
|
|
180
|
+
|
|
181
|
+
`phase_step` 严格属于当前阶段。所有 `state transition` 在切换 `phase` 时原子清空 `phase_step` 和 `phase_step_data`。禁止跨阶段保留或比较步骤编号;跨阶段事实必须记录在专用字段或落盘产物中。
|
|
182
|
+
|
|
56
183
|
**Step 2:阶段判定**(按顺序检查,首个命中者生效)
|
|
57
184
|
|
|
58
185
|
1. `archived: true` 或 change 已移入 archive → 流程完成
|
|
@@ -148,9 +275,10 @@ bash "$COMATE" state <name> validate
|
|
|
148
275
|
bash "$COMATE" guard <name> <phase> [--apply] [--json]
|
|
149
276
|
bash "$COMATE" handoff <name> <design|build> --write [--full]
|
|
150
277
|
bash "$COMATE" sources <name> track <file...> [--note <text>]
|
|
151
|
-
bash "$COMATE" sources <name> check | list
|
|
152
|
-
bash "$COMATE" sources find <file>
|
|
153
|
-
bash "$COMATE"
|
|
278
|
+
bash "$COMATE" sources <name> check | list
|
|
279
|
+
bash "$COMATE" sources find <file>
|
|
280
|
+
bash "$COMATE" dependency <name> archived
|
|
281
|
+
bash "$COMATE" archive <name> [--dry-run]
|
|
154
282
|
bash "$COMATE" status
|
|
155
283
|
bash "$COMATE" doctor
|
|
156
284
|
```
|
|
@@ -172,7 +300,7 @@ bash "$COMATE" doctor
|
|
|
172
300
|
| `verify_mode` | `light` / `full`(由 scale 评估写入) |
|
|
173
301
|
| `verify_result` | `pending` / `pass` / `fail` |
|
|
174
302
|
| `verification_report` | 验证报告路径,verify-pass 前必须指向真实文件 |
|
|
175
|
-
| `branch_status` | `pending` / `handled` |
|
|
303
|
+
| `branch_status` | `pending` / `handled` / `discarded` |
|
|
176
304
|
| `handoff_context` / `handoff_hash` | design 交接包路径 + 源文件 sha256 |
|
|
177
305
|
| `impl_context` / `impl_hash` | build 交接包路径 + plan+tasks 的 sha256(防漂移) |
|
|
178
306
|
| `direct_override` | full 流程用 `direct` 需显式 `true` |
|
|
@@ -61,11 +61,11 @@
|
|
|
61
61
|
引用:`comate-verify` Step 1b、Step 2b 的 Spec 漂移处理。
|
|
62
62
|
|
|
63
63
|
5. **分支收尾方式选择**(verify / finishing-a-development-branch)
|
|
64
|
-
暂停请用户选择:本地合并 / 推送建 PR / 保持分支 /
|
|
64
|
+
暂停请用户选择:本地合并 / 推送建 PR / 保持分支 / 丢弃工作。前三项操作成功后写 `branch_status: handled`;丢弃工作写 `branch_status: discarded` 并停止流程,禁止执行 verify guard 或归档。
|
|
65
65
|
引用:`comate-verify` Step 3。
|
|
66
66
|
|
|
67
67
|
6. **预设升级确认**(fix → full)
|
|
68
|
-
命中升级条件(见 `comate-fix` SKILL 的「升级条件」,bug
|
|
68
|
+
命中升级条件(见 `comate-fix` SKILL 的「升级条件」,bug 模式与调整模式各有阈值)时,先写 `phase_step: fix.upgrade-awaiting`,再暂停请用户确认。用户确认后执行原子转换 `state transition <name> fix-upgrade`,由脚本清除 fix 默认构建选项并进入 design。
|
|
69
69
|
引用:`comate-fix`「升级条件」。
|
|
70
70
|
|
|
71
71
|
7. **构建期范围扩张**(build)
|
|
@@ -50,6 +50,8 @@ FIELD_ORDER=(
|
|
|
50
50
|
schema_version
|
|
51
51
|
workflow
|
|
52
52
|
phase
|
|
53
|
+
phase_step
|
|
54
|
+
phase_step_data
|
|
53
55
|
build_mode
|
|
54
56
|
tdd_mode
|
|
55
57
|
isolation
|
|
@@ -88,7 +90,7 @@ declare -A ENUMS=(
|
|
|
88
90
|
[isolation]="branch worktree"
|
|
89
91
|
[verify_mode]="light full"
|
|
90
92
|
[verify_result]="pending pass fail"
|
|
91
|
-
[branch_status]="pending handled"
|
|
93
|
+
[branch_status]="pending handled discarded"
|
|
92
94
|
[direct_override]="true false"
|
|
93
95
|
[archived]="true false"
|
|
94
96
|
[source_kind]="conversation file"
|
|
@@ -111,6 +113,8 @@ declare -A FREEFORM_KEYS=(
|
|
|
111
113
|
[verify_command]=1
|
|
112
114
|
[created_at]=1
|
|
113
115
|
[verified_at]=1
|
|
116
|
+
[phase_step]=1
|
|
117
|
+
[phase_step_data]=1
|
|
114
118
|
)
|
|
115
119
|
|
|
116
120
|
# --- Path location ---
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
# sources find <file> — reverse lookup: changes citing a file
|
|
20
20
|
# gate <prd> review — create/refresh gate.yaml next to the PRD, pin hash
|
|
21
21
|
# gate <prd> set <field> <value> — write score | blocking_open | gate_status | …
|
|
22
|
-
# gate <prd> pass [--tbd] —
|
|
22
|
+
# gate <prd> pass [--tbd] — pass clean gate or explicitly accepted TBD blockers
|
|
23
23
|
# gate <prd> spawned <change> — record a change fanned out from this PRD
|
|
24
24
|
# gate <prd> status [--json] — print gate status (computes stale on hash drift)
|
|
25
25
|
# gate <prd> check — precondition guard before spawning a change
|
|
@@ -60,7 +60,7 @@ Usage: comate.sh <command> ...
|
|
|
60
60
|
state <name> init <workflow> full | fix
|
|
61
61
|
state <name> get <field>
|
|
62
62
|
state <name> set <field> <value>
|
|
63
|
-
state <name> transition <event> open-complete|design-complete|build-complete|verify-pass|verify-fail|archived
|
|
63
|
+
state <name> transition <event> open-complete|design-complete|build-complete|verify-pass|verify-fail|fix-upgrade|archived
|
|
64
64
|
state <name> check <phase> [--json]
|
|
65
65
|
state <name> recover <phase>
|
|
66
66
|
state <name> scale
|
|
@@ -72,9 +72,10 @@ Usage: comate.sh <command> ...
|
|
|
72
72
|
sources <name> check
|
|
73
73
|
sources <name> list
|
|
74
74
|
sources find <file>
|
|
75
|
+
dependency <name> archived verify an exact archived change exists
|
|
75
76
|
gate <prd> review create/refresh gate.yaml next to PRD, pin hash
|
|
76
77
|
gate <prd> set <field> <value> score | blocking_open | gate_status | …
|
|
77
|
-
gate <prd> pass [--tbd]
|
|
78
|
+
gate <prd> pass [--tbd] pass: zero blockers; --tbd: accepted blockers
|
|
78
79
|
gate <prd> spawned <change> record a change fanned out from this PRD
|
|
79
80
|
gate <prd> status [--json]
|
|
80
81
|
gate <prd> check precondition guard before spawning a change
|
|
@@ -138,6 +139,8 @@ state_init() {
|
|
|
138
139
|
schema_version: $COMATE_SCHEMA_VERSION
|
|
139
140
|
workflow: $workflow
|
|
140
141
|
phase: open
|
|
142
|
+
phase_step: null
|
|
143
|
+
phase_step_data: null
|
|
141
144
|
build_mode: $build_mode
|
|
142
145
|
tdd_mode: $tdd_mode
|
|
143
146
|
isolation: $isolation
|
|
@@ -237,7 +240,7 @@ state_transition() {
|
|
|
237
240
|
validate_change_name "$name"
|
|
238
241
|
validate_enum_event() {
|
|
239
242
|
case "$1" in
|
|
240
|
-
open-complete|design-complete|build-complete|verify-pass|verify-fail|archived) return 0 ;;
|
|
243
|
+
open-complete|design-complete|build-complete|verify-pass|verify-fail|fix-upgrade|archived) return 0 ;;
|
|
241
244
|
*) die "$COMATE_USAGE" "ERROR: unknown event '$1'" ;;
|
|
242
245
|
esac
|
|
243
246
|
}
|
|
@@ -246,6 +249,13 @@ state_transition() {
|
|
|
246
249
|
local yaml; yaml=$(require_yaml "$name")
|
|
247
250
|
validate_flat_yaml "$yaml"
|
|
248
251
|
|
|
252
|
+
# phase_step is local to the current phase. Carrying it into the next phase
|
|
253
|
+
# makes identical step numbers ambiguous and can skip mandatory work.
|
|
254
|
+
_clear_phase_progress() {
|
|
255
|
+
yaml_set "$yaml" phase_step null
|
|
256
|
+
yaml_set "$yaml" phase_step_data null
|
|
257
|
+
}
|
|
258
|
+
|
|
249
259
|
case "$event" in
|
|
250
260
|
open-complete)
|
|
251
261
|
_require_phase "$yaml" open
|
|
@@ -255,10 +265,12 @@ state_transition() {
|
|
|
255
265
|
else
|
|
256
266
|
yaml_set "$yaml" phase build
|
|
257
267
|
fi
|
|
268
|
+
_clear_phase_progress
|
|
258
269
|
;;
|
|
259
270
|
design-complete)
|
|
260
271
|
_require_phase "$yaml" design
|
|
261
272
|
yaml_set "$yaml" phase build
|
|
273
|
+
_clear_phase_progress
|
|
262
274
|
;;
|
|
263
275
|
build-complete)
|
|
264
276
|
_require_phase "$yaml" build
|
|
@@ -267,6 +279,7 @@ state_transition() {
|
|
|
267
279
|
yaml_set "$yaml" verify_result pending
|
|
268
280
|
yaml_set "$yaml" verification_report null
|
|
269
281
|
yaml_set "$yaml" branch_status pending
|
|
282
|
+
_clear_phase_progress
|
|
270
283
|
;;
|
|
271
284
|
verify-pass)
|
|
272
285
|
_require_phase "$yaml" verify
|
|
@@ -274,12 +287,36 @@ state_transition() {
|
|
|
274
287
|
yaml_set "$yaml" verify_result pass
|
|
275
288
|
yaml_set "$yaml" phase archive
|
|
276
289
|
yaml_set "$yaml" verified_at "$(today)"
|
|
290
|
+
_clear_phase_progress
|
|
277
291
|
;;
|
|
278
292
|
verify-fail)
|
|
279
293
|
_require_phase "$yaml" verify
|
|
280
|
-
|
|
294
|
+
# The failure is captured in the report; once routed back to build the
|
|
295
|
+
# active verification state must be pending or the orchestrator loops.
|
|
296
|
+
yaml_set "$yaml" verify_result pending
|
|
281
297
|
yaml_set "$yaml" phase build
|
|
298
|
+
yaml_set "$yaml" verification_report null
|
|
299
|
+
yaml_set "$yaml" branch_status pending
|
|
300
|
+
_clear_phase_progress
|
|
301
|
+
;;
|
|
302
|
+
fix-upgrade)
|
|
303
|
+
[ "$(yaml_get "$yaml" workflow)" = "fix" ] || \
|
|
304
|
+
die "$COMATE_BLOCK" "ERROR: fix-upgrade requires workflow=fix"
|
|
305
|
+
case "$(yaml_get "$yaml" phase)" in
|
|
306
|
+
open|build) ;;
|
|
307
|
+
*) die "$COMATE_BLOCK" "ERROR: fix-upgrade is only valid from open or build" ;;
|
|
308
|
+
esac
|
|
309
|
+
yaml_set "$yaml" workflow full
|
|
310
|
+
yaml_set "$yaml" phase design
|
|
311
|
+
yaml_set "$yaml" build_mode null
|
|
312
|
+
yaml_set "$yaml" tdd_mode null
|
|
313
|
+
yaml_set "$yaml" isolation null
|
|
314
|
+
yaml_set "$yaml" verify_mode null
|
|
315
|
+
yaml_set "$yaml" direct_override false
|
|
316
|
+
yaml_set "$yaml" verify_result pending
|
|
317
|
+
yaml_set "$yaml" verification_report null
|
|
282
318
|
yaml_set "$yaml" branch_status pending
|
|
319
|
+
_clear_phase_progress
|
|
283
320
|
;;
|
|
284
321
|
archived)
|
|
285
322
|
_require_phase "$yaml" archive
|
|
@@ -498,15 +535,19 @@ state_recover() {
|
|
|
498
535
|
yaml="$dir/.comate.yaml"
|
|
499
536
|
[ -f "$yaml" ] || die "$COMATE_CORRUPT" "ERROR: .comate.yaml not found at $yaml"
|
|
500
537
|
|
|
501
|
-
local phase workflow
|
|
538
|
+
local phase workflow phase_step phase_step_data
|
|
502
539
|
phase=$(yaml_get "$yaml" phase)
|
|
503
540
|
workflow=$(yaml_get "$yaml" workflow)
|
|
541
|
+
phase_step=$(yaml_get "$yaml" phase_step)
|
|
542
|
+
phase_step_data=$(yaml_get "$yaml" phase_step_data)
|
|
504
543
|
# If a phase arg was passed, honor it for reporting; else use stored phase.
|
|
505
544
|
[ -n "$phase_arg" ] && phase="$phase_arg"
|
|
506
545
|
|
|
507
546
|
echo "=== Recovery Context: $name ==="
|
|
508
547
|
echo "Phase: $phase"
|
|
509
548
|
echo "Workflow: $workflow"
|
|
549
|
+
echo "Phase step: ${phase_step:-null}"
|
|
550
|
+
echo "Phase step data: ${phase_step_data:-null}"
|
|
510
551
|
echo ""
|
|
511
552
|
|
|
512
553
|
local design_doc plan verify_result verify_mode verification_report
|
|
@@ -578,7 +619,11 @@ state_recover() {
|
|
|
578
619
|
echo "Tasks: tasks.md MISSING"
|
|
579
620
|
fi
|
|
580
621
|
echo ""
|
|
581
|
-
if [ "$
|
|
622
|
+
if [[ "$phase_step" == build.blocked-by-* ]]; then
|
|
623
|
+
local dep="$phase_step_data"
|
|
624
|
+
if [ -z "$dep" ] || [ "$dep" = "null" ]; then dep="${phase_step#build.blocked-by-}"; fi
|
|
625
|
+
echo "Recovery action: Blocked by $dep. Run: comate.sh dependency $dep archived"
|
|
626
|
+
elif [ "$isolation" = "null" ] || [ -z "$isolation" ]; then
|
|
582
627
|
echo "Recovery action: Isolation not selected. AskUserQuestion for branch/worktree."
|
|
583
628
|
elif [ "$build_mode" = "null" ] || [ -z "$build_mode" ]; then
|
|
584
629
|
echo "Recovery action: Build mode not selected. AskUserQuestion for execution method."
|
|
@@ -600,7 +645,9 @@ state_recover() {
|
|
|
600
645
|
_field_status "branch_status" "$branch_status"
|
|
601
646
|
_field_status "impl_hash" "$impl_hash"
|
|
602
647
|
echo ""
|
|
603
|
-
if [ "$
|
|
648
|
+
if [ "$branch_status" = "discarded" ]; then
|
|
649
|
+
echo "Recovery action: Work was discarded. Run verify-fail to return to build before reimplementing, or explicitly abandon the change."
|
|
650
|
+
elif [ "$verify_result" = "pass" ] && [ "$branch_status" = "handled" ]; then
|
|
604
651
|
echo "Recovery action: Verification complete. Run guard to transition to archive."
|
|
605
652
|
elif [ "$verify_result" = "pass" ]; then
|
|
606
653
|
echo "Recovery action: Verified but branch not handled. Complete branch handling, set branch_status=handled."
|
|
@@ -1345,6 +1392,23 @@ sources_find() {
|
|
|
1345
1392
|
return 0
|
|
1346
1393
|
}
|
|
1347
1394
|
|
|
1395
|
+
# dependency <name> archived — prove completion from archived state, rather
|
|
1396
|
+
# than inferring it from absence in `openspec list`.
|
|
1397
|
+
dependency_archived() {
|
|
1398
|
+
local name="$1"
|
|
1399
|
+
validate_change_name "$name"
|
|
1400
|
+
[ ! -d "openspec/changes/$name" ] || \
|
|
1401
|
+
die "$COMATE_BLOCK" "BLOCK: dependency '$name' is still active"
|
|
1402
|
+
local found="" yaml
|
|
1403
|
+
while IFS= read -r yaml; do
|
|
1404
|
+
[ "$(yaml_get "$yaml" archived)" = "true" ] && found="$yaml"
|
|
1405
|
+
done < <(find openspec/changes/archive -mindepth 2 -maxdepth 2 \
|
|
1406
|
+
-path "*/????-??-??-${name}/.comate.yaml" -type f 2>/dev/null | sort)
|
|
1407
|
+
[ -n "$found" ] || \
|
|
1408
|
+
die "$COMATE_BLOCK" "BLOCK: no archived=true record found for dependency '$name'"
|
|
1409
|
+
log_pass "[DEPENDENCY] archived: $name ($found)"
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1348
1412
|
# =====================================================================
|
|
1349
1413
|
# gate — phase 0: PRD quality gate + split precondition
|
|
1350
1414
|
# =====================================================================
|
|
@@ -1416,10 +1480,8 @@ gate_set() {
|
|
|
1416
1480
|
log_pass "[GATE] set $field=$value"
|
|
1417
1481
|
}
|
|
1418
1482
|
|
|
1419
|
-
# gate <prd> pass [--tbd] — flip to passed/passed-with-tbd.
|
|
1420
|
-
#
|
|
1421
|
-
# edit invalidates the pass. --tbd records that the user authorised proceeding
|
|
1422
|
-
# with unresolved TBDs (spawned changes must carry ⚠ markers).
|
|
1483
|
+
# gate <prd> pass [--tbd] — flip to passed/passed-with-tbd. Normal pass requires
|
|
1484
|
+
# zero blockers; --tbd requires at least one explicitly accepted blocker.
|
|
1423
1485
|
gate_pass() {
|
|
1424
1486
|
local prd; prd=$(require_prd "$1")
|
|
1425
1487
|
local tbd=0
|
|
@@ -1427,9 +1489,22 @@ gate_pass() {
|
|
|
1427
1489
|
local gate; gate=$(gate_path_for "$prd")
|
|
1428
1490
|
[ -f "$gate" ] || die "$COMATE_CORRUPT" "ERROR: gate not found (run 'gate review' first): $gate"
|
|
1429
1491
|
|
|
1430
|
-
local
|
|
1431
|
-
|
|
1432
|
-
|
|
1492
|
+
local score blocking changes_map
|
|
1493
|
+
score=$(yaml_get "$gate" score)
|
|
1494
|
+
blocking=$(yaml_get "$gate" blocking_open)
|
|
1495
|
+
changes_map=$(yaml_get "$gate" changes_map)
|
|
1496
|
+
[[ "$score" =~ ^[0-9]+$ ]] && [ "$score" -ge 0 ] && [ "$score" -le 100 ] || \
|
|
1497
|
+
die "$COMATE_BLOCK" "BLOCK: score must be an integer from 0 to 100 (got '$score')"
|
|
1498
|
+
[[ "$blocking" =~ ^[0-9]+$ ]] || \
|
|
1499
|
+
die "$COMATE_BLOCK" "BLOCK: blocking_open must be a non-negative integer (got '$blocking')"
|
|
1500
|
+
if [ "$tbd" -eq 1 ]; then
|
|
1501
|
+
[ "$blocking" -gt 0 ] || \
|
|
1502
|
+
die "$COMATE_BLOCK" "BLOCK: --tbd requires at least one recorded unresolved blocker"
|
|
1503
|
+
elif [ "$blocking" -ne 0 ]; then
|
|
1504
|
+
die "$COMATE_BLOCK" "BLOCK: blocking_open='$blocking' — resolve all blocking issues or use --tbd after explicit user authorization"
|
|
1505
|
+
fi
|
|
1506
|
+
if [ -z "$changes_map" ] || [ "$changes_map" = "null" ]; then
|
|
1507
|
+
die "$COMATE_BLOCK" "BLOCK: changes_map is required before passing the gate"
|
|
1433
1508
|
fi
|
|
1434
1509
|
local report; report=$(yaml_get "$gate" review_report)
|
|
1435
1510
|
if [ -z "$report" ] || [ "$report" = "null" ] || ! file_nonempty "$report"; then
|
|
@@ -1703,7 +1778,7 @@ status() {
|
|
|
1703
1778
|
echo "No active changes."
|
|
1704
1779
|
return 0
|
|
1705
1780
|
fi
|
|
1706
|
-
local any=0 d name yaml phase workflow build_mode vr dd plan total done tasks_file
|
|
1781
|
+
local any=0 d name yaml phase phase_step workflow build_mode vr dd plan total done tasks_file
|
|
1707
1782
|
for d in "$changes_dir"/*/; do
|
|
1708
1783
|
[ -d "$d" ] || continue
|
|
1709
1784
|
name=$(basename "$d")
|
|
@@ -1713,6 +1788,7 @@ status() {
|
|
|
1713
1788
|
[ "$(yaml_get "$yaml" archived)" = "true" ] && continue
|
|
1714
1789
|
any=1
|
|
1715
1790
|
phase=$(yaml_get "$yaml" phase)
|
|
1791
|
+
phase_step=$(yaml_get "$yaml" phase_step)
|
|
1716
1792
|
workflow=$(yaml_get "$yaml" workflow)
|
|
1717
1793
|
build_mode=$(yaml_get "$yaml" build_mode)
|
|
1718
1794
|
vr=$(yaml_get "$yaml" verify_result)
|
|
@@ -1726,6 +1802,7 @@ status() {
|
|
|
1726
1802
|
fi
|
|
1727
1803
|
echo "• $name [phase: $phase, $done/$total tasks]"
|
|
1728
1804
|
echo " workflow: $workflow | build_mode: $build_mode"
|
|
1805
|
+
[ -n "$phase_step" ] && [ "$phase_step" != "null" ] && echo " step: $phase_step"
|
|
1729
1806
|
[ -n "$dd" ] && [ "$dd" != "null" ] && echo " design: $dd"
|
|
1730
1807
|
[ -n "$plan" ] && [ "$plan" != "null" ] && echo " plan: $plan"
|
|
1731
1808
|
[ "$phase" = "verify" ] && echo " verify_result: $vr"
|
|
@@ -1870,6 +1947,11 @@ case "$CMD" in
|
|
|
1870
1947
|
esac
|
|
1871
1948
|
fi
|
|
1872
1949
|
;;
|
|
1950
|
+
dependency)
|
|
1951
|
+
NAME="${1:-}"; SUB="${2:-}"
|
|
1952
|
+
[ -n "$NAME" ] && [ "$SUB" = "archived" ] || { usage_top; exit "$COMATE_USAGE"; }
|
|
1953
|
+
dependency_archived "$NAME"
|
|
1954
|
+
;;
|
|
1873
1955
|
gate)
|
|
1874
1956
|
PRD="${1:-}"; SUB="${2:-}"
|
|
1875
1957
|
[ -n "$PRD" ] && [ -n "$SUB" ] || { usage_top; exit "$COMATE_USAGE"; }
|
|
@@ -144,8 +144,10 @@ seed_open() {
|
|
|
144
144
|
|
|
145
145
|
@test "open-complete routes full to design" {
|
|
146
146
|
seed_open
|
|
147
|
+
comate state demo set phase_step open.review-confirmed >/dev/null
|
|
147
148
|
comate state demo transition open-complete
|
|
148
149
|
[ "$(comate state demo get phase)" = "design" ]
|
|
150
|
+
[ "$(comate state demo get phase_step)" = "null" ]
|
|
149
151
|
}
|
|
150
152
|
|
|
151
153
|
@test "open-complete routes fix to build" {
|
|
@@ -201,6 +203,56 @@ seed_open() {
|
|
|
201
203
|
[ "$status" -eq 1 ]
|
|
202
204
|
}
|
|
203
205
|
|
|
206
|
+
@test "fix-upgrade resets preset decisions and enters design" {
|
|
207
|
+
comate state demo init fix
|
|
208
|
+
comate state demo transition open-complete
|
|
209
|
+
comate state demo set phase_step build.options-confirmed >/dev/null
|
|
210
|
+
comate state demo transition fix-upgrade
|
|
211
|
+
[ "$(comate state demo get workflow)" = "full" ]
|
|
212
|
+
[ "$(comate state demo get phase)" = "design" ]
|
|
213
|
+
[ "$(comate state demo get build_mode)" = "null" ]
|
|
214
|
+
[ "$(comate state demo get tdd_mode)" = "null" ]
|
|
215
|
+
[ "$(comate state demo get isolation)" = "null" ]
|
|
216
|
+
[ "$(comate state demo get phase_step)" = "null" ]
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
@test "discarded branch cannot pass verification" {
|
|
220
|
+
comate state demo init full
|
|
221
|
+
comate state demo set phase verify >/dev/null
|
|
222
|
+
printf '# pass\n' > report.md
|
|
223
|
+
comate state demo set verification_report report.md >/dev/null
|
|
224
|
+
comate state demo set branch_status discarded >/dev/null
|
|
225
|
+
run comate state demo transition verify-pass
|
|
226
|
+
[ "$status" -eq 1 ]
|
|
227
|
+
[ "$(comate state demo get phase)" = "verify" ]
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
@test "verify-fail returns to build without a failure routing loop" {
|
|
231
|
+
comate state demo init full
|
|
232
|
+
comate state demo set phase verify >/dev/null
|
|
233
|
+
comate state demo set verify_result fail >/dev/null
|
|
234
|
+
comate state demo transition verify-fail
|
|
235
|
+
[ "$(comate state demo get phase)" = "build" ]
|
|
236
|
+
[ "$(comate state demo get verify_result)" = "pending" ]
|
|
237
|
+
[ "$(comate state demo get verification_report)" = "null" ]
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
@test "recover reports phase-local progress" {
|
|
241
|
+
comate state demo init full
|
|
242
|
+
comate state demo set phase_step open.review-awaiting >/dev/null
|
|
243
|
+
run comate state demo recover open
|
|
244
|
+
[ "$status" -eq 0 ]
|
|
245
|
+
[[ "$output" == *"Phase step: open.review-awaiting"* ]]
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
@test "status exposes awaiting decisions" {
|
|
249
|
+
comate state demo init full
|
|
250
|
+
comate state demo set phase_step open.review-awaiting >/dev/null
|
|
251
|
+
run comate status
|
|
252
|
+
[ "$status" -eq 0 ]
|
|
253
|
+
[[ "$output" == *"step: open.review-awaiting"* ]]
|
|
254
|
+
}
|
|
255
|
+
|
|
204
256
|
# --- guard open ---
|
|
205
257
|
|
|
206
258
|
@test "guard open passes with full artifacts and applies" {
|
|
@@ -436,6 +488,18 @@ SH
|
|
|
436
488
|
[ "$status" -eq 0 ]
|
|
437
489
|
}
|
|
438
490
|
|
|
491
|
+
@test "dependency archived requires an archived=true record" {
|
|
492
|
+
comate state dep init full
|
|
493
|
+
run comate dependency dep archived
|
|
494
|
+
[ "$status" -eq 1 ]
|
|
495
|
+
comate state dep set phase archive >/dev/null
|
|
496
|
+
comate state dep transition archived >/dev/null
|
|
497
|
+
mkdir -p openspec/changes/archive
|
|
498
|
+
mv openspec/changes/dep openspec/changes/archive/2026-08-20-dep
|
|
499
|
+
run comate dependency dep archived
|
|
500
|
+
[ "$status" -eq 0 ]
|
|
501
|
+
}
|
|
502
|
+
|
|
439
503
|
@test "top-level usage error returns code 2" {
|
|
440
504
|
run comate frobnicate
|
|
441
505
|
[ "$status" -eq 2 ]
|
|
@@ -503,16 +567,41 @@ seed_prd() {
|
|
|
503
567
|
comate gate "$prd" review >/dev/null
|
|
504
568
|
comate gate "$prd" set score 90 >/dev/null
|
|
505
569
|
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
570
|
+
comate gate "$prd" set changes_map "demo:功能项1" >/dev/null
|
|
506
571
|
run comate gate "$prd" pass
|
|
507
572
|
[ "$status" -eq 1 ]
|
|
508
573
|
[[ "$output" == *"report"* ]]
|
|
509
574
|
}
|
|
510
575
|
|
|
576
|
+
@test "gate pass blocks without a confirmed changes map" {
|
|
577
|
+
local prd; prd=$(seed_prd)
|
|
578
|
+
comate gate "$prd" review >/dev/null
|
|
579
|
+
comate gate "$prd" set score 90 >/dev/null
|
|
580
|
+
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
581
|
+
printf '# report\n' > "docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
582
|
+
run comate gate "$prd" pass
|
|
583
|
+
[ "$status" -eq 1 ]
|
|
584
|
+
[[ "$output" == *"changes_map"* ]]
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
@test "gate pass --tbd requires unresolved blockers" {
|
|
588
|
+
local prd; prd=$(seed_prd)
|
|
589
|
+
comate gate "$prd" review >/dev/null
|
|
590
|
+
comate gate "$prd" set score 90 >/dev/null
|
|
591
|
+
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
592
|
+
comate gate "$prd" set changes_map "demo:功能项1" >/dev/null
|
|
593
|
+
printf '# report\n' > "docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
594
|
+
run comate gate "$prd" pass --tbd
|
|
595
|
+
[ "$status" -eq 1 ]
|
|
596
|
+
[[ "$output" == *"requires at least one"* ]]
|
|
597
|
+
}
|
|
598
|
+
|
|
511
599
|
@test "gate pass succeeds and check passes after report written" {
|
|
512
600
|
local prd; prd=$(seed_prd)
|
|
513
601
|
comate gate "$prd" review >/dev/null
|
|
514
602
|
comate gate "$prd" set score 90 >/dev/null
|
|
515
603
|
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
604
|
+
comate gate "$prd" set changes_map "demo:功能项1" >/dev/null
|
|
516
605
|
printf '# 评审报告\n' > \
|
|
517
606
|
"docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
518
607
|
run comate gate "$prd" pass
|
|
@@ -525,7 +614,8 @@ seed_prd() {
|
|
|
525
614
|
local prd; prd=$(seed_prd)
|
|
526
615
|
comate gate "$prd" review >/dev/null
|
|
527
616
|
comate gate "$prd" set score 65 >/dev/null
|
|
528
|
-
comate gate "$prd" set blocking_open
|
|
617
|
+
comate gate "$prd" set blocking_open 2 >/dev/null
|
|
618
|
+
comate gate "$prd" set changes_map "demo:功能项1" >/dev/null
|
|
529
619
|
printf '# 评审报告\n' > \
|
|
530
620
|
"docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
531
621
|
run comate gate "$prd" pass --tbd
|
|
@@ -539,6 +629,7 @@ seed_prd() {
|
|
|
539
629
|
comate gate "$prd" review >/dev/null
|
|
540
630
|
comate gate "$prd" set score 90 >/dev/null
|
|
541
631
|
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
632
|
+
comate gate "$prd" set changes_map "demo:功能项1" >/dev/null
|
|
542
633
|
printf '# 评审报告\n' > \
|
|
543
634
|
"docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
544
635
|
comate gate "$prd" pass >/dev/null
|
|
@@ -554,6 +645,7 @@ seed_prd() {
|
|
|
554
645
|
comate gate "$prd" review >/dev/null
|
|
555
646
|
comate gate "$prd" set score 90 >/dev/null
|
|
556
647
|
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
648
|
+
comate gate "$prd" set changes_map "demo:功能项1" >/dev/null
|
|
557
649
|
printf '# 评审报告\n' > \
|
|
558
650
|
"docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
559
651
|
comate gate "$prd" pass >/dev/null
|
|
@@ -572,6 +664,7 @@ seed_prd() {
|
|
|
572
664
|
comate gate "$prd" review >/dev/null
|
|
573
665
|
comate gate "$prd" set score 90 >/dev/null
|
|
574
666
|
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
667
|
+
comate gate "$prd" set changes_map "login-flow:功能项1" >/dev/null
|
|
575
668
|
printf '# 报告\n' > \
|
|
576
669
|
"docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
577
670
|
comate gate "$prd" pass >/dev/null
|
|
@@ -587,6 +680,7 @@ seed_prd() {
|
|
|
587
680
|
comate gate "$prd" review >/dev/null
|
|
588
681
|
comate gate "$prd" set score 90 >/dev/null
|
|
589
682
|
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
683
|
+
comate gate "$prd" set changes_map "login-flow:功能项1;logout-flow:功能项2" >/dev/null
|
|
590
684
|
printf '# 报告\n' > \
|
|
591
685
|
"docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
592
686
|
comate gate "$prd" pass >/dev/null
|
|
@@ -616,6 +710,7 @@ seed_prd() {
|
|
|
616
710
|
comate gate "$prd" review >/dev/null
|
|
617
711
|
comate gate "$prd" set score 90 >/dev/null
|
|
618
712
|
comate gate "$prd" set blocking_open 0 >/dev/null
|
|
713
|
+
comate gate "$prd" set changes_map "demo:功能项1" >/dev/null
|
|
619
714
|
printf '# 报告\n' > \
|
|
620
715
|
"docs/knowledge-base/requirements/test/PRD-001-REVIEW.md"
|
|
621
716
|
comate gate "$prd" pass >/dev/null
|
|
@@ -25,7 +25,43 @@ fi
|
|
|
25
25
|
bash "$COMATE" state <name> check build
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
**幂等性检查**:
|
|
29
|
+
|
|
30
|
+
1. 读取 `.comate.yaml` 的 `plan`、`isolation`、`build_mode`、`tdd_mode`、`phase_step`、`phase_step_data`
|
|
31
|
+
|
|
32
|
+
2. **检查是否被依赖阻塞**(最高优先级检查):
|
|
33
|
+
- 若 `phase_step` 为 `build.blocked-by-<dependency>`:
|
|
34
|
+
- 从 `phase_step` 或 `phase_step_data` 中提取依赖的 change 名称
|
|
35
|
+
- 运行 `bash "$COMATE" dependency <dependency> archived` 检查归档目录中是否存在该 change 且其 `.comate.yaml` 明确记录 `archived: true`;不得用“不在活跃列表”推断归档完成
|
|
36
|
+
- **若依赖已归档**:
|
|
37
|
+
```bash
|
|
38
|
+
bash "$COMATE" state <name> set phase_step build.options-confirmed
|
|
39
|
+
bash "$COMATE" state <name> set phase_step_data null
|
|
40
|
+
```
|
|
41
|
+
清除阻塞标记,说明「依赖 change <dependency> 已完成,继续当前 change 的 build」,继续第 3 步检查
|
|
42
|
+
- **若依赖未归档**:提示「当前 change 正在等待 <dependency> 完成。请先完成 <dependency> 的全流程后再继续。」,**立即退出**
|
|
43
|
+
|
|
44
|
+
3. **已完成 Step 3(工作方式已选定)** 的判定条件:
|
|
45
|
+
- `isolation`、`build_mode`、`tdd_mode` **三个字段全部已设置且非 null**
|
|
46
|
+
- 或 `phase_step` 值为 `build.options-confirmed`
|
|
47
|
+
|
|
48
|
+
4. **幂等分支**:
|
|
49
|
+
- **三个决策字段全部已设置** → 跳过 Step 3a-3c,说明「工作方式已选定:isolation={value}, build_mode={value}, tdd_mode={value}」,直接进入执行(加载对应技能)
|
|
50
|
+
- **任一字段未设置或为 null**:
|
|
51
|
+
- 若 `phase_step` 为 `build.plan-created` 或 `build.plan-recorded` → 继续对应步骤(见下方第 5 点)
|
|
52
|
+
- 若 `plan` 未设置 → 从 Step 1 开始
|
|
53
|
+
- 若 `plan` 已设置但决策未完成 → 从 Step 3 开始
|
|
54
|
+
|
|
55
|
+
5. **断点恢复**(根据 `phase_step` 值):
|
|
56
|
+
- `phase_step` 为 `build.plan-created`(或旧版 `1`)→ 从 Step 2 开始并改写新格式
|
|
57
|
+
- `phase_step` 为 `build.plan-recorded` / `build.options-awaiting`(或旧版 `2`)→ 从 Step 3 恢复并改写新格式
|
|
58
|
+
- `phase_step` 为 `build.options-confirmed`(或旧版 `3-confirmed`)→ 直接加载执行技能并改写新格式
|
|
59
|
+
- `phase_step` 为 `build.blocked-by-*` → 见第 2 点的依赖阻塞检查
|
|
60
|
+
|
|
61
|
+
6. **已进入执行阶段**(plan 已设置、决策已完成):
|
|
62
|
+
- 读 tasks.md 找第一个未勾选任务继续
|
|
63
|
+
- 已提交的任务不得重复提交
|
|
64
|
+
- 上下文压缩恢复时,重新加载对应的执行技能,然后继续未完成的任务
|
|
29
65
|
|
|
30
66
|
### 1. 制定计划
|
|
31
67
|
|
|
@@ -44,10 +80,17 @@ base-ref: <实施前的 git rev-parse HEAD>
|
|
|
44
80
|
|
|
45
81
|
`base-ref` 用于验证阶段跨提交统计改动规模。创建计划时先 `git rev-parse HEAD` 记录。
|
|
46
82
|
|
|
83
|
+
**步骤完成后记录**:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
bash "$COMATE" state <name> set phase_step build.plan-created
|
|
87
|
+
```
|
|
88
|
+
|
|
47
89
|
### 2. 记录计划路径
|
|
48
90
|
|
|
49
91
|
```bash
|
|
50
92
|
bash "$COMATE" state <name> set plan docs/superpowers/plans/YYYY-MM-DD-feature.md
|
|
93
|
+
bash "$COMATE" state <name> set phase_step build.plan-recorded
|
|
51
94
|
```
|
|
52
95
|
|
|
53
96
|
无需手动改 phase,guard 会在退出条件满足后自动流转。
|
|
@@ -79,11 +122,17 @@ bash "$COMATE" state <name> set plan docs/superpowers/plans/YYYY-MM-DD-feature.m
|
|
|
79
122
|
|
|
80
123
|
#### 3c. 联合决策(仍有 ≥2 有效选项的维度才问)
|
|
81
124
|
|
|
82
|
-
对仍有多个有效选项的维度,**一次 AskUserQuestion 问清全部**,选 `branch` 时**分支名也在同一次确认**,不得先问是否继续再二次追问配置或命名。已在 3b 自动写入的维度不再列入问题。每个选项附推荐理由(推荐只说明倾向,不代替用户拍板):
|
|
125
|
+
对仍有多个有效选项的维度,**一次 AskUserQuestion 问清全部**,选 `branch` 时**分支名也在同一次确认**,不得先问是否继续再二次追问配置或命名。已在 3b 自动写入的维度不再列入问题。每个选项附推荐理由(推荐只说明倾向,不代替用户拍板):
|
|
83
126
|
|
|
84
127
|
- **工作区隔离**:`branch` 新建分支(简单快速,≤3 文件推荐)/ `worktree` 独立工作区(需并行或当前分支有未提交工作时推荐)。
|
|
85
128
|
- **执行方式**:`subagent-driven-development`(任务 ≥3、独立、需双阶段审查)/ `executing-plans`(任务 ≤2 且无跨模块依赖,或来自 fix 预设)。
|
|
86
|
-
- **TDD 模式**:`tdd`(涉及业务逻辑/新功能/API,推荐)/ `direct`(无需测试覆盖或用户明确跳过)。
|
|
129
|
+
- **TDD 模式**:`tdd`(涉及业务逻辑/新功能/API,推荐)/ `direct`(无需测试覆盖或用户明确跳过)。
|
|
130
|
+
|
|
131
|
+
提问前先持久化:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
bash "$COMATE" state <name> set phase_step build.options-awaiting
|
|
135
|
+
```
|
|
87
136
|
|
|
88
137
|
用户选择后(连同 3b 已自动应用的维度)写入:
|
|
89
138
|
|
|
@@ -91,6 +140,7 @@ bash "$COMATE" state <name> set plan docs/superpowers/plans/YYYY-MM-DD-feature.m
|
|
|
91
140
|
bash "$COMATE" state <name> set isolation <branch|worktree>
|
|
92
141
|
bash "$COMATE" state <name> set build_mode <subagent-driven-development|executing-plans|direct>
|
|
93
142
|
bash "$COMATE" state <name> set tdd_mode <tdd|direct>
|
|
143
|
+
bash "$COMATE" state <name> set phase_step build.options-confirmed
|
|
94
144
|
```
|
|
95
145
|
|
|
96
146
|
`isolation` 是脚本级硬约束,保持 `null` 时 `build → verify` 的 guard 和 `state transition build-complete` 都会失败。
|
|
@@ -136,9 +186,36 @@ bash "$COMATE" state <name> set build_mode direct
|
|
|
136
186
|
|------|------|------|
|
|
137
187
|
| 小 | 遗漏验收场景、边界条件 | 直接编辑 delta spec + design.md,追加 tasks.md |
|
|
138
188
|
| 中 | 接口变更、新增组件、数据流变化 | **AskUserQuestion 确认后**加载 `superpowers:brainstorming` 更新 Design Doc + delta spec |
|
|
139
|
-
| 大 | 全新 capability | **AskUserQuestion 确认拆分后**用 `/comate-open` 创建独立 change |
|
|
140
|
-
|
|
141
|
-
**50% 阈值**:以 tasks.md 初始任务总数为基准,新增任务超过总数一半即视为超范围,**必须 AskUserQuestion 暂停**决定是否拆分。创建独立 change 必须调 `/comate-open`,不得直接调 `/opsx:new`。
|
|
189
|
+
| 大 | 全新 capability | **AskUserQuestion 确认拆分后**用 `/comate-open` 创建独立 change,**当前 change 的 build 流程立即终止** |
|
|
190
|
+
|
|
191
|
+
**50% 阈值**:以 tasks.md 初始任务总数为基准,新增任务超过总数一半即视为超范围,**必须 AskUserQuestion 暂停**决定是否拆分。创建独立 change 必须调 `/comate-open`,不得直接调 `/opsx:new`。
|
|
192
|
+
|
|
193
|
+
凡需 AskUserQuestion 决定范围扩张时,提问前先写 `phase_step: build.scope-awaiting`;用户决定继续当前 change 后恢复为 `build.options-confirmed`。
|
|
194
|
+
|
|
195
|
+
**大规模扩张(全新 capability)确认拆分后的流程终止规则**:
|
|
196
|
+
|
|
197
|
+
1. 用 `/comate-open` 创建独立 change `<new-change-name>`
|
|
198
|
+
2. **当前 change `<current>` 的 build 流程立即暂停**,记录依赖关系:
|
|
199
|
+
```bash
|
|
200
|
+
bash "$COMATE" state <current> set phase_step "build.blocked-by-<new-change-name>"
|
|
201
|
+
bash "$COMATE" state <current> set phase_step_data "<new-change-name>"
|
|
202
|
+
```
|
|
203
|
+
3. 提示用户:
|
|
204
|
+
```
|
|
205
|
+
已创建独立 change <new-change-name>。
|
|
206
|
+
当前 change <current> 的 build 流程已暂停,等待 <new-change-name> 完成。
|
|
207
|
+
|
|
208
|
+
请先完成 <new-change-name> 的全流程(design → build → verify → archive),
|
|
209
|
+
然后再继续 <current> 的 build。
|
|
210
|
+
```
|
|
211
|
+
4. **立即退出当前 /comate 调用**,不继续执行当前 change 的后续任务,不进入 Step 5
|
|
212
|
+
|
|
213
|
+
**恢复被阻塞的 change**:
|
|
214
|
+
|
|
215
|
+
当用户稍后运行 `/comate <current>` 时,Step 0 幂等性检查会发现 `phase_step` 包含 `blocked-by` 标记:
|
|
216
|
+
- 检查依赖的 change 是否已归档
|
|
217
|
+
- 若 `dependency <name> archived` 通过 → 清除阻塞标记,恢复 `phase_step` 为 `build.options-confirmed`,继续执行 tasks.md 中未完成的任务
|
|
218
|
+
- 若未归档 → 提示用户先完成依赖 change,退出
|
|
142
219
|
|
|
143
220
|
### 5. 上下文管理与 build 交接包
|
|
144
221
|
|
|
@@ -25,7 +25,39 @@ fi
|
|
|
25
25
|
bash "$COMATE" state <name> check design
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
**幂等性检查**:
|
|
29
|
+
|
|
30
|
+
1. 读取 `.comate.yaml` 的 `design_doc`、`handoff_context`、`handoff_hash`、`phase_step`
|
|
31
|
+
|
|
32
|
+
2. **已完成 Step 1c(方案已确认)** 的判定条件(按优先级,首个命中即算):
|
|
33
|
+
|
|
34
|
+
a. **phase_step 明确标记已确认**(最高优先级):
|
|
35
|
+
- `phase_step` 值为 `design.approval-confirmed` 或 `design.complete`(旧版 `1c-confirmed` / `2` 兼容一次)
|
|
36
|
+
- → **立即判定为已完成 Step 1c**,跳过 Step 1a-1c
|
|
37
|
+
|
|
38
|
+
b. **Design Doc 文件存在且格式正确**(次优先级):
|
|
39
|
+
- `design_doc` 已设置且文件存在
|
|
40
|
+
- frontmatter 含 `comate_change: <name>`
|
|
41
|
+
- frontmatter 含 `role: technical-design`
|
|
42
|
+
- frontmatter 含 `canonical_spec: openspec`
|
|
43
|
+
- 文件内容非空(除了 frontmatter 外有实质设计内容)
|
|
44
|
+
- → **判定为已完成 Step 1c**,跳过 Step 1a-1c
|
|
45
|
+
|
|
46
|
+
**说明**:之所以 `phase_step` 优先级更高,是因为它是原子操作记录的决策状态,即使 Design Doc 文件创建失败或被误删,也能防止重复进入决策流程。
|
|
47
|
+
|
|
48
|
+
3. **幂等分支**:
|
|
49
|
+
- **已完成 Step 1c 且 Design Doc 存在** → 跳过 Step 1a-1c,检查交接包:
|
|
50
|
+
- 若 `handoff_context` 和 `handoff_hash` 已设置且验证通过 → 直接进入 Step 2 的 guard 检查
|
|
51
|
+
- 若交接包缺失或 hash 不匹配 → 重新生成交接包(`bash "$COMATE" handoff <name> design --write`),**但不重新 brainstorming,不重新确认方案**,然后进入 Step 2
|
|
52
|
+
- **已确认但 Design Doc 缺失** → 从 `.comate/design-candidate.md` 恢复已确认方案并创建 Design Doc;候选文件也缺失时停止并报告状态损坏,不得假称 Design Doc 已存在,也不得重新向用户询问同一决策
|
|
53
|
+
- **未完成 Step 1c** → 继续 Step 1a
|
|
54
|
+
|
|
55
|
+
4. **断点恢复**(根据 `phase_step` 值):
|
|
56
|
+
- `phase_step` 为 `design.handoff-written`(或旧版 `1a`)→ 从 Step 1b 开始并改写新格式
|
|
57
|
+
- `phase_step` 为 `design.brainstorm-complete` / `design.approval-awaiting`(或旧版 `1b`)→ 从候选文件恢复 Step 1c 并改写新格式
|
|
58
|
+
- `phase_step` 为 `design.approval-confirmed` 或 `design.complete` → 见第 3 点幂等分支
|
|
59
|
+
|
|
60
|
+
5. **特别注意**:即使上下文压缩或会话中断,只要 `phase_step` 已标记 `design.approval-confirmed` 或 Design Doc 文件存在且格式正确,**就不得重新执行 brainstorming 或重新要求用户确认方案**。
|
|
29
61
|
|
|
30
62
|
### 1a. 生成 OpenSpec → Superpowers 交接包
|
|
31
63
|
|
|
@@ -33,6 +65,8 @@ bash "$COMATE" state <name> check design
|
|
|
33
65
|
|
|
34
66
|
```bash
|
|
35
67
|
bash "$COMATE" handoff <name> design --write
|
|
68
|
+
# 记录步骤完成
|
|
69
|
+
bash "$COMATE" state <name> set phase_step design.handoff-written
|
|
36
70
|
```
|
|
37
71
|
|
|
38
72
|
脚本生成 `openspec/changes/<name>/.comate/handoff/design-context.{json,md}` 并在 `.comate.yaml` 写入 `handoff_context` / `handoff_hash`。默认是 **compact 可追溯摘录**(含脚本标记 `Generated-by: comate`、source path、line range、sha256),不是 agent summary。需全文时加 `--full`。
|
|
@@ -62,13 +96,48 @@ canonical_spec: openspec
|
|
|
62
96
|
|
|
63
97
|
禁止跳过;该技能不可用时停止流程并提示安装 Superpowers,不要用普通对话替代。
|
|
64
98
|
|
|
65
|
-
brainstorming
|
|
99
|
+
brainstorming 阶段不写最终 Design Doc;但必须把完整候选方案写入 `openspec/changes/<name>/.comate/design-candidate.md`,供确认与上下文恢复使用。
|
|
100
|
+
|
|
101
|
+
**步骤完成后记录**:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
bash "$COMATE" state <name> set phase_step design.brainstorm-complete
|
|
105
|
+
```
|
|
66
106
|
|
|
67
107
|
### 1c. 用户确认设计方案(决策阻塞点 2)
|
|
68
108
|
|
|
69
109
|
**必须使用 AskUserQuestion 工具暂停等待用户明确确认设计方案**。规则见 `comate/reference/decision-points.md` 第 2 条。确认前不得创建最终 Design Doc、写 `design_doc`、跑 design guard 或进入 build。
|
|
70
110
|
|
|
71
|
-
展示摘要:采用的技术方案、关键取舍与风险、测试策略、Spec Patch(如有)。用户确认后才继续 Step 2;要求调整则继续迭代。
|
|
111
|
+
展示摘要:采用的技术方案、关键取舍与风险、测试策略、Spec Patch(如有)。用户确认后才继续 Step 2;要求调整则继续迭代。
|
|
112
|
+
|
|
113
|
+
提问前先确认候选文件非空,并持久化等待状态:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
bash "$COMATE" state <name> set phase_step design.approval-awaiting
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**确认后的处理顺序(不可颠倒)**:
|
|
120
|
+
|
|
121
|
+
1. **立即记录决策状态**:
|
|
122
|
+
```bash
|
|
123
|
+
bash "$COMATE" state <name> set phase_step design.approval-confirmed
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
2. **然后创建 Design Doc 文件**(保存到 `docs/superpowers/specs/YYYY-MM-DD-topic-design.md`),frontmatter 必须包含:
|
|
127
|
+
```yaml
|
|
128
|
+
---
|
|
129
|
+
comate_change: <name>
|
|
130
|
+
role: technical-design
|
|
131
|
+
canonical_spec: openspec
|
|
132
|
+
---
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
3. **记录 design_doc 路径**:
|
|
136
|
+
```bash
|
|
137
|
+
bash "$COMATE" state <name> set design_doc docs/superpowers/specs/YYYY-MM-DD-topic-design.md
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**说明**:候选方案先落盘,确认后再记录 `design.approval-confirmed` 并创建最终文件。这样中断恢复既不会重复提问,也不会丢失创建 Design Doc 所需内容。
|
|
72
141
|
|
|
73
142
|
### 2. 更新 comate 状态
|
|
74
143
|
|
|
@@ -79,6 +148,9 @@ bash "$COMATE" state <name> set design_doc docs/superpowers/specs/YYYY-MM-DD-top
|
|
|
79
148
|
# 如有 delta spec 变更,重新生成 handoff 以更新 hash
|
|
80
149
|
bash "$COMATE" handoff <name> design --write
|
|
81
150
|
|
|
151
|
+
# 记录步骤完成
|
|
152
|
+
bash "$COMATE" state <name> set phase_step design.complete
|
|
153
|
+
|
|
82
154
|
# 自动流转
|
|
83
155
|
bash "$COMATE" guard <name> design --apply
|
|
84
156
|
```
|
|
@@ -138,15 +138,19 @@ Fix 为**一次性连续执行**。调用后在自有步骤间自动推进,但
|
|
|
138
138
|
| 需新增 capability | 超出局部优化 |
|
|
139
139
|
| 需 delta spec | 影响已有规格 |
|
|
140
140
|
|
|
141
|
-
**必须使用 AskUserQuestion
|
|
141
|
+
**必须使用 AskUserQuestion 工具暂停确认升级**。提问前记录:
|
|
142
142
|
|
|
143
143
|
```bash
|
|
144
|
-
bash "$COMATE" state <name> set
|
|
145
|
-
bash "$COMATE" state <name> set workflow full
|
|
146
|
-
bash "$COMATE" state <name> transition open-complete
|
|
144
|
+
bash "$COMATE" state <name> set phase_step fix.upgrade-awaiting
|
|
147
145
|
```
|
|
148
146
|
|
|
149
|
-
|
|
147
|
+
用户确认后使用原子状态转换进入完整流程:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
bash "$COMATE" state <name> transition fix-upgrade
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
该转换会原子设置 `workflow: full`、进入 `phase: design`,并清空 fix 预置的 `build_mode` / `tdd_mode` / `isolation` / `verify_mode` 及阶段进度,避免 full build 误沿用 `direct`。然后**立即加载 `comate-design` skill** 补 Design Doc。用户不确认则停止 fix 并报告超出适用范围。
|
|
150
154
|
|
|
151
155
|
## 退出条件
|
|
152
156
|
|
|
@@ -42,7 +42,7 @@ gate 命令族(退出码:`0` 通过 / `1` 阻塞 / `2` 用法 / `3` 环境 /
|
|
|
42
42
|
```bash
|
|
43
43
|
bash "$COMATE" gate <prd> review # 建/刷新 gate.yaml,钉 PRD 哈希,回报告路径
|
|
44
44
|
bash "$COMATE" gate <prd> set <field> <value> # 写 score | blocking_open | gate_status
|
|
45
|
-
bash "$COMATE" gate <prd> pass [--tbd] #
|
|
45
|
+
bash "$COMATE" gate <prd> pass [--tbd] # 普通通过要求 0 阻断;--tbd 要求有已授权的未解决阻断
|
|
46
46
|
bash "$COMATE" gate <prd> spawned <change> # 记录据此 PRD 扇出的 change
|
|
47
47
|
bash "$COMATE" gate <prd> status [--json] # 查状态(哈希漂移自动判 stale)
|
|
48
48
|
bash "$COMATE" gate <prd> check # comate-open 建 change 前的前置守卫
|
|
@@ -209,12 +209,12 @@ bash "$COMATE" gate <prd> set changes_map "changeA:功能项1,2,3;changeB:功能
|
|
|
209
209
|
映射与 `blocking_open` 都就绪后,置门禁通过:
|
|
210
210
|
|
|
211
211
|
```bash
|
|
212
|
-
bash "$COMATE" gate <prd> pass # 阻断已清零
|
|
213
|
-
# 或用户授权带 TBD:
|
|
214
|
-
bash "$COMATE" gate <prd> pass --tbd
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
`pass`
|
|
212
|
+
bash "$COMATE" gate <prd> pass # 阻断已清零
|
|
213
|
+
# 或用户授权带 TBD:
|
|
214
|
+
bash "$COMATE" gate <prd> pass --tbd
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
`pass` 会硬校验评分为 0–100、`changes_map` 非空、报告非空;普通 pass 要求 `blocking_open=0`,`--tbd` 则要求存在至少 1 个已记录且经用户明确接受的未解决阻断项。之后 PRD 再被改,哈希漂移会使门禁 `stale`,须重跑 `/comate-gate`。
|
|
218
218
|
|
|
219
219
|
### 6. 逐 Change 初始化(调 comate-open)
|
|
220
220
|
|
|
@@ -63,8 +63,11 @@ if [ -z "$COMATE" ]; then
|
|
|
63
63
|
return 1 2>/dev/null || exit 1
|
|
64
64
|
fi
|
|
65
65
|
|
|
66
|
+
bash "$COMATE" state <name> init full
|
|
66
67
|
```
|
|
67
68
|
|
|
69
|
+
这会创建 `openspec/changes/<name>/.comate.yaml`,初始状态:`workflow: full`, `phase: open`, `phase_step: null`。
|
|
70
|
+
|
|
68
71
|
### 3b. 判定需求来源(源文件追踪)
|
|
69
72
|
|
|
70
73
|
`state init` 默认写入 `source_kind: conversation`、`source_manifest: null`(需求由对话产生)。
|
|
@@ -91,7 +94,7 @@ bash "$COMATE" gate <prd路径> spawned <name>
|
|
|
91
94
|
|
|
92
95
|
需求**来自对话**时跳过本步。
|
|
93
96
|
|
|
94
|
-
### 3.
|
|
97
|
+
### 3. 入口状态验证与幂等性检查
|
|
95
98
|
|
|
96
99
|
```bash
|
|
97
100
|
bash "$COMATE" state <name> check open
|
|
@@ -99,16 +102,41 @@ bash "$COMATE" state <name> check open
|
|
|
99
102
|
|
|
100
103
|
验证通过后继续 Step 4。失败时脚本输出具体原因。
|
|
101
104
|
|
|
102
|
-
|
|
105
|
+
**幂等性检查**:
|
|
106
|
+
|
|
107
|
+
1. 读取 `.comate.yaml` 的 `phase`、`phase_step`、workflow、以及三件套文件路径
|
|
108
|
+
|
|
109
|
+
2. **已完成 Step 5(产物已审视确认)** 的判定条件:
|
|
110
|
+
- `phase_step` 值为 `open.review-confirmed`(旧版 `5-confirmed` 兼容一次)
|
|
111
|
+
- 或 `phase` 已经不是 `open`(说明已流转到下一阶段)
|
|
112
|
+
|
|
113
|
+
3. **幂等分支**:
|
|
114
|
+
- **已完成 Step 5** → 跳过所有步骤,说明「开题已完成,三件套已确认」,直接检查退出条件(guard)
|
|
115
|
+
- **未完成 Step 5** → 检查三件套是否存在:
|
|
116
|
+
- 三件套全部存在且非空 → 跳到 Step 4(内容完整性检查)
|
|
117
|
+
- 任一文件缺失或为空 → 从 Step 1 开始(如果是首次)或 Step 3b/3c(如果是 PRD 来源)
|
|
118
|
+
|
|
119
|
+
4. **断点恢复**(根据 `phase_step` 值):
|
|
120
|
+
- `phase_step` 为 `open.artifacts-created` → 从 Step 4 开始
|
|
121
|
+
- `phase_step` 为 `open.review-awaiting`(或旧版 `4`)→ 恢复 Step 5 的用户确认,并改写为新格式
|
|
122
|
+
- `phase_step` 为 `open.review-confirmed`(或旧版 `5-confirmed`)→ 见第 3 点幂等分支
|
|
123
|
+
|
|
124
|
+
5. **open 阶段特点**:open 阶段的所有操作(explore、创建三件套、状态初始化)可安全重复执行。但**产物审视(Step 5)的用户确认不可重复**,一旦 `phase_step: open.review-confirmed` 被记录,即使上下文压缩也不得重新要求用户确认。
|
|
103
125
|
|
|
104
126
|
### 4. 内容完整性检查
|
|
105
127
|
|
|
106
|
-
逐个确认三个文件路径存在且非空:
|
|
128
|
+
逐个确认三个文件路径存在且非空:
|
|
107
129
|
- **proposal.md**:问题背景、目标、范围、非目标
|
|
108
130
|
- **design.md**:高层架构决策、方案选型、数据流
|
|
109
131
|
- **tasks.md**:任务列表,每个任务有明确描述
|
|
110
132
|
|
|
111
|
-
任一文件缺失或为空时,不得进入 Step 5 或执行守卫,必须回创建步骤补充。
|
|
133
|
+
任一文件缺失或为空时,不得进入 Step 5 或执行守卫,必须回创建步骤补充。
|
|
134
|
+
|
|
135
|
+
完整性检查通过后记录:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
bash "$COMATE" state <name> set phase_step open.artifacts-created
|
|
139
|
+
```
|
|
112
140
|
|
|
113
141
|
### 5. 产物审视(决策阻塞点 1,按来源分类)
|
|
114
142
|
|
|
@@ -119,21 +147,46 @@ bash "$COMATE" state <name> check open
|
|
|
119
147
|
同时满足以下**全部**条件时,本决策点降级为自动流转,**不 AskUserQuestion**:
|
|
120
148
|
|
|
121
149
|
1. `source_kind: file`(本 change 追踪了源文件);
|
|
122
|
-
2. 追踪的源是一份 PRD,且 `bash "$COMATE" gate <prd路径> check` 返回 PASS(exit 0)——即门禁 `passed`/`passed-with-tbd` 且 PRD 哈希未漂移。PRD 路径从 `sources <name> list` 或 Step
|
|
123
|
-
3. change 名已记入该 PRD 的 `spawned_changes`(Step
|
|
150
|
+
2. 追踪的源是一份 PRD,且 `bash "$COMATE" gate <prd路径> check` 返回 PASS(exit 0)——即门禁 `passed`/`passed-with-tbd` 且 PRD 哈希未漂移。PRD 路径从 `sources <name> list` 或 Step 3c 的上下文取得;
|
|
151
|
+
3. change 名已记入该 PRD 的 `spawned_changes`(Step 3c 的 `gate spawned` 已执行,通常由 `/comate-gate` 备妥);
|
|
124
152
|
4. **范围一致性自检**:proposal 的目标/范围/非目标忠实承接 gate 映射里本 change 认领的功能项——没有擅自扩大或缩小、没有认领未分配的功能项、没有漏掉已分配项。
|
|
125
153
|
|
|
126
|
-
四条全成立时:范围/映射/命名已在决策点 6
|
|
154
|
+
四条全成立时:范围/映射/命名已在决策点 6 由用户拍板,三件套只是承接,无新的有效选项。
|
|
155
|
+
|
|
156
|
+
**自动流转处理**:
|
|
157
|
+
|
|
158
|
+
1. **记录自动确认状态**:
|
|
159
|
+
```bash
|
|
160
|
+
bash "$COMATE" state <name> set phase_step open.review-confirmed
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
2. **如实报告**:「本 change 承接自 PRD <prd-name>,认领功能项:<列出项>。已核对范围与映射一致,自动进入下一阶段。」
|
|
164
|
+
|
|
165
|
+
3. 直接进入退出条件执行守卫流转
|
|
127
166
|
|
|
128
167
|
#### 5b. 需要用户输入的两种情形(AskUserQuestion 阻塞)
|
|
129
168
|
|
|
130
169
|
- **对话来源**(`source_kind: conversation`):范围此前未经用户拍板,三件套第一次成形。
|
|
131
170
|
- **PRD 扇出但 5a 第 4 条不成立**(范围与映射有偏差):分歧重新出现。
|
|
132
171
|
|
|
133
|
-
以上任一情形,**必须使用 AskUserQuestion 工具暂停等待用户确认**。以单选题呈现摘要(proposal 问题/目标/范围、design 架构决策/选型、tasks 数量与关键任务;PRD 偏差场景额外列出偏差点)和选项:
|
|
134
|
-
- 「确认,继续下一阶段」—
|
|
172
|
+
以上任一情形,**必须使用 AskUserQuestion 工具暂停等待用户确认**。以单选题呈现摘要(proposal 问题/目标/范围、design 架构决策/选型、tasks 数量与关键任务;PRD 偏差场景额外列出偏差点)和选项:
|
|
173
|
+
- 「确认,继续下一阶段」— 记录确认状态后执行守卫流转
|
|
135
174
|
- 「需要调整」— 附调整说明(PRD 偏差场景默认建议按映射修正),修改后重新请求确认
|
|
136
175
|
|
|
176
|
+
**提问前先持久化等待状态**:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
bash "$COMATE" state <name> set phase_step open.review-awaiting
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**用户确认后立即记录**:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
bash "$COMATE" state <name> set phase_step open.review-confirmed
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
然后继续执行退出条件(guard)。
|
|
189
|
+
|
|
137
190
|
## 退出条件
|
|
138
191
|
|
|
139
192
|
- 三件套已创建且内容完整
|
|
@@ -67,10 +67,12 @@ git diff --stat "$BASE_REF"...HEAD
|
|
|
67
67
|
```
|
|
68
68
|
然后调 `/comate-build`。回到 build 前如实报告:哪些是 CRITICAL 失败项、判定依据、将如何修复。
|
|
69
69
|
|
|
70
|
-
2. **无 CRITICAL,仅 WARNING / SUGGESTION** —— 属"用户决策"(接受偏差是合法选择)。**一次性 AskUserQuestion 批量展示**全部失败项与推荐处理,提供:
|
|
70
|
+
2. **无 CRITICAL,仅 WARNING / SUGGESTION** —— 属"用户决策"(接受偏差是合法选择)。**一次性 AskUserQuestion 批量展示**全部失败项与推荐处理,提供:
|
|
71
71
|
- **全部修复**:`bash "$COMATE" state <name> transition verify-fail` 然后调 `/comate-build`
|
|
72
72
|
- **逐项处理**:勾选要修的项,其余接受偏差
|
|
73
|
-
- **接受偏差**:全部接受,须在报告记录每项原因和影响
|
|
73
|
+
- **接受偏差**:全部接受,须在报告记录每项原因和影响
|
|
74
|
+
|
|
75
|
+
提问前先写 `phase_step: verify.failure-awaiting`;作出决定后清除或写入对应处理结果。
|
|
74
76
|
|
|
75
77
|
3. **Spec 漂移** —— 按 Step 2b 的单选题处理(属"用户决策",必须暂停)。
|
|
76
78
|
|
|
@@ -91,10 +93,12 @@ git diff --stat "$BASE_REF"...HEAD
|
|
|
91
93
|
|
|
92
94
|
规模为「大」时**立即使用 Skill 工具加载 `openspec-verify-change`**。检查项:tasks 全勾、实现符合 design.md 高层决策、符合 Design Doc、能力规格场景全通过、proposal 目标满足、delta spec 与 design doc 无矛盾、关联设计文档可定位。
|
|
93
95
|
|
|
94
|
-
**Spec 漂移处理**(决策阻塞点 4 的一部分):若发现 delta spec 与 design doc 矛盾,**必须以单选题 AskUserQuestion 暂停**:
|
|
96
|
+
**Spec 漂移处理**(决策阻塞点 4 的一部分):若发现 delta spec 与 design doc 矛盾,**必须以单选题 AskUserQuestion 暂停**:
|
|
95
97
|
- A:在 design doc 追加 "Implementation Divergence" 节记录偏差(属 verify 阶段允许产物,写入后不再触发 Step 1b dirty 决策)
|
|
96
98
|
- B:`state transition verify-fail` 然后调 `/comate-build` 由 Spec 增量更新规则更新
|
|
97
|
-
- C:确认偏差可接受继续(归档时 design doc 标记 `superseded-by-main-spec`)
|
|
99
|
+
- C:确认偏差可接受继续(归档时 design doc 标记 `superseded-by-main-spec`)
|
|
100
|
+
|
|
101
|
+
提问前先写 `phase_step: verify.spec-drift-awaiting`。
|
|
98
102
|
|
|
99
103
|
### 3. 记录验证证据
|
|
100
104
|
|
|
@@ -123,15 +127,20 @@ bash "$COMATE" state <name> set verification_report docs/superpowers/reports/YYY
|
|
|
123
127
|
|
|
124
128
|
**立即执行:** 使用 Skill 工具加载 `superpowers:finishing-a-development-branch`。不可用时停止并提示安装。
|
|
125
129
|
|
|
126
|
-
分支处理选项:本地合并 / 推送建 PR / 保持分支 / 丢弃工作。**必须使用 AskUserQuestion 工具暂停等待用户选择**。规则见 `comate/reference/decision-points.md` 第 5
|
|
130
|
+
分支处理选项:本地合并 / 推送建 PR / 保持分支 / 丢弃工作。**必须使用 AskUserQuestion 工具暂停等待用户选择**。规则见 `comate/reference/decision-points.md` 第 5 条。提问前先写:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
bash "$COMATE" state <name> set phase_step verify.branch-awaiting
|
|
134
|
+
```
|
|
127
135
|
|
|
128
|
-
|
|
136
|
+
选择本地合并 / 推送建 PR / 保持分支且操作完成后写入状态:
|
|
129
137
|
|
|
130
138
|
```bash
|
|
131
|
-
bash "$COMATE" state <name> set branch_status handled
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
139
|
+
bash "$COMATE" state <name> set branch_status handled
|
|
140
|
+
bash "$COMATE" state <name> set phase_step verify.branch-handled
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
选择**丢弃工作**时必须写 `branch_status: discarded` 和 `phase_step: verify.discarded`,随后立即停止;不得运行 verify guard、不得设置 `verify_result: pass`、不得归档。若之后要继续该 change,先执行 `state transition <name> verify-fail` 回到 build,再重新实现并生成新的 build handoff。
|
|
135
144
|
|
|
136
145
|
## 退出条件
|
|
137
146
|
|