@house365/comate 0.3.0 → 0.4.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.
@@ -447,3 +447,200 @@ SH
447
447
  run comate frobnicate
448
448
  [ "$status" -eq 2 ]
449
449
  }
450
+
451
+ # --- gate ---
452
+
453
+ seed_prd() {
454
+ mkdir -p docs/knowledge-base/requirements/test
455
+ printf '# PRD-001\n功能清单:登录、登出\n' > \
456
+ docs/knowledge-base/requirements/test/PRD-001-demo.md
457
+ echo "docs/knowledge-base/requirements/test/PRD-001-demo.md"
458
+ }
459
+
460
+ @test "gate review creates gate.yaml next to PRD" {
461
+ local prd; prd=$(seed_prd)
462
+ run comate gate "$prd" review
463
+ [ "$status" -eq 0 ]
464
+ [ -f "docs/knowledge-base/requirements/test/PRD-001-demo.gate.yaml" ]
465
+ }
466
+
467
+ @test "gate review writes reviewing status and pins prd_hash" {
468
+ local prd; prd=$(seed_prd)
469
+ comate gate "$prd" review >/dev/null
470
+ local gate="docs/knowledge-base/requirements/test/PRD-001-demo.gate.yaml"
471
+ run comate gate "$prd" status
472
+ [ "$status" -eq 0 ]
473
+ [[ "$output" == *"reviewing"* ]]
474
+ local hash; hash=$(grep '^prd_hash:' "$gate" | awk '{print $2}')
475
+ [ -n "$hash" ]
476
+ [ "$hash" != "null" ]
477
+ }
478
+
479
+ @test "gate check blocks when status is reviewing" {
480
+ local prd; prd=$(seed_prd)
481
+ comate gate "$prd" review >/dev/null
482
+ run comate gate "$prd" check
483
+ [ "$status" -eq 1 ]
484
+ [[ "$output" == *"BLOCK"* ]]
485
+ }
486
+
487
+ @test "gate pass blocked when blocking_open not zero" {
488
+ local prd; prd=$(seed_prd)
489
+ comate gate "$prd" review >/dev/null
490
+ comate gate "$prd" set score 80 >/dev/null
491
+ run comate gate "$prd" pass
492
+ [ "$status" -eq 1 ]
493
+ [[ "$output" == *"blocking_open"* ]]
494
+ }
495
+
496
+ @test "gate pass blocked when review report missing" {
497
+ local prd; prd=$(seed_prd)
498
+ comate gate "$prd" review >/dev/null
499
+ comate gate "$prd" set score 90 >/dev/null
500
+ comate gate "$prd" set blocking_open 0 >/dev/null
501
+ run comate gate "$prd" pass
502
+ [ "$status" -eq 1 ]
503
+ [[ "$output" == *"report"* ]]
504
+ }
505
+
506
+ @test "gate pass succeeds and check passes after report written" {
507
+ local prd; prd=$(seed_prd)
508
+ comate gate "$prd" review >/dev/null
509
+ comate gate "$prd" set score 90 >/dev/null
510
+ comate gate "$prd" set blocking_open 0 >/dev/null
511
+ printf '# 评审报告\n' > \
512
+ "docs/knowledge-base/requirements/test/PRD-REVIEW-PRD-001-demo.md"
513
+ run comate gate "$prd" pass
514
+ [ "$status" -eq 0 ]
515
+ run comate gate "$prd" check
516
+ [ "$status" -eq 0 ]
517
+ }
518
+
519
+ @test "gate pass --tbd sets passed-with-tbd" {
520
+ local prd; prd=$(seed_prd)
521
+ comate gate "$prd" review >/dev/null
522
+ comate gate "$prd" set score 65 >/dev/null
523
+ comate gate "$prd" set blocking_open 0 >/dev/null
524
+ printf '# 评审报告\n' > \
525
+ "docs/knowledge-base/requirements/test/PRD-REVIEW-PRD-001-demo.md"
526
+ run comate gate "$prd" pass --tbd
527
+ [ "$status" -eq 0 ]
528
+ run comate gate "$prd" status
529
+ [[ "$output" == *"passed-with-tbd"* ]]
530
+ }
531
+
532
+ @test "gate check blocks after PRD modified post-pass (stale)" {
533
+ local prd; prd=$(seed_prd)
534
+ comate gate "$prd" review >/dev/null
535
+ comate gate "$prd" set score 90 >/dev/null
536
+ comate gate "$prd" set blocking_open 0 >/dev/null
537
+ printf '# 评审报告\n' > \
538
+ "docs/knowledge-base/requirements/test/PRD-REVIEW-PRD-001-demo.md"
539
+ comate gate "$prd" pass >/dev/null
540
+ # mutate PRD after passing
541
+ printf '\n额外内容\n' >> "$prd"
542
+ run comate gate "$prd" check
543
+ [ "$status" -eq 1 ]
544
+ [[ "$output" == *"stale"* ]] || [[ "$output" == *"hash mismatch"* ]]
545
+ }
546
+
547
+ @test "gate status reports stale on hash drift without mutating file" {
548
+ local prd; prd=$(seed_prd)
549
+ comate gate "$prd" review >/dev/null
550
+ comate gate "$prd" set score 90 >/dev/null
551
+ comate gate "$prd" set blocking_open 0 >/dev/null
552
+ printf '# 评审报告\n' > \
553
+ "docs/knowledge-base/requirements/test/PRD-REVIEW-PRD-001-demo.md"
554
+ comate gate "$prd" pass >/dev/null
555
+ printf '\n改动\n' >> "$prd"
556
+ run comate gate "$prd" status
557
+ [ "$status" -eq 0 ]
558
+ [[ "$output" == *"stale"* ]]
559
+ # gate.yaml should still say passed (status is computed, not written by status cmd)
560
+ local gate="docs/knowledge-base/requirements/test/PRD-001-demo.gate.yaml"
561
+ local stored; stored=$(grep '^gate_status:' "$gate" | awk '{print $2}')
562
+ [ "$stored" = "passed" ]
563
+ }
564
+
565
+ @test "gate spawned records change name in spawned_changes" {
566
+ local prd; prd=$(seed_prd)
567
+ comate gate "$prd" review >/dev/null
568
+ comate gate "$prd" set score 90 >/dev/null
569
+ comate gate "$prd" set blocking_open 0 >/dev/null
570
+ printf '# 报告\n' > \
571
+ "docs/knowledge-base/requirements/test/PRD-REVIEW-PRD-001-demo.md"
572
+ comate gate "$prd" pass >/dev/null
573
+ run comate gate "$prd" spawned login-flow
574
+ [ "$status" -eq 0 ]
575
+ local gate="docs/knowledge-base/requirements/test/PRD-001-demo.gate.yaml"
576
+ local sc; sc=$(grep '^spawned_changes:' "$gate" | sed 's/spawned_changes: //')
577
+ [[ "$sc" == *"login-flow"* ]]
578
+ }
579
+
580
+ @test "gate spawned appends second change comma-joined" {
581
+ local prd; prd=$(seed_prd)
582
+ comate gate "$prd" review >/dev/null
583
+ comate gate "$prd" set score 90 >/dev/null
584
+ comate gate "$prd" set blocking_open 0 >/dev/null
585
+ printf '# 报告\n' > \
586
+ "docs/knowledge-base/requirements/test/PRD-REVIEW-PRD-001-demo.md"
587
+ comate gate "$prd" pass >/dev/null
588
+ comate gate "$prd" spawned login-flow >/dev/null
589
+ comate gate "$prd" spawned logout-flow >/dev/null
590
+ local gate="docs/knowledge-base/requirements/test/PRD-001-demo.gate.yaml"
591
+ local sc; sc=$(grep '^spawned_changes:' "$gate" | sed 's/spawned_changes: //')
592
+ [[ "$sc" == *"login-flow"* ]]
593
+ [[ "$sc" == *"logout-flow"* ]]
594
+ }
595
+
596
+ @test "gate status returns none when gate does not exist" {
597
+ mkdir -p docs/knowledge-base/requirements/test
598
+ run comate gate "docs/knowledge-base/requirements/test/PRD-001-demo.md" status
599
+ [ "$status" -eq 0 ]
600
+ [[ "$output" == *"none"* ]]
601
+ }
602
+
603
+ @test "gate unknown subcommand returns usage error" {
604
+ local prd; prd=$(seed_prd)
605
+ run comate gate "$prd" frobnicate
606
+ [ "$status" -eq 2 ]
607
+ }
608
+
609
+ @test "gate review re-opens reviewing when PRD changes after pass" {
610
+ local prd; prd=$(seed_prd)
611
+ comate gate "$prd" review >/dev/null
612
+ comate gate "$prd" set score 90 >/dev/null
613
+ comate gate "$prd" set blocking_open 0 >/dev/null
614
+ printf '# 报告\n' > \
615
+ "docs/knowledge-base/requirements/test/PRD-REVIEW-PRD-001-demo.md"
616
+ comate gate "$prd" pass >/dev/null
617
+ printf '\n改动\n' >> "$prd"
618
+ # re-run review after PRD change — should reset to reviewing
619
+ run comate gate "$prd" review
620
+ [ "$status" -eq 0 ]
621
+ run comate gate "$prd" status
622
+ [[ "$output" == *"reviewing"* ]]
623
+ }
624
+
625
+ @test "gate set rejects unknown field" {
626
+ local prd; prd=$(seed_prd)
627
+ comate gate "$prd" review >/dev/null
628
+ run comate gate "$prd" set nonexistent_field foo
629
+ [ "$status" -eq 2 ]
630
+ }
631
+
632
+ @test "gate set rejects invalid gate_status value" {
633
+ local prd; prd=$(seed_prd)
634
+ comate gate "$prd" review >/dev/null
635
+ run comate gate "$prd" set gate_status flying
636
+ [ "$status" -eq 2 ]
637
+ }
638
+
639
+ @test "gate status --json emits json with status field" {
640
+ local prd; prd=$(seed_prd)
641
+ comate gate "$prd" review >/dev/null
642
+ run comate gate "$prd" status --json
643
+ [ "$status" -eq 0 ]
644
+ [[ "$output" == *'"status"'* ]]
645
+ [[ "$output" == *'"reviewing"'* ]]
646
+ }
@@ -0,0 +1,185 @@
1
+ ---
2
+ name: comate-grill
3
+ description: "决策点穷追式澄清工具。对计划/设计/PRD 问题进行深度优先遍历,逐个决策点给推荐答案并等用户确认,直到所有歧义清零。可由 comate-intake 内部调用,或用户直接 /comate-grill 使用。"
4
+ ---
5
+
6
+ # comate-grill —— 决策点穷追式澄清
7
+
8
+ **定位**:一个通用的决策澄清引擎,用于在计划/设计/需求阶段对模糊点、依赖链、歧义进行**逐个深挖**,直到所有分支清晰。
9
+
10
+ **算法来源**:改编自社区 [grill-me pattern](https://github.com/mattpocock/skills/blob/main/skills/productivity/grill-me/)(Timothy Vang、Matt Pocock 等贡献的最佳实践),内化到 comate 家族以避免外部依赖漂移。
11
+
12
+ ---
13
+
14
+ ## 核心算法(四条铁律)
15
+
16
+ 1. **决策树深度优先遍历**
17
+ 串行解决决策点,不批量轰炸。后续分支常依赖前面的答案,所以必须一个接一个。
18
+
19
+ 2. **每个问题附推荐答案**
20
+ 不是裸问题("你觉得 X 怎么设计?"),而是"我建议用 Y 方案,因为 Z 理由。你同意吗?如果不同意,你倾向什么?"
21
+
22
+ 3. **优先探索代码库/文档,不问能查到的事实**
23
+ - 已有架构约定、字段定义、接口规范、对接档案 → 用 Read/Grep/Glob/LSP 核实,引用来源,不丢给用户。
24
+ - 产品决策(范围、优先级、用户行为、状态流转、数据口径、失败处理、验收规则)→ 必须问用户。
25
+
26
+ 4. **一次一问,等回答再进下一个**
27
+ 并行提多个问题会让用户不知从哪答起,且前面的答案可能让后面的问题失效。
28
+
29
+ ---
30
+
31
+ ## 调用场景
32
+
33
+ ### 由其他 skill 内部调用(主场景)
34
+
35
+ - **comate-intake 步骤 3(阻断闸门)**:当 PRD 阻断问题 > 3 个或有决策依赖链时,用户可选「深度澄清模式」,此时 intake 调用本 skill,传入阻断问题清单,逐个深挖。
36
+ - **未来扩展**:comate-design 的方案澄清、comate-verify 的验收标准澄清等,都可复用本 skill。
37
+
38
+ **调用方式**(从其他 skill 内):
39
+
40
+ ```markdown
41
+ 用 Skill 工具加载 `comate-grill`,传入:
42
+
43
+ 话题:<要澄清的主题,如「PRD 阻断问题清单」>
44
+ 问题列表:
45
+ 1. [ID] 问题描述 | 原文依据 | 影响范围 | 当前歧义
46
+ 2. ...
47
+ ```
48
+
49
+ ### 用户直接调用
50
+
51
+ 用户可以在任何阶段直接 `/comate-grill <话题>` 对计划、设计、决策进行穷追式澄清。适用于:
52
+
53
+ - 自己的计划草稿想被挑战一遍
54
+ - 技术方案有多个路径,想逐条过一遍利弊
55
+ - PRD/需求文档的边界不清楚,想被问到无死角
56
+
57
+ ---
58
+
59
+ ## 工作流
60
+
61
+ ### 输入
62
+
63
+ - **话题**:澄清的主题(如「PRD 阻断问题」「技术选型」「API 设计」)
64
+ - **问题列表**(可选,无则从话题自由展开):带 ID、描述、依据、影响的问题清单
65
+
66
+ ### 过程
67
+
68
+ 1. **建决策树骨架**
69
+ 根据问题列表(或从话题展开)识别所有决策点,按依赖关系排序(前面的决策会影响后面的选项)。
70
+
71
+ 2. **逐点深挖**
72
+ 从第一个决策点开始:
73
+ - 先查代码库/文档/架构约定能否直接回答(能则引用来源,告知用户,进入下一个)
74
+ - 不能则构造推荐答案:2–3 个互斥选项 + 推荐项 + 理由 + 各选项的后果
75
+ - 用 **AskUserQuestion** 提问,等用户回答
76
+ - 记录答案,更新后续决策点的前置条件
77
+
78
+ 3. **递归展开新分支**
79
+ 用户的回答可能引出新的子问题(如选了"分布式事务"就要问"补偿机制怎么设计")。把新问题插入决策树对应位置,继续深挖。
80
+
81
+ 4. **终止条件**
82
+ 所有决策点都有明确答案(非"待定""看情况"),或用户主动喊停。
83
+
84
+ ### 输出
85
+
86
+ - **决策台账**(markdown 表格):每个问题的 ID、问题、推荐、用户答案、依据/来源
87
+ - **待办事项**(若有):哪些答案需要后续在代码/文档中落地
88
+
89
+ ---
90
+
91
+ ## Guardrails
92
+
93
+ - **AskUserQuestion 是真阻塞点**:推荐答案、默认值、"通常做法"、历史偏好都不能替代用户明确回答。只有用户选了选项或输入自定义答案,才能进入下一个决策点。
94
+ - **不替用户拍板**:可以给建议、列利弊、引用案例,但最终选择必须等用户确认。
95
+ - **不问能查到的事实**:已有的架构文档、代码约定、接口规范先用工具核实,只问"怎么做"的决策,不问"是什么"的事实。
96
+ - **分支依赖显式标注**:后续问题若依赖前面的答案,在提问时点明"因为你选了 X,所以这里...",让用户理解为什么要问这个。
97
+ - **深度有限,避免无底洞**:单个决策点最多展开 2 层子问题。若发现需要第 3 层,说明原问题拆得不够,停下来重新拆解问题本身。
98
+
99
+ ---
100
+
101
+ ## 示例
102
+
103
+ **输入**(由 comate-intake 调用):
104
+
105
+ ```
106
+ 话题:PRD 门禁阻断问题清单
107
+ 问题列表:
108
+ 1. [B-03] 用户登录失败后的重试机制未明确 | 原文"支持登录" | 影响:异常路径、用户体验
109
+ 2. [B-07] 数据同步到第三方失败时的降级策略缺失 | 原文"对接外部 API" | 影响:可用性、数据一致性
110
+ 3. [B-11] 管理员权限范围模糊(能否删除其他管理员的数据?)| 原文"管理员可管理所有数据" | 影响:权限设计、安全
111
+ ```
112
+
113
+ **执行**:
114
+
115
+ 1. **问题 1(登录重试)**
116
+ - 先查现有登录模块代码:发现有 `max_retries` 配置但未用
117
+ - 给推荐:"我建议限制 5 次/15 分钟,超过后锁定账户 30 分钟并发邮件通知,理由是防暴力破解。你同意吗?"
118
+ - 用户答:"改成 3 次/10 分钟,锁定 1 小时"
119
+ - 记录,进入下一个
120
+
121
+ 2. **问题 2(第三方失败降级)**
122
+ - 查架构文档:无降级策略先例
123
+ - 给推荐:"我建议失败后写本地队列,定时重试 3 次,3 次后人工介入。你倾向什么?"
124
+ - 用户答:"可以,但重试间隔用指数退避"
125
+ - 追问:"指数退避的初始间隔和最大间隔?"(新分支)
126
+ - 用户答:"初始 30s,最大 10min"
127
+ - 记录,进入下一个
128
+
129
+ 3. **问题 3(管理员权限)**
130
+ - 查权限表和现有角色定义:只有 `admin` 和 `user` 两角色
131
+ - 给推荐:"建议引入超级管理员(super_admin)和普通管理员(admin),普通管理员不能删除其他管理员的数据。你同意吗?"
132
+ - 用户答:"不需要超级管理员,所有管理员平级,但删除操作需二次确认"
133
+ - 记录
134
+
135
+ **输出**:
136
+
137
+ ```markdown
138
+ ## 决策台账
139
+
140
+ | ID | 问题 | 推荐 | 用户答案 | 依据/来源 |
141
+ |-------|------|------|----------|-----------|
142
+ | B-03 | 登录重试机制 | 5次/15分钟,锁定30分钟 | 3次/10分钟,锁定1小时 | 用户确认 |
143
+ | B-07 | 第三方失败降级 | 本地队列+定时重试3次 | 同意,重试用指数退避(30s→10min) | 用户确认 |
144
+ | B-11 | 管理员权限范围 | 引入super_admin和admin两级 | 不分级,删除操作二次确认 | 用户确认 |
145
+
146
+ 所有阻断问题已澄清,可更新 PRD 评审报告并置 `blocking_open=0`。
147
+ ```
148
+
149
+ ---
150
+
151
+ ## 与 comate 其他 skill 的区别
152
+
153
+ | skill | 定位 | 提问方式 |
154
+ |-------|------|----------|
155
+ | **comate-grill** | 决策点穷追引擎,逐个深挖直到无歧义 | 深度优先、一次一问、附推荐 |
156
+ | comate-intake | PRD 门禁+拆分,暴露问题但不深挖每个 | 批量扫描+分轮处理 |
157
+ | openspec-explore | 探索问题空间,发散式头脑风暴 | 开放式、多角度、不强制收敛 |
158
+ | comate-design | 技术设计+方案 brainstorming | 方案对比、架构决策、不逐点穷举 |
159
+
160
+ **简单说**:explore 是发散、grill 是收敛、intake 是门禁、design 是方案对比。grill 的独特价值是"不放过任何一个模糊点"。
161
+
162
+ ---
163
+
164
+ ## 何时用 comate-grill
165
+
166
+ **推荐用**:
167
+ - 阻断问题 > 3 个且有依赖链(intake 自动提供选项)
168
+ - 技术方案有多条路径,想逐条过利弊(design 阶段手动调用)
169
+ - 自己的计划草稿想被挑战到无死角(用户直接 `/comate-grill <话题>`)
170
+
171
+ **不推荐用**:
172
+ - 简单问题(≤ 2 个独立决策点)→ 直接 AskUserQuestion 即可
173
+ - 纯事实查询("这个字段在哪张表")→ 用 Read/Grep/LSP
174
+ - 开放式头脑风暴("有哪些可能的方案")→ 用 openspec-explore
175
+
176
+ ---
177
+
178
+ ## 维护说明
179
+
180
+ 本 skill 是社区最佳实践的内化版本,避免外部依赖漂移。若社区 grill-me 有新算法改进,可在此同步更新,但保持 comate 命名空间和中文文档风格。
181
+
182
+ **来源致谢**:
183
+ - [mattpocock/skills - grill-me](https://github.com/mattpocock/skills/blob/main/skills/productivity/grill-me/SKILL.md)
184
+ - [gsarig/skills - grill-me](https://github.com/gsarig/skills/blob/main/skills/grill-me/README.md)
185
+ - [RobMitt/grill-me-skill](https://github.com/RobMitt/grill-me-skill)
@@ -0,0 +1,222 @@
1
+ ---
2
+ name: comate-intake
3
+ description: "comate 阶段 0:PRD 门禁与拆分。用 /comate-intake 调用。对原始 PRD 做质量审阅+评分+阻断闸门,通过后按依赖/独立性判定拆成 1 或 N 个 change,逐个交给 comate-open。门禁状态钉在 PRD 同级 <PRD>.gate.yaml,门禁未通过禁止建 change。"
4
+ ---
5
+
6
+ # comate 阶段 0:PRD 门禁与拆分(Intake)
7
+
8
+ **定位**:comate 五阶段(open→design→build→verify→archive)之前的上游入口。输入一份**原始 PRD**,产出「已过门禁、已拆分」的 N 个 change,各自进入 open 阶段。
9
+
10
+ **两件事,缺一不可**:
11
+ 1. **门禁**:审阅 PRD 质量、百分制评分、建阻断台账。阻断问题未清零,**禁止建任何 change**。
12
+ 2. **拆分**:按依赖/整体性/独立性/规模判定该 PRD 变成几个 change,粒度由用户拍板(AI 只给建议)。
13
+
14
+ **FRD 层已消解**:不再产独立 FRD 文档。PRD 直接作为 change 的源文档被 `sources track` 钉住,其内容顺着 open→design 流进 comate 原生产物(proposal / design / tasks)。
15
+
16
+ ---
17
+
18
+ ## 核心铁律
19
+
20
+ - **门禁状态是可验证的文件真相源**:钉在 PRD 同级 `<PRD>.gate.yaml`。评审报告 `PRD-REVIEW-<PRD名>.md` 是给人看的派生物,**不是**状态源。
21
+ - **AskUserQuestion 是真阻塞点**:文字提示、推荐方案、默认值、历史偏好、用户未反对,都**不能**替代明确回答。
22
+ - **只审不改**:门禁只暴露 PRD 问题,不替 PRD 补内容、不替产品拍板。
23
+ - **门禁未通过禁止建 change**:`gate_status ∈ {passed, passed-with-tbd}` 且 PRD 哈希未漂移,才允许 comate-open 建 change(由 `gate check` 硬强制)。
24
+ - **拆分粒度由人定**:AI 给「功能项→change」映射建议,用户确认或改,AI 不拍板。
25
+
26
+ ---
27
+
28
+ ## 脚本定位(单一入口)
29
+
30
+ ```bash
31
+ COMATE="${COMATE:-$(for r in . ./.claude/skills "$HOME"/.claude/skills "$HOME"/.config/skills "$HOME"/.cursor/skills; do
32
+ [ -d "$r" ] && find "$r" -maxdepth 6 -path '*/comate/scripts/comate.sh' -type f -print -quit 2>/dev/null
33
+ done | head -1)}"
34
+ if [ -z "$COMATE" ]; then
35
+ echo "ERROR: comate.sh 未找到,请确认 comate skill 已安装。" >&2
36
+ return 1 2>/dev/null || exit 1
37
+ fi
38
+ ```
39
+
40
+ gate 命令族(退出码:`0` 通过 / `1` 阻塞 / `2` 用法 / `3` 环境 / `4` 状态损坏):
41
+
42
+ ```bash
43
+ bash "$COMATE" gate <prd> review # 建/刷新 gate.yaml,钉 PRD 哈希,回报告路径
44
+ bash "$COMATE" gate <prd> set <field> <value> # 写 score | blocking_open | gate_status
45
+ bash "$COMATE" gate <prd> pass [--tbd] # 置 passed(要求 blocking_open=0 且报告非空)
46
+ bash "$COMATE" gate <prd> spawned <change> # 记录据此 PRD 扇出的 change
47
+ bash "$COMATE" gate <prd> status [--json] # 查状态(哈希漂移自动判 stale)
48
+ bash "$COMATE" gate <prd> check # comate-open 建 change 前的前置守卫
49
+ ```
50
+
51
+ ---
52
+
53
+ ## 步骤
54
+
55
+ ### 1. 定位 PRD
56
+
57
+ - 用户给了路径/编号 → 直接读该文件。
58
+ - 未给 → 用 Glob 列出候选(默认约定 `docs/knowledge-base/requirements/**/PRD-*.md`,若项目无此结构,探测 `docs/**/*.md` 中文件名含 `PRD`/`需求` 的),用 **AskUserQuestion** 让用户选一个。
59
+ - 读取后重点提取:**功能清单**(各功能项 + 优先级 P0/P1/P2)、**范围(In/Out)**、**第三方依赖**、**验收标准**、文档状态。
60
+ - 若 PRD 明显未定稿(状态字段非「已定稿」等),用 **AskUserQuestion** 提示可能未冻结并暂停确认;确认前只审阅,不建 gate。
61
+
62
+ ### 2. 门禁:质量审阅 + 评分(不可跳过)
63
+
64
+ 先初始化 gate(钉当前 PRD 哈希、拿到报告路径):
65
+
66
+ ```bash
67
+ bash "$COMATE" gate <prd> review
68
+ ```
69
+
70
+ **逐维度排查**(每条既看「有没有」,也看「清不清楚、能不能落地」):
71
+
72
+ | 维度 | 查什么 |
73
+ |------|--------|
74
+ | 逻辑自洽 | 需求前后是否矛盾;流程有无断链;条件/分支是否闭合;功能项间是否冲突或重复 |
75
+ | 数据与来源 | 用到的数据是否交代来源(哪张表/哪个接口/哪方提供);口径/单位/时间范围是否明确 |
76
+ | 边界与范围 | In/Out 是否清晰;极值、空值、并发、权限、异常路径是否覆盖;第三方失败/降级是否提及 |
77
+ | 表述清晰 | 术语是否一致且有定义;有无「尽快/大量/若干」等模糊量词;验收是否可度量 |
78
+ | 完整性 | 目标/背景、功能清单、优先级、验收标准、第三方依赖是否齐全;有无 TBD/待定 |
79
+
80
+ **每个问题标严重程度三档:**
81
+ - **严重**(扣 15 分):阻断开发或导致做错方向(逻辑矛盾、关键数据无来源、核心边界缺失、需求自相冲突)。
82
+ - **中**(扣 7 分):影响实现质量或需返工(口径不清、部分异常路径未覆盖、验收不可度量)。
83
+ - **低**(扣 2 分):表述瑕疵、术语不统一、可读性问题,不影响方向。
84
+
85
+ **评分**(百分制,从 100 扣,扣到 0 为止):≥85 优(可拆)、70–84 良(可拆,受影响处标待确认)、<70 待补(建议先补 PRD)。
86
+
87
+ **先分流再提问**:
88
+ - **仓库事实**(已有架构约定、字段、接口、对接档案):先用 Read/Glob/rg 核实并引用来源,不丢给用户决定。
89
+ - **产品决策**(范围、优先级、用户可见行为、状态流转、权限、数据口径、失败处理、验收规则):必须用 **AskUserQuestion** 问用户,不得用推荐方案/历史偏好/「待确认」代替确认。
90
+
91
+ **写评审报告(必生成)** 到 `gate review` 回显的 `review_report` 路径(PRD 同级 `PRD-REVIEW-<PRD名>.md`)。内容含:评分 + 评级 + 一句话总评、问题台账表(`ID` / 维度 / 严重程度 / 原文依据 / 影响章节 / 是否阻断 / 建议 / 产品回填列)、逐条问题。若无问题,明确写「审阅通过,未发现阻断项」。
92
+
93
+ **阻断规则**:影响范围、用户行为、状态流转、数据契约、权限、异常处理或验收标准的问题标「阻断」。把当前未关闭的阻断问题数写入 gate:
94
+
95
+ ```bash
96
+ bash "$COMATE" gate <prd> set score <分数>
97
+ bash "$COMATE" gate <prd> set blocking_open <未关闭阻断数>
98
+ ```
99
+
100
+ ### 3. 阻断闸门(AskUserQuestion)
101
+
102
+ **若 `blocking_open > 0`**,先判定复杂度:
103
+
104
+ - **阻断数 ≤ 3 且无明显依赖链** → 默认模式(批量+分轮处理)
105
+ - **阻断数 > 3 或存在决策依赖链** → 提供深度澄清选项
106
+
107
+ #### 默认模式(阻断数 ≤ 3)
108
+
109
+ 用 **AskUserQuestion** 暂停,给三选项(文字提示不能替代工具等待):
110
+ 1. **先补 PRD** — 让用户/产品补齐,补后回步骤 2 重新审阅(`gate review` 会因 PRD 改动重钉哈希、状态回 reviewing)。
111
+ 2. **授权带 TBD 继续** — 用户显式授权。此时后续 change 的 proposal/design 受影响处必须标 **「⚠ 待确认」** 并引用评审报告。
112
+ 3. **暂停** — 停在此,不建 change。
113
+
114
+ 对每轮最多 1–3 个高影响决策提问;每个问题给 `ID`、原文依据、影响、2–3 个互斥选项、推荐项及后果,允许自定义答案。用户回答后更新报告台账、重算 `blocking_open`,直到清零或用户选 2。
115
+
116
+ #### 复杂场景模式(阻断数 > 3 或有依赖链)
117
+
118
+ 用 **AskUserQuestion** 暂停,给四选项:
119
+ 1. **先补 PRD** — 同上。
120
+ 2. **授权带 TBD 继续** — 同上。
121
+ 3. **深度澄清模式** — 调用 `comate-grill` skill 逐决策点穷追式澄清。适合复杂 PRD,更彻底但耗时更长。
122
+ 4. **暂停** — 停在此,不建 change。
123
+
124
+ **若用户选 3(深度澄清)**:
125
+
126
+ 1. **立即执行**:使用 Skill 工具加载 `comate-grill`,传入话题和阻断问题清单:
127
+
128
+ ```markdown
129
+ 话题:PRD 门禁阻断问题清单
130
+ 问题列表:
131
+ [逐条列出所有 blocking_open > 0 的问题,每条含:ID、问题描述、原文依据、影响范围、当前歧义]
132
+ ```
133
+
134
+ 2. `comate-grill` 会逐个决策点深挖,每个问题附推荐答案,等用户确认后进入下一个,直到所有分支清晰。
135
+
136
+ 3. 完成后更新评审报告台账、重算 `blocking_open`。若依然未清零,回到本步骤 3 再次判定(通常经过深度澄清后会清零)。
137
+
138
+ **只有 `blocking_open` 清零、或用户选 2 授权,才进入步骤 4。**
139
+
140
+ ### 4. 拆分判定(必须 AskUserQuestion 问人)
141
+
142
+ 列出 PRD 功能清单各功能项及优先级,AI 按下列维度**给拆分建议**(不拍板):
143
+
144
+ - **依赖关系**:前后依赖的功能项归**同一** change。
145
+ - **整体性**:共同构成一个完整用户价值的功能簇归**同一** change。
146
+ - **独立性**:互不依赖、可并行实现的功能项拆成**独立** change。
147
+ - **规模**:功能点少(≤3)且简单 → **1 个** change 即可;复杂多点(>5)且可切分 → **多个** change。
148
+
149
+ 产出「功能项 → change」映射建议,例如:
150
+
151
+ ```
152
+ 建议拆分:
153
+ - Change A「核心登录流」:功能项 1、2、3(有依赖链,整体交付)
154
+ - Change B「运营配置」:功能项 4、5(独立,可与 A 并行)
155
+ - Change C「数据报表」:功能项 6(独立后置)
156
+ ```
157
+
158
+ 用 **AskUserQuestion**(可多选/自定义)让用户确认:
159
+ - 哪些功能项归哪个 change(显示建议映射);
160
+ - 是一功能项一 change 还是合并;
161
+ - 各 change 命名(默认取主功能项名,用户可改)。
162
+
163
+ **映射确认前不得建任何 change。** 确认后用 **TodoWrite** 把每个待建 change 建成任务项。
164
+
165
+ ### 5. 通过门禁
166
+
167
+ 映射与 `blocking_open` 都就绪后,置门禁通过:
168
+
169
+ ```bash
170
+ bash "$COMATE" gate <prd> pass # 阻断已清零
171
+ # 或用户授权带 TBD:
172
+ bash "$COMATE" gate <prd> pass --tbd
173
+ ```
174
+
175
+ `pass` 会硬校验 `blocking_open=0` 且报告非空,并重钉 PRD 哈希——之后 PRD 再被改,哈希漂移会使门禁 `stale`,须重跑 `/comate-intake`。
176
+
177
+ ### 6. 逐 Change 初始化(调 comate-open)
178
+
179
+ 对映射里每个 change,逐个调用 comate-open。**每次都在 change 描述里点明**:本 change 承接 PRD 的哪些功能项、范围边界、以及(多 change 时)相邻职责归哪个 change(In/Out 显式互引,防重复防遗漏)。
180
+
181
+ **立即执行**:用 Skill 工具加载 `comate-open`,传入 change 名与来源 PRD。comate-open 内部会:
182
+ - 先跑 `gate check <prd>` 前置守卫(未通过则阻断);
183
+ - 生成 proposal.md(范围/目标/非目标承接该 change 的功能项,不脱离 PRD 另起炉灶);
184
+ - `sources track <prd>` 钉住 PRD 为源(`source_kind=file`);
185
+ - design.md / tasks.md 由后续 comate-design 细化。
186
+
187
+ 每建成一个,记录到门禁:
188
+
189
+ ```bash
190
+ bash "$COMATE" gate <prd> spawned <change-name>
191
+ ```
192
+
193
+ 若门禁是 `passed-with-tbd`,在该 change 的 proposal/design 受影响处标 **「⚠ 待确认」** 并引用评审报告。
194
+
195
+ 多 change 时,在 PRD 同目录建 `CHANGES-MAP.md` 记录「功能项 → change」映射,便于回溯。
196
+
197
+ ### 7. 收尾
198
+
199
+ 展示:
200
+ - PRD 审阅评分 + 评级、阻断问题关闭情况;
201
+ - 评审报告路径、gate.yaml 路径与最终 `gate_status`;
202
+ - 拆分映射(功能项 → N 个 change);
203
+ - 已建的 change 列表(名称 + 承接功能项 + 是否带 ⚠ TBD);
204
+ - 待用户补的字段(如技术负责人)。
205
+
206
+ 提示:「已过门禁并创建 N 个 change。对每个 change 调用 `/comate` 继续 design→build→verify→archive。」
207
+
208
+ ---
209
+
210
+ ## Guardrails
211
+
212
+ - 生成 change 前必先过门禁并评分(步骤 2),不可跳过;审阅只暴露问题、不替 PRD 补内容。
213
+ - 评审报告**必生成**,不再询问是否生成。
214
+ - 门禁状态以 `<PRD>.gate.yaml` 为唯一真相源;报告是人类可读派生物,二者冲突以 gate.yaml 为准。
215
+ - 影响范围、用户行为、状态流转、数据契约、权限、异常处理或验收标准的歧义必须逐项确认;未清零只能停在 reviewing/blocked,或经用户授权走 passed-with-tbd(带 ⚠ 标记)。
216
+ - AskUserQuestion 是真实阻塞点:文字输出/推荐/默认值/历史选择/用户未反对都不能替代明确回答。
217
+ - 拆分粒度(1 PRD → 几个 change)由用户定,AI 只给建议不拍板。
218
+ - 每个 change 承接 PRD 对应功能项,不另起炉灶;范围/依赖/验收与 PRD 对齐。
219
+ - 多 change 时在各 change 的 In/Out Scope 显式互引边界职责归属。
220
+ - 门禁通过后 PRD 若被改(哈希漂移),gate 转 stale,禁止再扇出 change,须重跑本 skill。
221
+ - 契约以项目架构文档(如 `docs/architecture/`,若存在)为事实源,change 里点名遵循了哪条,不硬编码具体值、不自造。
222
+ - 不写应用代码——本 skill 止于「过门禁 + 拆分 + 建 change 骨架」,实现由后续 comate 阶段驱动。
@@ -0,0 +1,36 @@
1
+ # docs 文档目录说明
2
+
3
+ 本目录承载项目的长期文档,与代码同仓库、同评审、同版本管理。按用途分为以下几类:
4
+
5
+ | 子目录 | 定位 | 说明 |
6
+ |--------|------|------|
7
+ | `architecture/` | 架构规范 | 前后端分层、依赖规则、命名、错误码等工程铁律,以仓库**当前实现**为准 |
8
+ | `knowledge-base/` | 知识库 | 上游需求(PRD)与横向(第三方对接)的长期文档,详见其内 `README.md` |
9
+
10
+ ## architecture/
11
+
12
+ 工程约束的唯一来源,是 `/comate-intake` PRD 门禁审阅中「契约对齐」的事实源。改对应层代码前必须先读。
13
+
14
+ **占位目录,需根据项目实际情况建立规范文档**。常见架构文档包含:
15
+
16
+ - 后端分层 / 依赖 / DTO / 错误码 / 命名。
17
+ - 前端分层 / API / store / 路由 / 命名。
18
+ - 工程原则与铁律。
19
+
20
+ > 这些是**架构规则文档,不是 capability spec**,不放在 `openspec/specs/` 下,也不参与 `openspec validate --strict`。
21
+ > 调整架构相关代码时,必须同步更新对应文档。
22
+
23
+ ## knowledge-base/
24
+
25
+ 需求与第三方对接的长期文档,是 comate 变更流程的上游:
26
+
27
+ - `requirements/` —— 原始 PRD(产品需求文档)。PRD 经 `/comate-intake` 门禁与拆分后,扇出为 N 个 comate change。
28
+ - `integrations/` —— 第三方业务/接口对接档案与索引,跨多个变更长期维护。
29
+
30
+ 完整的命名规则、溯源约定与铁律见 `knowledge-base/README.md`。
31
+
32
+ ## 与 openspec/ 的边界
33
+
34
+ - `docs/` 放**长期文档**(架构规范、需求、对接档案)。
35
+ - `openspec/` 放**变更驱动的规格**:`changes/`(一次性变更)与 `specs/`(能力沉淀)。
36
+ - 两者通过 PRD 门禁状态(`<PRD>.gate.yaml`)与 change 的 `sources.manifest` 打通。