@andyqiu/codeforge 0.3.12 → 0.3.13

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/install.sh CHANGED
@@ -395,6 +395,15 @@ uninstall() {
395
395
  fi
396
396
  done
397
397
  hr
398
+ # 细粒度删除 skills:只删 CodeForge 自己的 skill,不删用户自装的(如 frontend-design)
399
+ OWNED_SKILLS=(ambiguity-gate devils-advocate ears-zh example-mapping success-criteria weighted-dimensions)
400
+ for skill_name in "${OWNED_SKILLS[@]}"; do
401
+ local p="$TARGET_ROOT/skills/$skill_name"
402
+ if [[ -e "$p" || -L "$p" ]]; then
403
+ run "rm -rf '$p'"
404
+ ok "已删除 skill: $p"
405
+ fi
406
+ done
398
407
  ok "卸载完成(opencode 自身和你的 AGENTS.md / ~/.config/codeforge/kh.json 不会被动)"
399
408
  }
400
409
 
@@ -524,6 +533,30 @@ for entry in "${COPY_DIRS[@]}"; do
524
533
  ok "$src_name/ → $dst_path (整目录拷贝)"
525
534
  done
526
535
 
536
+
537
+ # Step 5b/8: 装 skills/(opencode skill 目录:~/.config/opencode/skills/ 或 .opencode/skills/)
538
+ # skills/ 在项目顶级,git 追踪,npm 包含。安装时整目录 rsync 到 target。
539
+ # 细粒度 uninstall:只删 CodeForge 自己的 skill 子目录,不碰用户自装的其他 skill。
540
+ log "Step 5b/8: 装 skills/"
541
+ SKILLS_SRC="$SOURCE_ROOT/skills"
542
+ SKILLS_DST="$TARGET_ROOT/skills"
543
+ if [[ -d "$SKILLS_SRC" ]]; then
544
+ ensure_dir "$SKILLS_DST"
545
+ skill_count=0
546
+ while IFS= read -r skill_dir; do
547
+ skill_name="$(basename "$skill_dir")"
548
+ dst_skill="$SKILLS_DST/$skill_name"
549
+ if [[ -e "$dst_skill" || -L "$dst_skill" ]]; then
550
+ run "rm -rf '$dst_skill'"
551
+ fi
552
+ run "cp -R '$skill_dir' '$dst_skill'"
553
+ skill_count=$((skill_count + 1))
554
+ done < <(find "$SKILLS_SRC" -mindepth 1 -maxdepth 1 -type d)
555
+ ok "skills/ → $SKILLS_DST ($skill_count 个 skill)"
556
+ else
557
+ warn "skills/ 目录不存在,跳过(发布包未含 skills)"
558
+ fi
559
+
527
560
  # Step 6/8: AGENTS.md 智能合并(仅项目模式)
528
561
  log "Step 6/8: AGENTS.md 智能合并"
529
562
  if [[ "$MODE" == "project" ]]; then
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andyqiu/codeforge",
3
- "version": "0.3.12",
3
+ "version": "0.3.13",
4
4
  "description": "CodeForge — opencode 的零侵入扩展包",
5
5
  "type": "module",
6
6
  "private": false,
@@ -39,6 +39,10 @@
39
39
  "test": "vitest run",
40
40
  "test:watch": "vitest",
41
41
  "test:coverage": "vitest run --coverage",
42
+ "test:discover:sycophancy": "vitest run tests/discover/run-sycophancy-check.test.ts",
43
+ "test:discover:score": "node tests/discover/check-score.mjs",
44
+ "test:discover:lexicon": "node tests/discover/check-lexicon.mjs",
45
+ "test:discover": "npm run test:discover:sycophancy && npm run test:discover:score && npm run test:discover:lexicon",
42
46
  "bench": "node --experimental-strip-types --no-warnings ./scripts/bench-repo-map.mjs",
43
47
  "bench:json": "node --experimental-strip-types --no-warnings ./scripts/bench-repo-map.mjs --json",
44
48
  "lint": "tsc --noEmit",
@@ -63,6 +67,7 @@
63
67
  "phases:all": "npm run phase0:check && npm run phase1:check && npm run phase15:check && npm run phase2:check && npm run phase3:check && npm run phase4:check",
64
68
  "sync:models": "node ./scripts/sync-agent-models.mjs",
65
69
  "sync:models:check": "node ./scripts/sync-agent-models.mjs --check",
70
+ "sync": "node ./scripts/sync-agent-models.mjs && node ./scripts/dev-sync.mjs --sync-only",
66
71
  "replay": "node ./scripts/codeforge-replay.mjs",
67
72
  "release": "node ./scripts/release.mjs",
68
73
  "release:dry": "node ./scripts/release.mjs --dry-run",
@@ -114,6 +119,7 @@
114
119
  "commands/",
115
120
  "workflows/",
116
121
  "context-templates/",
122
+ "skills/",
117
123
  "scripts/check-bun.mjs",
118
124
  "scripts/merge-agents-md.mjs",
119
125
  "scripts/sync-agent-models.mjs",
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: ambiguity-gate
3
+ description: OMX 模糊度门控;判断用户输入是否清晰到可进入 Phase B,模糊则要求补充
4
+ metadata:
5
+ owner: codeforge
6
+ group: discover
7
+ version: 1.0.0
8
+ allowed_tools: [read]
9
+ mode: on-demand
10
+ trigger: discover Phase A 入口 / user_intent 漂移
11
+ ---
12
+
13
+ # Ambiguity Gate
14
+
15
+ ## 何时触发
16
+
17
+ 以下三种情况主动调用本 skill:
18
+
19
+ 1. **首次输入**:用户在 `@discover` session 首次发送意图描述时
20
+ 2. **user_intent 漂移**:对话过程中检测到用户意图在 ≥1 个维度发生变化(例如换了目标用户群、扩大了 scope、改变了核心 Job)
21
+ 3. **用户改口**:用户明确说"其实我想要的是……"或前后描述出现矛盾
22
+
23
+ ---
24
+
25
+ ## 门控判定流程(4 步)
26
+
27
+ ### Step 1:识别维度缺失
28
+
29
+ 逐一检查 5 个维度是否在用户输入中有明确信息:
30
+ - **who**:谁在用?(用户群 / 角色)
31
+ - **what**:做什么?(功能目标)
32
+ - **why**:为什么做?(Job / 痛点)
33
+ - **scope**:边界在哪?(本期做什么,不做什么)
34
+ - **criteria**:怎么算成功?(可观测的验收指标)
35
+
36
+ ### Step 2:评分
37
+
38
+ 按下方「模糊度评分表」给 5 个维度各打 0-2 分,累计得出总分(满分 10)。
39
+
40
+ ### Step 3:触发追问
41
+
42
+ - 总分 **< 5**:必须追问,聚焦得分最低的 1-2 个维度
43
+ - 总分 **5-7**:可选追问,若关键维度(who/why)有 0 分则必须补问
44
+ - 总分 **≥ 8**:放行,记录当前 intent snapshot,进入 Phase B
45
+
46
+ ### Step 4:放行条件
47
+
48
+ 满足以下**全部**条件后放行:
49
+ - who ≥ 1(用户群可识别)
50
+ - why ≥ 1(痛点或 Job 描述存在)
51
+ - 总分 ≥ 5
52
+ - 若检测到 user_intent 漂移,必须先向用户确认"你现在想要的是 X 还是 Y?"再放行
53
+
54
+ ---
55
+
56
+ ## 模糊度评分表
57
+
58
+ | 维度 | 0 分 | 1 分 | 2 分 |
59
+ |---|---|---|---|
60
+ | **who** | 完全没提目标用户 | 宽泛描述("用户"/"大家") | 具体角色 + 场景("月结算的财务") |
61
+ | **what** | 只说"做个东西" | 功能方向模糊("做个管理界面") | 功能目标明确("按客户分组导出 PDF") |
62
+ | **why** | 没有痛点 / Job 描述 | 隐约提到不方便 | 明确痛点 + 当前 workaround |
63
+ | **scope** | 没有任何边界 | 只说做什么,未说不做什么 | 明确本期做什么 + 显式排除 |
64
+ | **criteria** | 无验收描述 | 主观描述("用起来方便") | 可观测描述("3 秒内生成,每客户一个文件") |
65
+
66
+ ---
67
+
68
+ ## 追问话术(人话外壳)
69
+
70
+ > 在我把这事儿真正搞清楚之前,有几个地方我还没摸透:
71
+ > - [聚焦得分最低的维度,用业务语言问,不要用维度名称]
72
+
73
+ **示例**(who 维度得 0 分时):
74
+ > "这个功能主要给谁用?是内部财务同学,还是外部客户,还是两边都要?"
75
+
76
+ **示例**(criteria 维度得 0 分时):
77
+ > "怎么算这事儿做成了?有没有一个能量化的指标,比如多少时间内、多少用户用了?"
78
+
79
+ ---
80
+
81
+ ## 输出协议(**禁止向用户展示评分**)
82
+
83
+ 本 skill 完成判定后,**只向 discover agent 返回以下结构**,不得在用户侧展示 0-10 分数:
84
+
85
+ ```json
86
+ {
87
+ "pass": true,
88
+ "missing_dimensions": [],
89
+ "next_question": null
90
+ }
91
+ ```
92
+
93
+ | 字段 | 类型 | 说明 |
94
+ |---|---|---|
95
+ | `pass` | boolean | `true` = 放行进入 Phase B;`false` = 需要继续追问 |
96
+ | `missing_dimensions` | string[] | 得分 0 的维度列表(pass=true 时可为空数组) |
97
+ | `next_question` | string \| null | 下一个追问(pass=false 时必填,使用人话外壳;pass=true 时置 null) |
98
+
99
+ **❌ 禁止返回**:`score` 字段 / 0-10 总分 / 各维度分值 —— 这些是**内部计算中间值**,外露会与 `weighted-dimensions` 的 F/U/T/C/E 评分表混淆,造成 C5 dogfooding 中暴露的「杂交评分」反模式。
@@ -0,0 +1,74 @@
1
+ ---
2
+ name: devils-advocate
3
+ description: 反 sycophancy 强制对抗框架;列举 4 种 combo(A 核心前提不成立 / B 意图冲突 / C 反模式叠加 / D 多轮反对未回应)的识别与对抗策略
4
+ metadata:
5
+ owner: codeforge
6
+ group: discover
7
+ version: 1.0.0
8
+ allowed_tools: [read]
9
+ mode: on-demand
10
+ trigger: discover Phase C 召唤 challenger 前
11
+ ---
12
+
13
+ # Devil's Advocate
14
+
15
+ ## 4 种 Combo 识别表
16
+
17
+ 在 Phase C 召唤 `discover-challenger` 前,按此表识别当前意图中存在的风险 combo,整合进 prompt 传给 challenger:
18
+
19
+ | Combo | 名称 | 触发信号 | 典型话术 |
20
+ |---|---|---|---|
21
+ | **A** | 核心前提不成立 | 用户的整个方案依赖一个未验证的假设,且该假设一旦为假,方案完全失效 | "大家都会用的""这个需求肯定很多人有""用户一定会愿意……" |
22
+ | **B** | 意图冲突 | 当前需求与用户 ≤7 天内说过的话,或与团队 KH 已沉淀决策直接矛盾 | 先说"越简单越好",后加 5 个高级功能;先说"不要改主流程",后要求入侵主链路 |
23
+ | **C** | 反模式叠加 | 全局影响严重(伤生态/主流程)+ 反模式 ≥2 条同时命中 | 内容线性加法/"用户体验更好"作为万能理由/既要又要还要/把 PGC 包装成 UGC |
24
+ | **D** | 多轮反对未回应 | challenger 或 discover 连续 ≥2 轮提出同维度 [严重] 异议,用户未拿出新证据/新场景实质回应 | "先这样吧""你说的有道理,但我们先做再说""这些都不是问题" |
25
+
26
+ ---
27
+
28
+ ## 对抗强度档位
29
+
30
+ | 档位 | 触发条件 | challenger 行为 |
31
+ |---|---|---|
32
+ | **弱(关注)** | 单条 [关注] 级问题,无 combo 命中 | 指出问题 + 建议补充证据;不阻止推进 |
33
+ | **中(警告)** | 1-2 条 [警告] 级问题,或 combo A/B 信号但证据不充分 | 明确列出异议 + 要求 discover 让用户正面回应;可继续下一步但标记 |
34
+ | **强(严重 → 红旗)** | 任一 combo(A/B/C/D)完全触发 | 直接输出红旗 YES;列出触发 combo + 关键依据;要求 discover 在递交前向用户二次确认 |
35
+
36
+ **档位判定原则**:
37
+ - 档位只升不降(同一问题第 2 次出现自动升一档)
38
+ - Combo D 是时序判定:第 1 轮异议算"关注",第 2 轮同维度无新回应算"严重"
39
+ - 不允许"看起来有点像"的模糊判断,必须对照 combo 条件逐项比对
40
+
41
+ ---
42
+
43
+ ## 红旗输出 Schema
44
+
45
+ challenger 判定红旗后,回报给 discover 的结构化字段(最终写入 `handoff.yaml::red_flags`):
46
+
47
+ ```yaml
48
+ red_flags:
49
+ raised: true # bool,必填
50
+ combos: ["A"] # list[string],每项 ∈ {A,B,C,D};可同时触发多个 combo,combos 是数组(raised=true 时 length>=1)
51
+ reasons: # list[string],raised=true 时 ≥ 1 条
52
+ - "核心前提「用户愿意每天打开」未经验证"
53
+ - "与 KH item-xyz 历史结论矛盾"
54
+ user_persisted_rounds: 2 # int,用户硬扛了几轮
55
+ downstream_advisory: "coder 实施前必须与用户二次确认"
56
+ ```
57
+
58
+ **禁用词**(全部字段禁止出现):
59
+ - 允许替代措辞:`关键前提未证实` / `多轮反对未回应` / `带红旗交付`
60
+
61
+ ---
62
+
63
+ ## discover 准备 Challenger Prompt 的清单
64
+
65
+ 在 Phase C 召唤 `discover-challenger` 前,prompt 必须包含:
66
+
67
+ 1. **当前意图树**:用户最终确认的"给谁解决什么 Job"(一句话)
68
+ 2. **假设列表**:discover 自己列的 ≥5 条假设 + 每条标注 `[已验证 / 推测 / 高风险未知]`
69
+ 3. **用户原话摘要**:本 session 中用户说过的关键句(含前后矛盾的片段)
70
+ 4. **已命中的 combo 信号**(如有):列出哪个 combo 有触发迹象,方便 challenger 重点核查
71
+ 5. **关注维度**(可选):如 discover 特别担心某个维度,明示 challenger 重点看
72
+
73
+ **召唤话术(向用户展示)**:
74
+ > 我请一个专门挑刺的同事再看一眼,他会更直接,不留情面 —— 这是为了帮你避坑。
@@ -0,0 +1,126 @@
1
+ ---
2
+ name: ears-zh
3
+ description: EARS 中文句式库;提供 5 类需求句式模板(Ubiquitous/Event/State/Option/Complex)
4
+ metadata:
5
+ owner: codeforge
6
+ group: discover
7
+ version: 1.0.0
8
+ allowed_tools: [read]
9
+ mode: on-demand
10
+ trigger: discover Phase E 写 PRD / 其他 agent 写需求
11
+ ---
12
+
13
+ # EARS 中文句式库
14
+
15
+ > EARS(Easy Approach to Requirements Syntax)是一套结构化需求书写方法,让每条需求都清晰、可测试、无歧义。本 skill 提供中文适配版本,供 discover agent 在 Phase E 写需求清单时使用,也可被其他 agent(architect / pm)直接复用。
16
+
17
+ ---
18
+
19
+ ## 5 类句式模板
20
+
21
+ ### 1. 泛在型(Ubiquitous)
22
+
23
+ **适用**:任何时候都应该满足的行为,无需特定触发条件。
24
+
25
+ **模板**:
26
+ ```
27
+ 系统应当 <行为>。
28
+ ```
29
+
30
+ **示例**:
31
+ > 系统应当对所有用户输入进行 XSS 转义。
32
+ > 系统应当对所有 API 响应记录请求耗时日志。
33
+
34
+ ---
35
+
36
+ ### 2. 事件触发型(Event-Driven)
37
+
38
+ **适用**:某个事件发生时,系统做出响应。
39
+
40
+ **模板**:
41
+ ```
42
+ 当 <事件发生> 时,系统应当 <响应行为>。
43
+ ```
44
+
45
+ **示例**:
46
+ > 当用户点击「导出」按钮时,系统应当在 3 秒内生成 PDF 文件并触发下载。
47
+ > 当订单状态变为「已支付」时,系统应当向用户发送确认通知。
48
+
49
+ ---
50
+
51
+ ### 3. 状态型(State-Driven)
52
+
53
+ **适用**:系统或用户处于某种持续状态时,需要保持的行为。
54
+
55
+ **模板**:
56
+ ```
57
+ 处于 <系统/用户状态> 时,系统应当 <持续行为>。
58
+ ```
59
+
60
+ **示例**:
61
+ > 处于「离线模式」时,系统应当禁用所有需要网络的功能,并显示「离线中」提示。
62
+ > 处于「批量处理」进行中时,系统应当每 10 秒刷新一次进度状态。
63
+
64
+ ---
65
+
66
+ ### 4. 可选型(Optional)
67
+
68
+ **适用**:仅当某个前置特性/配置启用时才生效的需求。
69
+
70
+ **模板**:
71
+ ```
72
+ 如果 <前置特性/配置存在>,当 <事件> 时,系统应当 <响应>。
73
+ ```
74
+
75
+ **示例**:
76
+ > 如果用户配置了「邮件通知」,当导出任务完成时,系统应当发送含下载链接的邮件。
77
+ > 如果启用了「双因素认证」,当用户登录时,系统应当要求输入验证码。
78
+
79
+ ---
80
+
81
+ ### 5. 复合型(Complex)
82
+
83
+ **适用**:同时有前置条件 + 触发事件的需求。
84
+
85
+ **模板**:
86
+ ```
87
+ 如果 <前置条件>,当 <触发事件> 时,系统应当 <响应>,除非 <例外条件>。
88
+ ```
89
+
90
+ **示例**:
91
+ > 如果当月有交易记录,当用户点击「生成对账单」时,系统应当按客户分组生成 PDF,除非该客户被标记为「停用」。
92
+ > 如果用户拥有「管理员」权限,当用户访问「设置」页面时,系统应当展示高级配置项,除非系统处于维护模式。
93
+
94
+ ---
95
+
96
+ ## 选型决策树
97
+
98
+ 根据需求性质选择合适的句式类型:
99
+
100
+ ```
101
+ 这条需求...
102
+ ├─ 没有特定触发条件,任何时候都应满足?
103
+ │ └─ → 泛在型(Ubiquitous)
104
+ ├─ 由某个事件触发?
105
+ │ ├─ 只需要事件,无前置条件?
106
+ │ │ └─ → 事件触发型(Event-Driven)
107
+ │ └─ 还有前置条件(特性启用/状态判断)?
108
+ │ ├─ 前置条件是"可选特性/配置"?
109
+ │ │ └─ → 可选型(Optional)
110
+ │ └─ 前置条件是"运行时状态/数据条件"?
111
+ │ └─ → 复合型(Complex)
112
+ └─ 系统处于某种持续状态,需要持续保持行为?
113
+ └─ → 状态型(State-Driven)
114
+ ```
115
+
116
+ ---
117
+
118
+ ## 与 PRD 需求清单的对应关系
119
+
120
+ 在 `PRD.md §4 需求清单` 中,每条需求按此句式书写:
121
+
122
+ | 需求等级 | 推荐句式 | 说明 |
123
+ |---|---|---|
124
+ | **必做(R-must)** | 事件触发型 / 泛在型 | 核心路径,必须可测试 |
125
+ | **可做(R-should)** | 可选型 / 复合型 | 有前提条件,按配置启用 |
126
+ | **绝不做(R-anti)** | 复合型(带 `除非`) | 防错规则,明确边界 |
@@ -0,0 +1,96 @@
1
+ ---
2
+ name: example-mapping
3
+ description: BDD 场景挖掘;用 Rule/Example/Question 三色卡引导用户列具体 case 和边界
4
+ metadata:
5
+ owner: codeforge
6
+ group: discover
7
+ version: 1.0.0
8
+ allowed_tools: [read]
9
+ mode: on-demand
10
+ trigger: discover Phase B 中段 / Phase D 末段
11
+ ---
12
+
13
+ # Example Mapping
14
+
15
+ ## 三色卡定义
16
+
17
+ | 颜色 | 卡片类型 | 含义 | 发起问法 |
18
+ |---|---|---|---|
19
+ | 🟡 **黄** | **Rule**(规则) | 业务规则 / 约束 / 策略:在什么条件下,系统应该怎么做 | "这个场景下,有没有什么条件或限制是必须满足的?" |
20
+ | 🔵 **蓝** | **Example**(示例) | 具体例子:一个真实的用户行为序列,验证规则成立 | "能给我描述一个具体的操作过程吗?从什么触发,到看到什么结果?" |
21
+ | 🔴 **红** | **Question**(问题) | 未解决的疑问:还不确定、有争议、需要找人确认的点 | "这里我还不确定……你能帮我确认一下吗?" |
22
+
23
+ **核心原则**:每张黄卡(规则)至少配 1 张蓝卡(示例);红卡不能累积太多——红卡多说明规则还没想清楚。
24
+
25
+ ---
26
+
27
+ ## 挖掘 4 步法
28
+
29
+ ### Step 1:给 Story
30
+
31
+ 用一句话描述当前要挖掘的 user story(discover 根据 Phase A/B 的结论来):
32
+
33
+ > 作为 `<用户角色>`,当 `<触发事件>` 时,我希望 `<系统行为>`,以便 `<业务价值>`。
34
+
35
+ ### Step 2:列规则(黄卡)
36
+
37
+ 请用户和 discover 一起头脑风暴业务规则:
38
+
39
+ - "这个功能有哪些**限制条件**?"
40
+ - "什么情况下这个功能**不该触发**?"
41
+ - "有没有**特殊分组**或**权限差异**?"
42
+
43
+ 每条规则写成:"如果 X,则 Y"或"只有当 X,才能 Y"。
44
+
45
+ ### Step 3:配示例(蓝卡)
46
+
47
+ 针对每条规则,要求至少 1 个具体例子:
48
+
49
+ - "给我一个**正常情况**下的完整操作流程"
50
+ - "再给一个**边界/临界情况**的例子"
51
+ - "如果这条规则**不成立**,会发生什么?"
52
+
53
+ 蓝卡格式:`当 [具体条件] → [用户做了什么] → [系统应该输出什么]`
54
+
55
+ ### Step 4:标问题(红卡)
56
+
57
+ 遇到不确定的点立刻记录为红卡:
58
+
59
+ - 规则之间有冲突 → 红卡
60
+ - 示例能否覆盖规则仍不确定 → 红卡
61
+ - 需要找业务方/技术确认 → 红卡
62
+
63
+ ---
64
+
65
+ ## 收敛条件
66
+
67
+ 当满足以下条件时,本轮 Example Mapping 收敛,可以继续推进:
68
+
69
+ - **主路径**:每条核心规则(黄卡)至少配 1 张示例(蓝卡)
70
+ - **红卡 ≤ 2**:未解决问题 ≤ 2 张;超过则必须先解决优先级最高的红卡再继续
71
+ - **边界覆盖**:至少包含 1 个异常/边界示例(空状态 / 错误输入 / 无数据时)
72
+
73
+ 若红卡 > 2,discover 的处理原则:
74
+ 1. 优先把红卡变黄卡(能明确规则的就明确)
75
+ 2. 无法当场明确的,记录到 handoff.yaml::open_issues
76
+ 3. 标记为"后续 coder/planner 阶段确认"的留存红卡
77
+
78
+ ---
79
+
80
+ ## Phase B vs Phase D 调用差异
81
+
82
+ | 调用时机 | 目标 | 侧重 |
83
+ |---|---|---|
84
+ | **Phase B 中段**(核心 user story 已澄清后) | 挖掘主路径场景 | 先跑 happy path(正常流程 3-5 个蓝卡) |
85
+ | **Phase D 末段**(写验收前) | 补充边界 case | 重点挖 edge case:空状态/并发/错误输入/权限异常 |
86
+
87
+ **人话外壳**(Phase B 时):
88
+ > 在收拢方案之前,咱多想几个可能性。给我讲 2-3 个**具体**场景:
89
+ > - 场景 A:什么人,什么时候,发生什么事,期望什么结果?
90
+ > - 场景 B / C 同上。
91
+
92
+ **人话外壳**(Phase D 时):
93
+ > 核心流程我们已经说清楚了,再看看几个特殊情况:
94
+ > - 如果用户没有数据,会看到什么?
95
+ > - 如果操作中途失败了,怎么处理?
96
+ > - 有没有某些用户**不该**看到这个功能?
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: success-criteria
3
+ description: 验收标准生成;把 user story + example mapping 输出转为 SMART 验收清单
4
+ metadata:
5
+ owner: codeforge
6
+ group: discover
7
+ version: 1.0.0
8
+ allowed_tools: [read]
9
+ mode: on-demand
10
+ trigger: discover Phase E PRD 生成前
11
+ ---
12
+
13
+ # Success Criteria
14
+
15
+ ## SMART 检查表
16
+
17
+ 把每条验收标准逐项对照以下 5 项,不满足的必须改写:
18
+
19
+ | 维度 | 含义 | 检验问法 |
20
+ |---|---|---|
21
+ | **S — Specific(具体)** | 描述的是一个明确的、可操作的行为或状态,不含模糊副词 | "把'更快'改成'≤ 3 秒';把'用户满意'改成'NPS ≥ 40'" |
22
+ | **M — Measurable(可测量)** | 有数字或可观测的状态变化,能用工具/日志/截图验证 | "能不能写一段 e2e 测试 / 监控报警来验证这条?" |
23
+ | **A — Achievable(可达到)** | 在当前技术和时间约束下实际可实现,不是理想态 | "这个指标现在的 baseline 是多少?从哪到哪?" |
24
+ | **R — Relevant(相关性)** | 直接关联用户 Job 或业务目标,不是技术指标的自嗨 | "这条验收通过了,用户的原始问题有没有被解决?" |
25
+ | **T — Time-bound(时间窗口)** | 有明确的时间范围或触发时机(何时测、多久内、在哪个版本) | "是'上线后 3 天内'还是'每次操作时'?" |
26
+
27
+ ---
28
+
29
+ ## 验收语法
30
+
31
+ 推荐使用 EARS 句式(本项目已有 `ears-zh` skill 提供模板)将验收条件结构化:
32
+
33
+ **核心句式**(快速参考):
34
+ - 事件触发型:`当 <事件> 时,系统应当 <响应>,在 <时间窗口> 内`
35
+ - 状态型:`处于 <状态> 时,系统应当 <持续行为>`
36
+ - 条件型:`如果 <前置条件>,当 <事件> 时,系统应当 <响应>`
37
+
38
+ **与 Example Mapping 结合**:每张蓝卡(示例)对应一条验收标准;红卡(未解决问题)对应 `open_issues`,不进验收清单。
39
+
40
+ ---
41
+
42
+ ## 反模式(5 种不可验收写法)
43
+
44
+ 以下写法**不允许**出现在验收标准中,发现立即要求用户改写:
45
+
46
+ | 反模式 | 示例 | 改写方向 |
47
+ |---|---|---|
48
+ | **主观感受** | "用户体验更好" / "界面更美观" / "用起来更流畅" | 改为可观测行为:"用户完成任务的步骤数从 7 步减到 4 步" |
49
+ | **没有时间窗** | "系统应该快速响应" / "页面应该快速加载" | 补时间:"p95 响应时间 ≤ 500ms" |
50
+ | **双重否定** | "不会出现用户无法完成操作的情况" | 改为正向陈述:"用户点击提交后,100% 收到明确的成功或失败反馈" |
51
+ | **技术实现** | "使用 Redis 缓存热点数据" | 改为行为结果:"缓存命中率 ≥ 90%,冷启动后 ≤ 5 秒恢复响应" |
52
+ | **加法式兜底** | "还有其他任何用户可能需要的功能" / "以及其他情况" | 删除,或明确列出具体场景 |
53
+
54
+ ---
55
+
56
+ ## 输出格式(写入 handoff.yaml)
57
+
58
+ 每条验收标准输出为以下结构:
59
+
60
+ ```yaml
61
+ acceptance_criteria:
62
+ - id: "AC-R1-1"
63
+ description: "新人首次登录 3 秒内看到 ≥5 张推荐卡片"
64
+ measurable: true
65
+ metric: "p95_first_paint_ms < 3000 AND card_count >= 5"
66
+ - id: "AC-R1-2"
67
+ description: "当月无交易的客户不生成 PDF 文件"
68
+ measurable: true
69
+ metric: "导出任务完成后,空客户目录下文件数 = 0"
70
+ ```
71
+
72
+ **id 命名规范**:`AC-<需求id>-<序号>`,如 `AC-R1-1`、`AC-R2-3`。
73
+
74
+ ---
75
+
76
+ ## Phase E 前的快速校验步骤
77
+
78
+ 进入 Phase E 出 PRD 草稿前,逐条过一遍:
79
+
80
+ 1. 收集所有 Phase B/D 中已确认的蓝卡(示例)
81
+ 2. 每张蓝卡转一条验收标准(套 EARS 句式)
82
+ 3. 逐项过 SMART 5 维,标注不满足的维度
83
+ 4. 不满足的条目退回给用户补充,或由 discover 建议改写方案
84
+ 5. 全部通过后,写入 `handoff.yaml::acceptance_criteria`
@@ -0,0 +1,109 @@
1
+ ---
2
+ name: weighted-dimensions
3
+ description: 5 维加权打分逻辑;输出 weighted_score ∈ [0,1],供退出条件判断
4
+ metadata:
5
+ owner: codeforge
6
+ group: discover
7
+ version: 1.0.0
8
+ allowed_tools: [read]
9
+ mode: on-demand
10
+ trigger: 每轮对话结束前 / Phase 跳转判定
11
+ ---
12
+
13
+ # Weighted Dimensions
14
+
15
+ ## 5 个维度定义
16
+
17
+ | 维度 | 含义 | 典型证据 |
18
+ |---|---|---|
19
+ | **Functional** | 功能目标是否清晰:做什么、输出什么、核心流程是否可描述 | 用户能用一句话说出"给谁解决什么 Job" |
20
+ | **UX** | 用户体验诉求:交互形式、感知质量、用户旅程中的关键时刻 | 用户提到了"快"/"简单"/"不要让我多点"等具体体验锚点 |
21
+ | **Technical** | 技术可行性边界:性能要求、技术栈约束、已知依赖或限制 | 提及响应时间、系统限制、第三方 API、数据量级等 |
22
+ | **Constraints** | 业务约束:时间窗口、合规、资源限制、显式排除项 | 提及"本期只做……"/"不做……"/"必须兼容……" |
23
+ | **Edge Cases** | 边界场景:异常路径、零状态、错误处理、极端用户行为 | 用户或 discover 主动列举了"如果……怎么处理" |
24
+
25
+ ---
26
+
27
+ ## 加权公式
28
+
29
+ **默认权重分配**:
30
+
31
+ | 维度 | 权重 |
32
+ |---|---|
33
+ | Functional | **30%** |
34
+ | UX | **25%** |
35
+ | Technical | **20%** |
36
+ | Constraints | **15%** |
37
+ | Edge Cases | **10%** |
38
+
39
+ **计算公式**:
40
+
41
+ ```
42
+ weighted_score = Σ (维度得分 × 权重)
43
+ = F×0.30 + U×0.25 + T×0.20 + C×0.15 + E×0.10
44
+ ```
45
+
46
+ 其中每个维度得分 ∈ [0, 1.0](0 = 完全未知,0.5 = 部分清晰,1.0 = 充分明确)。
47
+
48
+ **示例**:
49
+
50
+ ```
51
+ F=0.8, U=0.5, T=0.3, C=0.6, E=0.2
52
+ weighted_score = 0.8×0.30 + 0.5×0.25 + 0.3×0.20 + 0.6×0.15 + 0.2×0.10
53
+ = 0.24 + 0.13 + 0.06 + 0.09 + 0.02
54
+ = 0.54
55
+ ```
56
+
57
+ ---
58
+
59
+ ## 阈值表
60
+
61
+ | 阶段跳转 | 所需 weighted_score | 备注 |
62
+ |---|---|---|
63
+ | Phase A → B | **≥ 0.5** | 且 Functional ≥ 0.7,用户能说出核心 Job |
64
+ | Phase B → C | **≥ 0.65** | ≥ 3 个具体场景已确认 |
65
+ | Phase C → D | —(由 challenger 红旗处理状态决定) | 至少 1 轮 challenger 反对被用户正面回应 |
66
+ | Phase D → E | **≥ 0.8** | 或 0.6-0.8 且用户明确说"够了" |
67
+
68
+ ---
69
+
70
+ ## 评分表输出模板
71
+
72
+ 当用户触发「评估 / 打分 / 评分 / 严谨模式 / 看进度 / 澄清度 / 现在多少分 / score / rate」关键词时,或进入 Phase E 前,按此格式输出:
73
+
74
+ ```
75
+ ─────────────────────────────────────
76
+ 本轮澄清度评分(满分 1.0):
77
+ | 维度 | 权重 | 当前 | 加权 |
78
+ |---------------|------|------|------|
79
+ | Functional | 30% | 0.8 | 0.24 |
80
+ | UX | 25% | 0.5 | 0.13 |
81
+ | Technical | 20% | 0.3 | 0.06 |
82
+ | Constraints | 15% | 0.6 | 0.09 |
83
+ | Edge Cases | 10% | 0.2 | 0.02 |
84
+ | **总分** | | | 0.54 |
85
+
86
+ 档位:Insufficient (<0.6) → 继续澄清
87
+ 建议下一步:聚焦 Technical 维度(本轮最低分)
88
+ ─────────────────────────────────────
89
+ ```
90
+
91
+ **档位规则**:
92
+
93
+ - **≥ 0.8** → Sufficient,建议进 Phase E 产出 PRD
94
+ - **0.6 ~ 0.8** → Acceptable,可选退出(用户拍板)
95
+ - **< 0.6** → Insufficient,必须继续澄清
96
+
97
+ ---
98
+
99
+ ## 维度打分指南
100
+
101
+ **Functional 常见打分依据**:
102
+ - 0.0:只说了"做个东西",完全不知道做什么
103
+ - 0.5:知道大方向("做个导出"),但不知道输出形式、流程
104
+ - 1.0:输入输出明确,核心流程可描述,用户能说出 Job
105
+
106
+ **Edge Cases 常见打分依据**:
107
+ - 0.0:完全没讨论过边界
108
+ - 0.5:讨论了 1-2 个正常 happy path,无异常路径
109
+ - 1.0:覆盖了至少 3 个边界场景(空状态/错误/极端输入)