@modus-ai/modus 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +45 -4
  2. package/dist/cli/index.js +2 -2
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/commands/config.d.ts.map +1 -1
  5. package/dist/commands/config.js +9 -8
  6. package/dist/commands/config.js.map +1 -1
  7. package/dist/commands/global.js +1 -1
  8. package/dist/commands/global.js.map +1 -1
  9. package/dist/commands/init.d.ts.map +1 -1
  10. package/dist/commands/init.js +0 -1
  11. package/dist/commands/init.js.map +1 -1
  12. package/dist/commands/status.js +2 -2
  13. package/dist/generators/claude.d.ts.map +1 -1
  14. package/dist/generators/claude.js +0 -36
  15. package/dist/generators/claude.js.map +1 -1
  16. package/dist/generators/copilot.d.ts.map +1 -1
  17. package/dist/generators/copilot.js +0 -1
  18. package/dist/generators/copilot.js.map +1 -1
  19. package/dist/utils/config.d.ts +32 -0
  20. package/dist/utils/config.d.ts.map +1 -1
  21. package/dist/utils/config.js +10 -2
  22. package/dist/utils/config.js.map +1 -1
  23. package/dist/utils/file-system.d.ts.map +1 -1
  24. package/dist/utils/file-system.js +2 -1
  25. package/dist/utils/file-system.js.map +1 -1
  26. package/package.json +1 -1
  27. package/schemas/knowledge-schema.yaml +123 -1
  28. package/templates/behavior-guard.md +165 -0
  29. package/templates/commands/auto.md +3 -1
  30. package/templates/commands/commit.md +63 -0
  31. package/templates/commands/harness.md +15 -8
  32. package/templates/commands/vibe.md +1 -1
  33. package/templates/knowledge-catalog.md +66 -10
  34. package/templates/skills/modus-agents/analyst/SKILL.md +16 -0
  35. package/templates/skills/modus-agents/deployer/SKILL.md +114 -62
  36. package/templates/skills/modus-agents/designer/SKILL.md +104 -92
  37. package/templates/skills/modus-agents/developer/SKILL.md +106 -67
  38. package/templates/skills/modus-agents/perf-auditor/SKILL.md +98 -61
  39. package/templates/skills/modus-agents/reviewer/SKILL.md +25 -2
  40. package/templates/skills/modus-agents/security-auditor/SKILL.md +111 -67
  41. package/templates/skills/modus-agents/skill-creator/SKILL.md +37 -19
  42. package/templates/skills/modus-agents/tester/SKILL.md +100 -54
  43. package/templates/skills/modus-auto/SKILL.md +16 -1
  44. package/templates/skills/modus-design-brief/SKILL.md +31 -13
  45. package/templates/skills/modus-harness/SKILL.md +78 -12
  46. package/templates/skills/modus-init/SKILL.md +801 -161
  47. package/templates/skills/modus-plan/SKILL.md +109 -43
  48. package/templates/skills/modus-spec/SKILL.md +175 -331
  49. package/templates/skills/modus-vibe/SKILL.md +147 -44
@@ -1,123 +1,167 @@
1
1
  ---
2
2
  name: modus-security-auditor
3
- description: Use this skill when the Harness orchestrator needs to perform security audit on code changes. Checks multi-tenant data isolation, missing authorization annotations, sensitive data logging, SQL injection risks, and bypass interface protection. Generates 05-security-report.md. Triggered by modus-harness in parallel with SubAgents 03 and 04 after Gate A passes.
4
- allowed-tools: Read, Write, Glob
3
+ description: Use this skill when the Harness orchestrator needs to perform static security audit on changed code. Detects multi-tenant data isolation leaks (tenantId from request vs UserContext), missing permission annotations, SQL injection risks, sensitive data logging, and improper bypass interfaces. Grades as critical/high/low and generates 05-security-report.md with HANDOFF block. Triggered by modus-harness in parallel with tester and perf-auditor after Gate A passes.
4
+ allowed-tools: Read, Glob
5
5
  disable: false
6
6
  ---
7
7
 
8
8
  # modus-security-auditor(安全审计 SubAgent)
9
9
 
10
- **调用方:** Harness Orchestrator(与 03/04 并行启动)
11
- **输入:** `02-sprint-contract.md` + 代码变更
10
+ **调用方:** Harness Orchestrator(Gate A 通过后,与 03/04 并行触发)
11
+ **输入:** `02-sprint-contract.md`(变更文件列表)+ 代码变更 + 业务 Skill(≤ 2 个)
12
12
  **产出物:** `modus/plans/active/{story-id}/05-security-report.md`
13
13
 
14
14
  ## 职责
15
15
 
16
- 对代码变更进行安全审计,重点检测多租户数据隔离漏洞、权限校验缺失、敏感信息泄露、SQL 注入等风险,按严重/高/低分级输出报告。
16
+ 对本次代码变更进行静态安全审计,重点检测多租户隔离漏洞、权限校验缺失、SQL 注入、敏感信息泄露等高频安全问题。不执行代码,不修改文件。
17
17
 
18
18
  ---
19
19
 
20
- ## 审计重点
20
+ ## 检测规则
21
21
 
22
- ### 1. 多租户数据隔离(严重)
22
+ ### Rule 1:多租户数据隔离漏洞(严重)
23
23
 
24
- **检测模式:**
25
- - DB 查询/更新缺少 `tenantId` 条件
26
- - `tenantId` 来自 request 参数(可被篡改),而不是从用户会话/上下文中获取
27
- - 数据归属校验:操作前是否验证当前用户有权操作该条记录
24
+ **触发条件:** Service / Mapper 中的 WHERE 条件使用了来自 request 参数而非 UserContext 的 `tenantId`
28
25
 
29
- **修复建议:**
30
- - `tenantId` 始终从服务端 UserContext/Session 中获取,不信任客户端传入
31
- - 关键查询增加 `AND tenant_id = #{tenantId}` 条件
32
- - 修改操作前查询数据归属,确认归属于当前租户
26
+ ```java
27
+ // ❌ 严重漏洞:tenantId 来自用户输入,可查看任意租户数据
28
+ public List<Order> listOrders(OrderQueryRequest request) {
29
+ return orderMapper.selectByTenantId(request.getTenantId()); // 危险
30
+ }
31
+
32
+ // ✅ 正确:tenantId 必须来自 UserContext(登录上下文)
33
+ public List<Order> listOrders(OrderQueryRequest request) {
34
+ Long tenantId = UserContext.getCurrentTenantId(); // 安全
35
+ return orderMapper.selectByTenantId(tenantId);
36
+ }
37
+ ```
38
+
39
+ **危害:** 横向越权,A 租户可读取 B 租户数据
40
+
41
+ ---
42
+
43
+ ### Rule 2:Facade/Controller 权限校验缺失(高风险)
44
+
45
+ **触发条件:** 新增的 Facade / Controller 方法缺少权限注解(如 `@UserAuthorization`、`@PreAuthorize`、`@RolesAllowed`)
46
+
47
+ **危害:** 未授权用户可直接调用接口
48
+ **修复建议:** 所有对外接口必须有权限注解,最小权限原则
33
49
 
34
50
  ---
35
51
 
36
- ### 2. 接口权限校验(高风险)
52
+ ### Rule 3:敏感信息日志泄露(高风险)
37
53
 
38
- **检测模式:**
39
- - 对外暴露的接口(Controller/Facade)缺少权限校验注解
40
- - 管理员操作接口未校验当前用户是否为管理员角色
41
- - 查询接口未过滤当前用户无权访问的数据
54
+ **触发条件:** `log.info` / `log.debug` / `log.error` 中直接打印以下敏感字段:
55
+ - 身份证号(idCard / idNo)
56
+ - 银行卡号(bankCard / cardNo)
57
+ - 手机号(phone / mobile)
58
+ - 密码(password / pwd)
59
+ - 完整 Token / sessionId
42
60
 
43
- **修复建议:**
44
- - 接口层添加权限校验注解或调用权限校验方法
45
- - 结合项目的权限框架(RBAC/自定义注解)进行检查
61
+ **危害:** 日志系统通常访问范围较广,敏感信息泄露风险高
62
+ **修复建议:** 使用脱敏工具类处理后再打印,如 `MaskUtils.maskPhone(phone)`
46
63
 
47
64
  ---
48
65
 
49
- ### 3. 敏感信息泄露(高风险)
66
+ ### Rule 4:SQL 注入风险(严重)
67
+
68
+ **触发条件:** MyBatis XML / 注解 SQL 中使用 `${}` 拼接用户输入(应使用 `#{}`)
50
69
 
51
- **检测模式:**
52
- - 日志中打印手机号、身份证号、银行卡号、密码等
53
- - 接口响应中返回不必要的敏感字段
54
- - 异常信息中暴露内部实现细节(SQL 语句、堆栈等)
70
+ ```xml
71
+ <!-- ❌ SQL 注入 -->
72
+ SELECT * FROM orders WHERE status = ${status}
55
73
 
56
- **修复建议:**
57
- - 日志脱敏:手机号保留前 3 4,身份证保留前 3 4
58
- - 响应对象中敏感字段加脱敏注解或做 mask 处理
59
- - 生产环境不返回原始异常信息
74
+ <!-- ✅ 安全 -->
75
+ SELECT * FROM orders WHERE status = #{status}
76
+ ```
77
+
78
+ **危害:** 用户可构造恶意 SQL 执行任意查询或修改数据
60
79
 
61
80
  ---
62
81
 
63
- ### 4. SQL 注入风险(严重)
82
+ ### Rule 5:Bypass 接口缺少多租户保护(高风险)
64
83
 
65
- **检测模式:**
66
- - MyBatis XML 中使用 `${}` 拼接用户输入(应使用 `#{}`)
67
- - 动态表名/列名未做白名单校验
68
- - 排序字段直接拼接到 SQL(`ORDER BY ${sortField}`)
84
+ **触发条件:** 以下类型的"内部接口"没有 tenantId 过滤:
85
+ - 定时任务(`@Scheduled` / `@XxlJob`)中的全量查询
86
+ - 管理后台接口中可跨租户的查询
87
+ - MQ 消费者处理消息时未验证消息的 tenantId
69
88
 
70
- **修复建议:**
71
- - 用户输入一律使用 `#{}` 参数化
72
- - 动态排序字段做枚举白名单校验
89
+ **危害:** 批量操作可能意外处理其他租户的数据
73
90
 
74
91
  ---
75
92
 
76
- ### 5. 越权操作(高风险)
93
+ ### Rule 6:不安全的反序列化(中风险)
94
+
95
+ **触发条件:** 使用 `ObjectInputStream` 直接反序列化用户可控的数据,或使用不安全的 JSON 反序列化(如 `JSONObject.parseObject(str, Object.class)`)
77
96
 
78
- **检测模式:**
79
- - 通过 ID 查询/修改数据,未校验该数据是否属于当前用户/租户
80
- - 批量操作接口未限制操作范围(如用户传入他人的 ID 列表)
97
+ **危害:** 远程代码执行(RCE)风险
98
+
99
+ ---
100
+
101
+ ## 执行流程
102
+
103
+ ### Step 1:确定审计范围
104
+
105
+ 读取 `02-sprint-contract.md` 的 `changed_files`,筛选需要审计的文件:
106
+ - Controller / Facade(Rule 1/2/3)
107
+ - Service / Manager(Rule 1/3/5)
108
+ - XML Mapper(Rule 4)
109
+ - MQ Consumer(Rule 5)
110
+ - 定时任务类(Rule 5)
111
+
112
+ ### Step 2:逐规则扫描
113
+
114
+ 对每个目标文件,逐一应用上述 6 条规则,记录发现的安全漏洞。
115
+
116
+ ### Step 3:风险分级
117
+
118
+ | 风险等级 | 定义 | 处理要求 |
119
+ |---------|------|---------|
120
+ | 严重(需 P1 重入)| 可直接导致数据泄露或越权的漏洞 | modus-reviewer 标记为 P1,触发 Loop 2 |
121
+ | 高(需 P2 重入)| 安全隐患,在特定条件下可被利用 | modus-reviewer 标记为 P2,触发 Loop 2 |
122
+ | 中(建议修复)| 潜在风险,当前影响有限 | cr-report 中作为 P3 建议 |
81
123
 
82
124
  ---
83
125
 
84
126
  ## 产出物格式(05-security-report.md)
85
127
 
86
128
  ```markdown
87
- # 安全审计报告
129
+ <!--HANDOFF
130
+ agent: "05-security-auditor"
131
+ story_id: "{story-id}"
132
+ gate_status: "passed"
133
+ critical_risks: {N}
134
+ high_risks: {N}
135
+ -->
136
+
137
+ # 安全审计报告 — {Story 标题}
88
138
 
89
139
  ## 审计摘要
90
- - 严重: {N} 个 | 高风险: {N} 个 | 低风险: {N} 个
140
+ - 审计文件数: {N}
141
+ - 严重: {N} 个 | 高风险: {N} 个 | 中风险: {N} 个
91
142
 
92
- ## 严重问题
143
+ ## 严重漏洞(必须修复)
93
144
 
94
- ### [SEC-CRITICAL-01] 多租户隔离缺失
145
+ ### [SEC-CRITICAL-01] 多租户隔离漏洞 — {ClassName}.{method}()
95
146
  - **位置:** `{文件名}.java:{行号}`
96
- - **问题:** `tenantId` request 参数获取,攻击者可篡改访问他人数据
97
- - **修复:**
98
- ```java
99
- // 错误
100
- Long tenantId = request.getTenantId();
101
- // 正确
102
- Long tenantId = UserContext.getCurrentTenantId();
103
- ```
104
-
105
- ## 高风险问题
147
+ - **漏洞描述:** tenantId 来自 request.getTenantId(),而非 UserContext
148
+ - **危害:** 横向越权,A 租户可读取 B 租户数据
149
+ - **修复方案:** 将 `request.getTenantId()` 替换为 `UserContext.getCurrentTenantId()`
150
+
151
+ ## 高风险(必须修复)
106
152
  ...
107
153
 
108
- ## 低风险问题
154
+ ## 中风险(建议修复)
109
155
  ...
110
156
 
111
- ## 无安全问题确认
112
- {如无问题,明确说明已检查的内容}
157
+ ## 无风险确认
158
+ {若某类规则未发现风险,明确写出「Rule N:未发现 XXX 风险」}
113
159
  ```
114
160
 
115
161
  ---
116
162
 
117
- ## 评级标准
163
+ ## 质量标准
118
164
 
119
- | 级别 | 说明 | 处理要求 |
120
- |------|------|----------|
121
- | 严重 | 可直接导致数据泄露或越权 | 必须在合入前修复,触发 Loop 2 重入 |
122
- | 高风险 | 有潜在安全风险,影响范围较大 | 必须在合入前修复,触发 Loop 2 重入 |
123
- | 低风险 | 安全最佳实践问题,影响范围有限 | 建议修复,不阻塞合入 |
165
+ - 每个漏洞必须有文件路径 + 行号定位
166
+ - 严重/高风险必须提供具体修复代码示例
167
+ - **HANDOFF 块必须位于文件最顶部**,`critical_risks` + `high_risks` modus-reviewer 决定 P1/P2 级别
@@ -13,7 +13,7 @@ disable: false
13
13
 
14
14
  ## 职责
15
15
 
16
- 从项目代码和工作流产物中提炼业务知识,生成或更新标准格式的 Skill 文件(v2/14节),并维护知识全景目录(`knowledge-catalog.md`)。支持五种调用模式,覆盖从初始化到持续积累的完整知识生命周期。
16
+ 从项目代码和工作流产物中提炼业务知识,生成或更新标准格式的 Skill 文件(v3/17节,当前默认),并维护知识全景目录(`knowledge-catalog.md`)。支持五种调用模式,覆盖从初始化到持续积累的完整知识生命周期。
17
17
 
18
18
  ---
19
19
 
@@ -21,7 +21,7 @@ disable: false
21
21
 
22
22
  ### 模式 A:全量初始化(来自 /modus:init)
23
23
 
24
- 为每个确认的业务域从零生成 `modus-biz-{domain}/SKILL.md`,初始 `status: draft`,`format_version: v2`。
24
+ 为每个确认的业务域从零生成 `modus-biz-{domain}/SKILL.md`,初始 `status: draft`,`format_version: v3`(17节标准格式,详见 modus-init SKILL 区块 C)。
25
25
 
26
26
  ### 模式 B:增量更新(来自 /plan 或 /spec 前置,含 hash 快速检查)
27
27
 
@@ -46,8 +46,12 @@ disable: false
46
46
  **hash 检查(防腐校验通过后执行):**
47
47
 
48
48
  ```bash
49
- # 计算当前 key_files 内容的 SHA-1 摘要
50
- shasum -a 1 {file1} {file2} ... | awk '{print $1}' | sort | shasum -a 1 | awk '{print $1}'
49
+ # 标准全局 hash 计算命令(必须与 modus-init 区块 B、modus-plan Step 4-2 使用完全相同的算法)
50
+ # 算法:按文件路径排序 输出 "SHA-1:文件路径" 字符串 整体再 hash
51
+ # 禁止使用「仅 hash 值排序 hash」或「内容拼接整体 hash」的替代算法
52
+ for f in $(echo "{key_files}" | tr ' ' '\n' | sort); do
53
+ echo "$(shasum -a 1 "$f" | awk '{print $1}'):$f"
54
+ done | shasum -a 1 | awk '{print $1}'
51
55
  ```
52
56
 
53
57
  **对比结果分级处理:**
@@ -84,16 +88,16 @@ Step B-10-6:触发跨域联动提示(检查引用了本域的其他 Skill,
84
88
  ### 模式 C:后置回写(来自 /plan、/spec 归档后)
85
89
 
86
90
  将本次工作中新确立的决策、规则、接口契约追加或更新到对应 Skill 文件。
87
- 从产出物(design.md、specs/*/spec.md)提取带类型标签的知识:
91
+ 从产出物(design-brief.md、specs/*/spec.md)提取带类型标签的知识:
88
92
  - delta spec 的 ADDED Requirements → `[process]` / `[model]` 追加到业务 Skill
89
93
  - delta spec 的 MODIFIED Requirements → 更新对应 `[guideline]`
90
- - design.md 的架构决策章节 → `[decision]` 追加到对应业务 Skill 或 modus-tech-wiki
94
+ - design-brief.md 的架构决策章节 → `[decision]` 追加到对应业务 Skill 或 modus-tech-wiki
91
95
 
92
96
  ### 模式 D:知识提取(来自 Harness ARCHIVE 阶段)
93
97
 
94
98
  从 Harness 全流程产物中系统性提取知识条目,判断提升路径,写回 Skill 并更新 catalog。
95
99
 
96
- **输入产物:** `01-analysis.md`、`02-sprint-contract.md`、`cr-report.md`、`07-deploy-status.md`
100
+ **输入产物:** `01-analysis.md`、`02-sprint-contract.md`、`03-test-report.md`、`04-perf-report.md`、`05-security-report.md`、`cr-report.md`、`07-deploy-status.md`
97
101
 
98
102
  **提取规则:**
99
103
 
@@ -101,9 +105,17 @@ Step B-10-6:触发跨域联动提示(检查引用了本域的其他 Skill,
101
105
  |---------|---------|---------|---------|
102
106
  | 01-analysis.md 的风险点 | 业务边界条件、并发风险 | `[pitfall]` | modus-biz-{domain} |
103
107
  | 02-sprint-contract.md 的架构决策 | 技术选型原因 | `[decision]` | modus-tech-wiki |
108
+ | 03-test-report.md 的失败用例与边界条件 | 未覆盖的测试场景、发现的 bug 规律 | `[pitfall]` | modus-biz-{domain} |
109
+ | 04-perf-report.md 的高/中风险项 | N+1 查询、大数据量无分页、慢查询模式 | `[pitfall]` | modus-tech-wiki |
110
+ | 05-security-report.md 的严重/高风险项 | 多租户隔离漏洞、权限缺失、敏感信息泄露 | `[pitfall]` `[invariant]` | modus-team-conventions |
104
111
  | cr-report.md 的 P1/P2 问题 | 规范违反模式 | `[pitfall]` `[guideline]` | modus-team-conventions |
105
112
  | 07-deploy-status.md 的部署注意事项 | 环境特殊配置 | `[guideline]` | modus-tech-wiki |
106
113
 
114
+ **03/04/05 报告提取优先级:**
115
+ - `05-security-report.md` 的严重/高危问题必须提取,不可跳过(涉及安全不变量)
116
+ - `04-perf-report.md` 的高风险项(N+1、无分页大查询)必须提取,中风险项选择性提取
117
+ - `03-test-report.md` 仅提取因测试失败而发现的新 pitfall,已通过的用例不提取
118
+
107
119
  **成熟度提升判定(统一使用 status 字段):**
108
120
  - 本次工作流成功验证了某条知识 → `draft` 升为 `verified`,更新 `last_referenced` 和 `usage_count +1`
109
121
  - 若该知识已是 `verified` 且跨不同工作流被引用 ≥2 次 → 升为 `proven`
@@ -111,7 +123,10 @@ Step B-10-6:触发跨域联动提示(检查引用了本域的其他 Skill,
111
123
  **hash 更新(ARCHIVE 阶段必做):**
112
124
 
113
125
  ```bash
114
- shasum -a 1 {key_files...} | awk '{print $1}' | sort | shasum -a 1 | awk '{print $1}'
126
+ # 标准全局 hash 计算命令(与 modus-init 区块 B 规定的算法完全一致)
127
+ for f in $(echo "{key_files}" | tr ' ' '\n' | sort); do
128
+ echo "$(shasum -a 1 "$f" | awk '{print $1}'):$f"
129
+ done | shasum -a 1 | awk '{print $1}'
115
130
  ```
116
131
 
117
132
  将新 hash 写入 SKILL.md frontmatter 的 `last_hash` 字段。
@@ -230,7 +245,7 @@ shasum -a 1 {key_files...} | awk '{print $1}' | sort | shasum -a 1 | awk '{print
230
245
 
231
246
  注释汇总统计(Step 1 完成后输出):
232
247
  发现 TODO {N}条 | FIXME {M}条 | WARN/注意 {W}条 | HACK {H}条 | @deprecated {D}条
233
- → TODO > 3 条时:触发知识空白标记,供 modus-init Step 3.5 访谈问卷生成使用
248
+ → TODO > 3 条时:触发知识空白标记,供 modus-init Step 4 访谈问卷生成使用
234
249
  ```
235
250
 
236
251
  ---
@@ -324,7 +339,7 @@ Step 2C-4:构建完整转换矩阵(含禁止转换,不允许留空):
324
339
  | PAID | COMPLETED | 确认收货 | completeOrder() | @Transactional | - |
325
340
  | COMPLETED | CANCELLED | - | - | - | ❌ 抛 InvalidTransitionException |
326
341
 
327
- 孤立状态(无入/出转换的枚举值)→ 标记为 ⚠️「孤立状态,触发 Step 3.5 访谈」
342
+ 孤立状态(无入/出转换的枚举值)→ 标记为 ⚠️「孤立状态,触发 Step 4 访谈」
328
343
  ```
329
344
 
330
345
  #### 2D. 自定义校验器扫描
@@ -522,7 +537,7 @@ Step 2C-4:构建完整转换矩阵(含禁止转换,不允许留空):
522
537
  1. **2A if/else 推断结果** → 将所有 `[invariant]` 标签条目写入本节,标注来源行号
523
538
  2. **2D 自定义校验器** → 将 isValid()/validate() 中的判断逻辑转为不变量条目
524
539
  3. **Step 1.4 代码注释挖掘** → 将 `//WARN / //注意 / //重要` 注释写入本节(标注来源)
525
- 4. **Step 3.5 人工访谈回答** → 将用户补充的业务约束写入本节(标注 `[人工补充: {日期}]`)
540
+ 4. **Step 4 人工访谈回答** → 将用户补充的业务约束写入本节(标注 `[人工补充: {日期}]`)
526
541
 
527
542
  每条不变量必含:不变量描述、验证位置(类名:行号或方法名)、违反后果(异常类或错误码)、来源标注
528
543
 
@@ -537,7 +552,7 @@ Step 2C-4:构建完整转换矩阵(含禁止转换,不允许留空):
537
552
  2. Domain/Entity 类的类级 Javadoc → 实体中文含义与边界说明
538
553
  3. Service/Manager 方法 Javadoc 中出现的业务专名词(如「结算」「对账」「预授权」「防重」)
539
554
  4. Step 1.4 代码注释中出现的业务术语(`// 注意:此处的"XX"指的是...` 类注释)
540
- 5. Step 3.5 人工访谈中用户提及的专业术语(标注 `[人工补充]`)
555
+ 5. Step 4 人工访谈中用户提及的专业术语(标注 `[人工补充]`)
541
556
 
542
557
  每个术语必含:术语名、定义(1-2句)、与通用概念的区别(若无区别可省略)
543
558
 
@@ -679,7 +694,7 @@ Step 4 扩展:upstream/downstream 双向同步(append-only,Git 无冲突
679
694
 
680
695
  ### Step 6:质量自检(生成后执行)
681
696
 
682
- 00-skills-builder 在完成 Skill 生成后,执行自动质量自检:
697
+ `modus-skill-creator`(SubAgent 00)在完成 Skill 生成后,执行自动质量自检:
683
698
 
684
699
  ```
685
700
  质量自检清单(v3 版本,含新节检查):
@@ -737,7 +752,7 @@ last_verified_by: "" # 最后 verified 确认人(运行 /modus:verify
737
752
  domain_confidence: 0 # 域置信度评分(0-10),来自 modus-init Step 2 评分矩阵
738
753
  invariant_count: 0 # Section 15 业务不变量条目数(由 Skills Builder 自动统计)
739
754
  glossary_size: 0 # Section 16 领域词汇表条目数(由 Skills Builder 自动统计)
740
- hidden_knowledge_rate: 0 # 隐性知识补全率(0-100),来自 modus-init Step 3.5 访谈问卷
755
+ hidden_knowledge_rate: 0 # 隐性知识补全率(0-100),来自 modus-init Step 4 访谈问卷
741
756
  upstream_skills: # 本 Skill 在 Section 10 中依赖的其他域 Skill(由 Step 4 双向同步维护)
742
757
  - modus-biz-payment
743
758
  downstream_skills: # 依赖本域的其他 Skill(由被依赖方的 Step 4 双向同步维护)
@@ -907,7 +922,7 @@ stateDiagram-v2
907
922
 
908
923
  ## 15. 业务不变量 [invariant]
909
924
 
910
- (无条件生成。来源:2A if/else 推断 + 2D 自定义校验器 + Step 1.4 注释挖掘 + Step 3.5 人工访谈。)
925
+ (无条件生成。来源:2A if/else 推断 + 2D 自定义校验器 + Step 1.4 注释挖掘 + Step 4 人工访谈。)
911
926
 
912
927
  | 不变量描述 | 验证位置 | 违反后果 | 来源 |
913
928
  |---------|---------|---------|------|
@@ -917,7 +932,7 @@ stateDiagram-v2
917
932
 
918
933
  ## 16. 领域词汇表 [model]
919
934
 
920
- (无条件生成。来源:枚举描述 + Javadoc + 代码注释 + Step 3.5 人工访谈。)
935
+ (无条件生成。来源:枚举描述 + Javadoc + 代码注释 + Step 4 人工访谈。)
921
936
 
922
937
  | 术语 | 定义 | 与通用概念的区别 |
923
938
  |------|------|----------------|
@@ -1042,7 +1057,7 @@ layer: "1"
1042
1057
  - 更新时必须更新 `updated` 日期和 `last_referenced`
1043
1058
  - 模式 D 每次执行后必须同步更新 `modus/knowledge-catalog.md`
1044
1059
  - 统一使用 `status` 字段(不使用 `maturity`),枚举值:`draft | verified | proven | stale | archived`
1045
- - 新生成的 Skill 默认写入 `format_version: v2`;存量 7 节 Skill 迁移前标记 `format_version: v1`
1060
+ - 新生成的 Skill 默认写入 `format_version: v3`(17节标准格式);存量 14 节 Skill 保留 `format_version: v2`;存量 7 节 Skill 迁移前标记 `format_version: v1`
1046
1061
 
1047
1062
  ---
1048
1063
 
@@ -1050,8 +1065,11 @@ layer: "1"
1050
1065
 
1051
1066
  ```
1052
1067
  verified 达标条件(全部满足方可从 draft 升为 verified):
1053
- ✅ 条件 1:所有无条件生成节(Section 9/10/13/15/16/17)内容非空且非合法初始占位符
1054
- 注:「暂无发现,随工作流积累」是合法初始内容 质量自检通过
1068
+ ✅ 条件 1:分两类检查
1069
+ 【必须有实质内容的节】Section 2(枚举)、Section 3(业务规则)、Section 5(API)
1070
+ → 不得为空或仅含「暂无发现」占位符(这些节在项目中必然有真实内容可填)
1071
+ 【允许占位符的节】Section 9/10/13/15/16/17(积累型知识)
1072
+ → 「暂无发现,随工作流积累」是合法初始内容,不阻碍 verified 升级
1055
1073
  ✅ 条件 2:质量自检清单(见 Step 6)零 ⚠️ 警告
1056
1074
  新增检查项:Section 17 开发场景速查 ≥ 3 行
1057
1075
  ✅ 条件 3:key_files hash 与当前代码库一致(无 stale 状态)
@@ -1,91 +1,137 @@
1
1
  ---
2
2
  name: modus-tester
3
- description: Use this skill when the Harness orchestrator needs to generate unit tests for code changes. Covers Happy Path, boundary conditions, exception paths, and concurrency scenarios. Generates 03-test-report.md. Triggered by modus-harness in parallel with SubAgents 04 and 05 after Gate A passes.
3
+ description: Use this skill when the Harness orchestrator needs to generate unit tests for changed code after Gate A. Covers three test paths (Happy Path / boundary / exception), uses MockBean isolation, inherits project base test class, and generates 03-test-report.md with HANDOFF block. Triggered by modus-harness in parallel with perf-auditor and security-auditor after Gate A passes.
4
4
  allowed-tools: Read, Write, Glob, Bash
5
5
  disable: false
6
6
  ---
7
7
 
8
8
  # modus-tester(代码测试 SubAgent)
9
9
 
10
- **调用方:** Harness Orchestrator(与 04/05 并行启动)
11
- **输入:** `02-sprint-contract.md` + 代码变更
12
- **产出物:** `modus/plans/active/{story-id}/03-test-report.md` + 单元测试代码
10
+ **调用方:** Harness Orchestrator(Gate A 通过后,与 04/05 并行触发)
11
+ **输入:** `02-sprint-contract.md`(变更文件列表)+ 代码变更 + 业务 Skill(≤ 2 个)
12
+ **产出物:** `modus/plans/active/{story-id}/03-test-report.md` + 测试代码
13
13
 
14
14
  ## 职责
15
15
 
16
- 为本次代码变更生成单元测试,验证核心业务逻辑有测试覆盖,输出测试报告。
16
+ 为本次代码变更生成单元测试,覆盖核心业务逻辑的三条测试路径(Happy Path / 边界条件 / 异常路径),使用 Mock 隔离外部依赖,确保测试独立可重复运行。
17
17
 
18
18
  ---
19
19
 
20
20
  ## 执行流程
21
21
 
22
- ### Step 1:分析代码变更
22
+ ### Step 1:确定测试目标
23
23
 
24
- 读取 `02-sprint-contract.md`,识别需要测试的关键方法:
25
- - Service/Manager 层的核心业务方法
26
- - 有复杂条件分支的逻辑
27
- - `01-analysis.md` 中标注的验收标准对应的逻辑
24
+ 读取 `02-sprint-contract.md` 的 `changed_files`,识别需要测试的类:
28
25
 
29
- ### Step 2:生成测试用例
26
+ **优先级(高 低):**
27
+ 1. Service / Manager 类(核心业务逻辑,必须测试)
28
+ 2. 含复杂条件分支的 Util / Helper 类
29
+ 3. Controller / Facade(仅测试参数校验和权限逻辑)
30
+ 4. Mapper 接口(通常跳过,属于集成测试范围)
30
31
 
31
- 按照 **Happy Path → 边界条件 → 异常路径** 三段式结构设计测试:
32
+ ### Step 2:三路径测试生成
32
33
 
33
- **Happy Path(正常流程)**
34
- - 主流程成功执行
35
- - 返回值正确
34
+ 对每个测试目标,生成以下三类测试用例:
36
35
 
37
- **边界条件(Boundary)**
38
- - null / 空值 / 空集合 / 零值
39
- - 最小值 / 最大值
40
- - 单条记录 / 批量记录
36
+ **Path 1 — Happy Path(正常流程)**
37
+ ```java
38
+ @Test
39
+ void {method}_success() {
40
+ // Given: 构造合法的输入数据
41
+ // When: 调用被测方法
42
+ // Then: 验证返回结果符合预期
43
+ }
44
+ ```
45
+
46
+ **Path 2 — 边界条件(Boundary)**
47
+ ```java
48
+ @Test
49
+ void {method}_withNullInput_throws() { ... }
50
+
51
+ @Test
52
+ void {method}_withEmptyList_returnsEmpty() { ... }
53
+
54
+ @Test
55
+ void {method}_withMaxValue_succeeds() { ... }
56
+ ```
57
+
58
+ **Path 3 — 异常路径(Exception)**
59
+ ```java
60
+ @Test
61
+ void {method}_whenDistributedLockFails_throws() { ... }
62
+
63
+ @Test
64
+ void {method}_whenDownstreamRpcTimeout_throwsServiceException() { ... }
65
+
66
+ @Test
67
+ void {method}_whenDatabaseError_rollsBack() { ... }
68
+ ```
69
+
70
+ ### Step 3:测试代码规范
41
71
 
42
- **异常路径(Exception)**
43
- - 依赖服务调用失败
44
- - 数据不存在
45
- - 业务规则校验失败(如余额不足、状态不合法)
46
- - 并发场景(如分布式锁被占用)
72
+ **Mock 隔离原则:**
73
+ - 使用 `@MockBean`(Spring)或 `@Mock`(Mockito)隔离所有外部依赖
74
+ - 不使用 `@SpringBootTest`(启动全量容器,速度慢),优先使用 `@ExtendWith(MockitoExtension.class)` 或项目已有的轻量基类
75
+ - 数据库操作全部 Mock,不依赖真实数据库
47
76
 
48
- ### Step 3:编写测试代码
77
+ **继承项目基类:**
78
+ - 读取项目已有的测试基类(如 `AbstractBaseTest`、`BaseServiceTest`),继承或参照其 Mock 配置
79
+ - 若无基类,使用 `@ExtendWith(MockitoExtension.class)`
49
80
 
50
- 遵循项目测试规范(从业务 Skill 或现有测试文件中提取),通用原则:
51
- - 使用 Mock 隔离外部依赖(DB、RPC、MQ 等)
52
- - 每个测试方法只测一个场景
53
- - 测试方法命名清晰表达场景:`test_{methodName}_{scenario}_{expectedResult}`
54
- - 断言明确,不只断言 "no exception"
81
+ **断言规范:**
82
+ - 使用 AssertJ JUnit 5 标准断言(`assertThat`/`assertEquals`)
83
+ - 异常测试用 `assertThrows`,验证异常类型和消息
55
84
 
56
- ### Step 4:运行测试(如可执行环境允许)
85
+ ### Step 4:执行测试验证
57
86
 
58
- 如果有可用的测试执行环境:
59
- - 执行新增的测试用例
60
- - 记录通过/失败状态
87
+ ```bash
88
+ {constitution.test_command} # 如 mvn test -pl {module} -Dtest={TestClass}
89
+ ```
90
+
91
+ 测试失败 → 修复测试代码(不修改业务代码)后重试。
61
92
 
62
93
  ---
63
94
 
64
95
  ## 产出物格式(03-test-report.md)
65
96
 
66
97
  ```markdown
67
- # 测试报告
68
-
69
- ## 测试覆盖摘要
70
- - 新增测试用例: {N} 个
71
- - 覆盖方法: {N}
72
- - 通过: {N} | 失败: {N} | 跳过: {N}
98
+ <!--HANDOFF
99
+ agent: "03-tester"
100
+ story_id: "{story-id}"
101
+ gate_status: "passed"
102
+ tests_generated: {N}
103
+ tests_passed: {N}
104
+ coverage_targets:
105
+ - "{ClassName}.{method}(): {覆盖的路径描述}"
106
+ -->
107
+
108
+ # 测试报告 — {Story 标题}
109
+
110
+ ## 测试摘要
111
+ - 生成测试用例: {N} 个
112
+ - 通过: {N} 个 | 失败: {N} 个
113
+ - 覆盖的核心逻辑: {列表}
73
114
 
74
115
  ## 测试用例列表
75
116
 
76
117
  ### {ClassName}Test
77
- | 测试方法 | 场景 | 状态 |
78
- |----------|------|------|
79
- | test_createOrder_success | 正常创建订单 | ✅ |
80
- | test_createOrder_insufficientBalance | 余额不足 | ✅ |
81
- | test_createOrder_concurrentLock | 并发锁冲突 | ✅ |
82
-
83
- ## 覆盖率分析
84
- - 核心业务逻辑:{N}% 覆盖
85
- - 未覆盖的分支:{描述原因}
86
-
87
- ## 验收标准覆盖
88
- | 验收场景 | 对应测试 | 状态 |
89
- |----------|----------|------|
90
- | {从 01-analysis.md 提取} | {测试方法名} | ✅/❌ |
118
+
119
+ | 测试用例 | 路径类型 | 测试场景 | 结果 |
120
+ |---------|---------|---------|------|
121
+ | {method}_success | Happy Path | {场景} | ✅ |
122
+ | {method}_withNull_throws | Boundary | null 输入 | ✅ |
123
+ | {method}_whenLockFail | Exception | 分布式锁获取失败 | ✅ |
124
+
125
+ ## 未覆盖说明
126
+
127
+ {若有意跳过某些场景,说明原因(如:Mapper 接口属于集成测试范畴,本次跳过)}
91
128
  ```
129
+
130
+ ---
131
+
132
+ ## 质量标准
133
+
134
+ - Service / Manager 类的核心业务方法必须有 Happy Path 覆盖
135
+ - 01-analysis.md 中标注的并发/事务风险点必须有对应的异常路径测试
136
+ - 所有测试必须在 Mock 隔离下独立通过,不依赖外部环境
137
+ - **HANDOFF 块必须位于文件最顶部**,`gate_status` 仅在所有测试通过时为 `passed`
@@ -63,6 +63,8 @@ story = tapd_mcp.get_story(story_id)
63
63
 
64
64
  #### 维度三:需求明确度 (Clarity)
65
65
 
66
+ > ⚠️ **刻度方向与复杂度/风险相反**:分值越高 = 需求越清晰(好)。判定树中「明确度=低」触发 harness,「明确度=高」支持 plan,方向勿与其他维度混淆。
67
+
66
68
  | 分值 | 判定条件 |
67
69
  |------|----------|
68
70
  | 高 (3) | 验收标准完整(有具体输入输出)、边界条件明确 |
@@ -98,6 +100,12 @@ story = tapd_mcp.get_story(story_id)
98
100
  - 复杂度=高 且 风险=高
99
101
  - 用户希望全自动从需求到部署
100
102
  → 推荐 harness(双 Loop 全自动流程)
103
+
104
+ **优先级规则(多条件同时满足时):**
105
+ harness > spec > plan > vibe
106
+ 即:若 harness 条件与 spec 条件同时满足,推荐 harness;
107
+ 若 spec 条件与 plan 条件同时满足,推荐 spec;以此类推。
108
+ 向用户展示次优选项以供参考。
101
109
  ```
102
110
 
103
111
  ### Step 5:展示推荐与对比
@@ -179,7 +187,14 @@ D. /modus:harness — 全自动 Harness
179
187
  用户确认后,根据选择自动触发对应模式:
180
188
 
181
189
  - **vibe**:以已整理的任务描述调用 `/modus:vibe`,上下文包含 Story 摘要
182
- - **plan**:以整理好的 prompt 调用 `/modus:plan`,自动跳过 Step 3 的澄清阶段(已通过 auto 确认)
190
+ - **plan**:以整理好的 prompt 调用 `/modus:plan`,在 prompt 末尾附加标记 `[AUTO_MODE: questions_confirmed]` 和答案摘要(格式见下),modus-plan Step 3 识别到此标记后跳过交互式澄清阶段:
191
+ ```
192
+ [AUTO_MODE: questions_confirmed]
193
+ 已确认的关键信息:
194
+ - 业务域: {domain}
195
+ - 核心目标: {一句话目标}
196
+ - 技术约束: {列表,若用户在 Step 6 中补充了约束}
197
+ ```
183
198
  - **spec**:以整理好的 prompt 调用 `/modus:spec`,携带 Story 验收标准作为 Scenario 参考输入
184
199
  - **harness**:直接调用 `/modus:harness {tapd_url}`
185
200