@tea-agent/loop-agent 0.38.2 → 0.38.3
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/CHANGELOG.md +18 -0
- package/README.md +2 -0
- package/bin/loop-agent.js +7 -3
- package/dist/application/task-lifecycle/advance.js +4 -0
- package/dist/build-stamp.json +3 -3
- package/dist/commands/task-advance.js +31 -0
- package/dist/executors/dag-pi-executor.js +58 -1
- package/dist/executors/pi-event-serializer.js +42 -1
- package/dist/executors/pi-executor.js +51 -0
- package/dist/executors/pi-extension-resolver.js +233 -0
- package/dist/executors/pi-sdk-executor.js +187 -59
- package/dist/executors/shell-executor.js +56 -2
- package/dist/executors/shell-write-guard.js +7 -0
- package/dist/task/contract/constants.js +1 -0
- package/dist/task/contract/diff.js +26 -0
- package/dist/task/contract/project.js +5 -0
- package/dist/task/contract/schema.js +6 -1
- package/dist/task/source-prepare/build-draft.js +15 -0
- package/dist/worker/console/pi-readiness.js +4 -4
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-C4bmo3iY.js → abnfDiagram-N423BO3Z-C4kVYweA.js} +1 -1
- package/dist/worker/console/static/assets/{arc-SAD7McOS.js → arc-Bj2M8iO5.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-DAVLUdK1.js → architectureDiagram-T3A2C74G-CLlXe4-6.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-CPPdv4vj.js → blockDiagram-VBNYF7ZC-psEp5xH0.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-D1GRGZax.js → c4Diagram-5PPSVZJV-DeKcOCGJ.js} +1 -1
- package/dist/worker/console/static/assets/channel-CPF4N7pf.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-D_Bq2ZqK.js → chunk-2GRJ4B5K-K0C744p1.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-CPLVtamK.js → chunk-2Q5K7J3B-xbNw4J9-.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DnaZWcL3.js → chunk-5RXB4S5H-DjLaSDUO.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BRTmFgnq.js → chunk-5VM5RSS4-CtiPlKel.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-BRlfYZoH.js → chunk-6Q2QTUOP-DZtolir7.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CjNybD4u.js → chunk-GF5L2VYU-CPcdNeew.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-D3e-74fG.js → chunk-JWPE2WC7-NgHc6V37.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-Br3ir6f2.js → chunk-KBJHAD2P-DQ_T-hg8.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-1NgVuRbh.js → chunk-RYQCIY6F-DgLsxcVP.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-BTYuvuWN.js → chunk-XXDRQBXY-UrVoM9z1.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C2DwA_Y1.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C2DwA_Y1.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BC6Bgosf.js → cose-bilkent-JH36ORCC-CLkYvTb3.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-DV-HypfL.js → cynefin-VYW2F7L2-BwT_xKrE.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-DhTaddO-.js → cynefinDiagram-MW4NZA55-Bi9tuzif.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BnEcOmiI.js → dagre-VZM6K2ZE-BCIqkWBV.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-xphGRVKp.js → diagram-7IWD3JNH-Dip6l9_Z.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-CrdD1mRG.js → diagram-B4RE2ZJO-B-xkh_wK.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-D4YdLsaF.js → diagram-LBJQPF4R-DZO0kTt_.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-LCKyGZ5U.js → diagram-Q27KOJAE-D6ZplNbZ.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-BeiTe7t0.js → diagram-UB23O5K3-BPekbhoS.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-BO2cq8GS.js → ebnfDiagram-BXEA7PRR-BtmaJpK5.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-CmWww3Nt.js → erDiagram-JOGREHBK-6DS0Xc44.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-C2kkUYg5.js → flowDiagram-UKHOOZJN-CihnROSm.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-DY_JZ2iQ.js → ganttDiagram-PKOTCBZU-CZC4zOE2.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-BizhCSw9.js → gitGraphDiagram-DS77QQ5N-Dq1fhzGN.js} +1 -1
- package/dist/worker/console/static/assets/{index-BXN89VPX.js → index-DTZOKgAn.js} +142 -63
- package/dist/worker/console/static/assets/index-Ya5FE7cD.css +1 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-Dlo2eK_d.js → infoDiagram-6WML65LV-DlSl4BGx.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-3EIlIIuZ.js → ishikawaDiagram-WSZJBQD7-snnzFl_U.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DiMDe5Yh.js → journeyDiagram-NVQOT4AX-BDE7qpMx.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-sN553oIN.js → kanban-definition-27J2QSJJ-CD2Ci04G.js} +1 -1
- package/dist/worker/console/static/assets/{linear-D9Py31Ld.js → linear-DdnapKIH.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-D7Occzk_.js → mermaid.core-BVjAT9b8.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-DjDRboiR.js → mindmap-definition-FAOFIHXS-D0yJk-zA.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-Cgc4qlzp.js → pegDiagram-VL7TDLO6-BVo9tFP-.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-DxZj8pKd.js → pieDiagram-7S7Q4E2Y-DnOV-mZ_.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-CJ50MngR.js → quadrantDiagram-CIZ2JOQS-CzUJo58i.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BY-OD8Tr.js → railroadDiagram-AXF67PYL-Bvikrolh.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-CQFButfK.js → requirementDiagram-LRYGKXZP-DtaSVCap.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-BB_QUK_b.js → sankeyDiagram-W5VNT64P-C2c9A0wW.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-CqhXZjyx.js → sequenceDiagram-SI44F4Z6-DmXJcU7r.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-2l1U4rgJ.js → sizeCapture-X5ZJPWSS-B4GUFW92.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-BX1FbrhJ.js → stateDiagram-OKZ733FA-Dsad2MXf.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-B8FB_cNk.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DOSnT7hb.js → swimlanes-SLNWSIFB-DGq48Fbi.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CrZYaWfx.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-DVJQA7AN.js → timeline-definition-Z64GVDOM-CSSi6OFf.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-74uxl9gx.js → vennDiagram-T6HMQDX7-BqyzPrWv.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DsBxlcg_.js → wardleyDiagram-T6FBY63Y-DlznVb6S.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-snuW9Mjw.js → xychartDiagram-ELKLHX3M-CfBcgJ_K.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/operator-chat/open-preview-in-browser.js +328 -0
- package/dist/worker/observe/node-input.js +72 -3
- package/dist/worker/observe/static/dag-history-labels.js +4 -0
- package/dist/worker/observe/static/state.js +2 -2
- package/dist/worker/observe/static/views/dag-inspector.js +51 -0
- package/dist/worker/observe/static/views/session-timeline.js +18 -5
- package/dist/workflows/dag/backend-test-case-coverage-analysis.js +56 -4
- package/dist/workflows/dag/backend-test-scenario-partitions.js +73 -1
- package/dist/workflows/dag/contract-output-registry.js +15 -0
- package/dist/workflows/dag/failure-category.js +4 -0
- package/dist/workflows/dag/frontend-implementation-contract.js +140 -39
- package/dist/workflows/dag/frontend-prewrite-gate.js +87 -135
- package/dist/workflows/dag/frontend-test-case-quality.js +5 -13
- package/dist/workflows/dag/frontend-test-environment-probe.js +227 -0
- package/dist/workflows/dag/frontend-test-markdown.js +61 -0
- package/dist/workflows/dag/frontend-test-result-contract.js +10 -18
- package/dist/workflows/dag/frontend-test-standard-scenarios.js +68 -0
- package/dist/workflows/dag/init-hybrid.js +79 -101
- package/dist/workflows/dag/node-execution.js +119 -8
- package/dist/workflows/dag/prompt.js +15 -1
- package/dist/workflows/dag/rerun-plan.js +22 -3
- package/dist/workflows/dag/structured-output-repair.js +712 -0
- package/dist/workflows/dag/types.js +23 -0
- package/dist/workflows/dag/validate.js +41 -1
- package/docs/operations/local-development-environment.md +1 -5
- package/docs/skills/vetted-skill-registry.md +14 -0
- package/docs/templates/README.md +1 -1
- package/docs/templates/agent-dag.schema.json +44 -0
- package/docs/templates/backend-test-dag.json +2 -2
- package/docs/templates/frontend-test-dag.json +8 -10
- package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +1 -1
- package/package.json +8 -4
- package/skills/analyze-product-requirements/SKILL.md +8 -5
- package/skills/analyze-product-requirements/references/acceptance-criteria.md +1 -1
- package/skills/analyze-product-requirements/references/clarification-and-knowledge.md +10 -6
- package/skills/analyze-product-requirements/references/example.md +50 -0
- package/skills/analyze-product-requirements/references/forward-test-cases.md +11 -7
- package/skills/analyze-product-requirements/references/kb-integration.md +5 -5
- package/skills/analyze-product-requirements/references/product-analysis-schema.md +8 -4
- package/skills/analyze-product-requirements/references/product-requirement-schema.md +2 -2
- package/skills/analyze-product-requirements/references/requirement-clarification-schema.md +1 -1
- package/skills/analyze-product-requirements/scripts/test-validators.mjs +11 -1
- package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +20 -1
- package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +9 -0
- package/skills/codebase-scout/SKILL.md +1 -1
- package/skills/improve-codebase-architecture/SKILL.md +81 -0
- package/skills/improve-codebase-architecture/deepening.md +37 -0
- package/skills/improve-codebase-architecture/html-report.md +123 -0
- package/skills/improve-codebase-architecture/interface-design.md +44 -0
- package/skills/improve-codebase-architecture/language.md +53 -0
- package/dist/worker/console/static/assets/channel-R6oQIDkw.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BPXlmPWI.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BPXlmPWI.js +0 -1
- package/dist/worker/console/static/assets/index-CuH5CNFu.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DJKi0Qel.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-YYe7EEm5.js +0 -8
|
@@ -24,6 +24,7 @@ analysis_status: no-clarification-required
|
|
|
24
24
|
- 无未确认的推断需求。
|
|
25
25
|
### 4.3 待确认问题
|
|
26
26
|
- 无待确认问题。
|
|
27
|
+
- 一致性核对:已逐条比对知识库、ai_workspace、仓库规范与代码现状,未发现冲突条目。
|
|
27
28
|
- 理由:范围、权限、校验、失败恢复和非目标均已由原始需求明确。
|
|
28
29
|
### 4.4 初步非目标
|
|
29
30
|
- 不修改头像。
|
|
@@ -102,3 +103,52 @@ Then:
|
|
|
102
103
|
```
|
|
103
104
|
|
|
104
105
|
故事与输出规范使用同一 ID;故事只引用 AC,AC 正文只在对应输出规范中出现一次。
|
|
106
|
+
|
|
107
|
+
# 需要澄清路径示例(输入 ↔ 规范冲突)
|
|
108
|
+
|
|
109
|
+
需求:查询订单列表支持分页,pageSize 允许值为 5、10、20。
|
|
110
|
+
知识库命中分页规范:允许值为 20、50、100。
|
|
111
|
+
|
|
112
|
+
## Product Analysis 外部事实与冲突条目
|
|
113
|
+
|
|
114
|
+
```md
|
|
115
|
+
## 5. 外部事实
|
|
116
|
+
### 5.1 知识库事实
|
|
117
|
+
- 检索状态:executed-hit。
|
|
118
|
+
- KB-FACT-001:分页允许值为 20、50、100;来源:分页规范 v3 §2;版本:当前有效;与输入关系:冲突。
|
|
119
|
+
### 5.2 代码库事实
|
|
120
|
+
- CODE-FACT-001:列表接口已存在,pageSize 为必填;证据位置:列表 controller;证据类别:代码现状;与输入关系:一致。
|
|
121
|
+
|
|
122
|
+
## 4. 需求分析
|
|
123
|
+
### 4.3 待确认问题
|
|
124
|
+
- P0:分页允许值集合冲突;冲突描述:输入声明「5、10、20」vs 规范声明「20、50、100」;冲突来源:KB-FACT-001;影响范围:backend。
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Clarification Q-* 冲突记录
|
|
128
|
+
|
|
129
|
+
澄清轮中不新增字段,冲突双方声明成对写入推荐理由,最终决策记录裁决结果。
|
|
130
|
+
|
|
131
|
+
```md
|
|
132
|
+
### Q-001 分页允许值
|
|
133
|
+
- 澄清轮次:1
|
|
134
|
+
- 分支:BR-001
|
|
135
|
+
- 优先级:P0
|
|
136
|
+
- 影响范围:backend
|
|
137
|
+
- 推荐答案:采用项目分页规范 20、50、100
|
|
138
|
+
- 推荐理由:输入声明为 5、10、20,项目规范(KB-FACT-001:分页规范 v3 §2)为 20、50、100,两者冲突;代码现状(CODE-FACT-001)未约束允许值集合,需用户裁决。
|
|
139
|
+
- 用户回答:仍使用 5、10、20
|
|
140
|
+
- 最终决策:分页允许值为 5、10、20,覆盖项目分页规范默认值
|
|
141
|
+
- 决策来源:user
|
|
142
|
+
- 状态:confirmed
|
|
143
|
+
- 决策标记:DEC-Q-001
|
|
144
|
+
- 目标位置:后端输出规范分页约定
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Product Requirement 合成
|
|
148
|
+
|
|
149
|
+
```md
|
|
150
|
+
## 4. 业务规则
|
|
151
|
+
- 分页允许值集合为 5、10、20(用户裁决,覆盖项目分页规范默认值)。
|
|
152
|
+
## 7. 决策追溯
|
|
153
|
+
- DEC-Q-001:分页允许值为 5、10、20,已合并到后端输出规范分页约定。
|
|
154
|
+
```
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
需求:登录用户在个人资料页修改自己的昵称;昵称 2–20 个字符;保存失败时保留输入并允许重试;不修改头像。
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
核对:生成产物前直接询问用户是否还有内容需要补充;未收到明确的“无需补充/确认继续”前不冻结 Product Analysis、不生成 complete 产物;用户确认后,三个产物都在 `<project-root>/docs/product-analysis/<requirement-id>/`,三者 `analysis_scope` 均为 `frontend`;Product Analysis 为 `no-clarification-required` 且不含正式 AC,其“原始需求”包含有效 `inline:sha256:*`
|
|
12
|
+
核对:生成产物前直接询问用户是否还有内容需要补充;未收到明确的“无需补充/确认继续”前不冻结 Product Analysis、不生成 complete 产物;用户确认后,三个产物都在 `<project-root>/docs/product-analysis/<requirement-id>/`,三者 `analysis_scope` 均为 `frontend`;Product Analysis 为 `no-clarification-required` 且不含正式 AC,其“原始需求”包含有效 `inline:sha256:*` 身份,“待确认问题”包含 `- 一致性核对:…未发现冲突条目。` 行且无任何“与输入关系:冲突”事实,每个前端初步输出规范包含有效页面路由;Clarification 使用三章精简结构、记录相同的原始需求身份和 `内容补充:用户已确认无需补充`,且没有 BR/Q/DEC;Product Requirement 为 complete,不含“默认假设”或“未决事项”;故事与同 ID 输出规范一一对应,每个前端规范均包含有效页面路由。
|
|
13
13
|
|
|
14
14
|
## Case 2:需要逐题澄清
|
|
15
15
|
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
|
|
66
66
|
核对:Product Analysis 可记录 `CODE-FACT-*`、证据路径和现状;Clarification 可引用该证据辅助判断,但不得把现状自动视为目标决策;Product Requirement 只写“仅管理员可以导出用户数据”等产品规则,不包含 `CODE-FACT-*`、`src/auth/permission.ts`、`role=admin`、代码符号、模块结构或当前实现过程。
|
|
67
67
|
|
|
68
|
-
## Case 8
|
|
68
|
+
## Case 8:分页允许值来源与冲突澄清
|
|
69
69
|
|
|
70
70
|
```text
|
|
71
71
|
显式调用 `analyze-product-requirements` skill,参数:`target=backend`。
|
|
@@ -73,7 +73,7 @@ A:需求明确 pageSize 为必填,但未给出允许值集合。
|
|
|
73
73
|
B:需求明确 pageSize 允许值为 5、10、20。
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
知识库分页规范允许值为 `20/50/100`。核对:A 使用有效知识库规范的 `20/50/100`;B
|
|
76
|
+
知识库分页规范允许值为 `20/50/100`。核对:A 使用有效知识库规范的 `20/50/100`;B 的输入值与知识库规范冲突(集合差异),必须进入待确认问题(对应事实标记 `与输入关系:冲突`,条目含 `冲突来源` 引用)并向用户逐题澄清,不得静默采用输入或规范;用户裁决后以确认值为准。知识库不可用或未命中时,A 才使用默认集合 `10/20/50/100`。不得从知识库/API 文档自动带入路径、方法、参数名、必填性、默认值、响应、错误码或 DTO。
|
|
77
77
|
|
|
78
78
|
## Case 9:项目状态与空数据规范
|
|
79
79
|
|
|
@@ -89,7 +89,7 @@ B:需求明确 pageSize 允许值为 5、10、20。
|
|
|
89
89
|
|
|
90
90
|
## Case 12:原始明确行为不伪造问题
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
原始需求明确指定页面路由、权限和错误恢复方式,且与有效规范(知识库、ai_workspace、仓库规范)及代码现状核对一致。核对:这些内容以 `source-requirement` 事实直接合并,不生成 `Q-*`、`DEC-Q-*` 或二次确认;任一通道与输入冲突时不得免澄清。
|
|
93
93
|
|
|
94
94
|
## Case 13:页面路由
|
|
95
95
|
|
|
@@ -111,9 +111,9 @@ B:需求明确 pageSize 允许值为 5、10、20。
|
|
|
111
111
|
|
|
112
112
|
分别使用“看似不涉及项目规范”的简单需求、让 `kb-design-assist` 返回无结果,以及让调用失败。核对:简单需求仍先从需求提取检索词并真实调用知识库,不允许 `not-executed`;无结果记录 `executed-no-match`,在有仓库时降级为受限、定向的代码库规范搜索,无仓库时按 unknown 分流;调用失败记录 `unavailable`,必须先说明失败原因并询问用户选择“修复后重试”或“跳过知识库”,未选择前不得预扫描项目资料、探索代码库或生成 complete 产物;选择修复后按重试结果继续,明确选择跳过后才允许降级。不得把“未执行”误写成“未命中”,也不得绕过确认门禁。
|
|
113
113
|
|
|
114
|
-
## Case 18
|
|
114
|
+
## Case 18:知识库与需求冲突(四通道)
|
|
115
115
|
|
|
116
|
-
原始需求明确分页允许值为 `5/10/20`,知识库规范为 `20/50/100
|
|
116
|
+
原始需求明确分页允许值为 `5/10/20`,知识库规范为 `20/50/100`;另提供与原始错误恢复行为冲突的设计规范、ai_workspace 校验规则冲突和代码现状冲突各一份。核对:四类冲突全部进入待确认问题并逐题澄清(含分页允许值,不得静默采用输入或规范);每条冲突条目成对列出输入声明与规范/代码声明、标注 `冲突来源`,对应事实标记 `与输入关系:冲突`;用户裁决前保持 pending,裁决后以确认值为准。
|
|
117
117
|
|
|
118
118
|
## Case 19:Web + Remote 接口范围
|
|
119
119
|
|
|
@@ -125,7 +125,7 @@ B:需求明确 pageSize 允许值为 5、10、20。
|
|
|
125
125
|
|
|
126
126
|
## Case 20A:知识库、代码库与澄清顺序
|
|
127
127
|
|
|
128
|
-
使用同时包含权限歧义、状态约定和已有相似实现的需求。核对执行轨迹严格为:从原始需求提取检索计划 → 调用 `kb-design-assist` → 项目资料预扫描 → 按知识结论定向探索代码库 → 汇总冲突与 unknown → 逐题向用户澄清。不得在知识库门禁通过前搜索代码,也不得在代码事实尚可查证时提前询问用户。
|
|
128
|
+
使用同时包含权限歧义、状态约定和已有相似实现的需求。核对执行轨迹严格为:从原始需求提取检索计划 → 调用 `kb-design-assist` → 项目资料预扫描 → 按知识结论定向探索代码库 → 执行「输入↔规范一致性核对」→ 汇总冲突与 unknown → 逐题向用户澄清。不得在知识库门禁通过前搜索代码,也不得在代码事实尚可查证时提前询问用户。
|
|
129
129
|
|
|
130
130
|
## Case 21:提示词冻结与来源身份
|
|
131
131
|
|
|
@@ -142,3 +142,7 @@ B:需求明确 pageSize 允许值为 5、10、20。
|
|
|
142
142
|
## Case 23:严格结构与全局唯一性
|
|
143
143
|
|
|
144
144
|
分别向三个产物 frontmatter 注入 `source_path`,让两个故事复用同一个 AC ID,并把 complete Clarification 的“最终决策”改为“未形成”。核对:额外 frontmatter 字段、重复 AC ID 和未形成最终决策都被 validator 拒绝。
|
|
145
|
+
|
|
146
|
+
## Case 24:输入与规范冲突必须澄清
|
|
147
|
+
|
|
148
|
+
需求:昵称 1–30 个字符;知识库/ai_workspace 规范为 2–20 个字符。核对:输入声明与规范冲突必须进入待确认问题(冲突描述成对列出双方声明、含 `冲突来源` 引用,对应事实标记 `与输入关系:冲突`),逐题澄清,用户裁决前保持 pending;用户确认后 Q-* 为 confirmed/user,Product Requirement 采用确认值。构造以下 Product Analysis 时 validator 必须拒绝:(a) 事实标记 `与输入关系:冲突` 但待确认问题未引用其 ID;(b) `no-clarification-required` 且存在冲突标记;(c) `no-clarification-required` 且待确认问题缺少 `- 一致性核对:…未发现冲突条目。` 行;构造 Clarification 未覆盖 PA 冲突条目(冲突事实 ID 未出现在任何 Q-*)时,complete 校验必须拒绝。
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
需求分析优先查询设计系统、交互/文案规范、用户可见状态枚举、共享状态组件、权限可见性、错误语义和分页允许值。Controller、Service、Entity、Response、Remote、Web API 或 `interfaces.md` 等纯实现规范仅用于判断当前问题是否属于下游技术设计,不得据此扩写产品需求。
|
|
15
15
|
|
|
16
|
-
知识库状态已确定或用户确认跳过后,再按固定顺序预扫描 `<project-root>/ai_workspace/project-how-to`、`code-specification`、`project-business
|
|
16
|
+
知识库状态已确定或用户确认跳过后,再按固定顺序预扫描 `<project-root>/ai_workspace/project-how-to`、`code-specification`、`project-business`,然后才进入常规代码搜索。目录缺失不阻断;命中内容统一记录为 `CODE-FACT-*` 条目并标注证据类别:项目规范,参与「输入↔规范一致性核对」。仓库规范文档(仓库级指令、README、设计系统、架构规范)同样记录为 `CODE-FACT-*` 并标注证据类别:项目规范。
|
|
17
17
|
|
|
18
18
|
## 结果状态
|
|
19
19
|
|
|
@@ -36,18 +36,18 @@
|
|
|
36
36
|
|
|
37
37
|
## 事实与优先级
|
|
38
38
|
|
|
39
|
-
每条有效结果使用 `KB-FACT
|
|
39
|
+
每条有效结果使用 `KB-FACT-*`,记录规范事实、来源文档及定位、版本/生效状态、适用范围、需求影响、置信度和与输入关系(一致 | 补充 | 冲突)。事实条目使用单行格式:`- <KB|CODE>-FACT-<编号>:<事实>;来源:<文档/证据定位>;证据类别:<项目规范|代码现状>(仅 CODE-FACT);与输入关系:<一致|补充|冲突>`。标记为"冲突"的事实必须被 Product Analysis"待确认问题"的冲突条目引用。过期、适用范围不明、相互冲突或无法定位来源的结果不得作为已确认规范,只能记录为冲突或 unknown。
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
产品行为来源优先级(仅用于「输入↔规范一致性核对」与冲突澄清完成、用户裁决后的合成默认,不构成跳过澄清的依据):
|
|
42
42
|
|
|
43
43
|
1. 用户已确认决策。
|
|
44
44
|
2. 原始需求明确内容。
|
|
45
45
|
3. 当前有效且适用于本项目的知识库规范。
|
|
46
46
|
4. 模型推断或通用兜底。
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
"原始需求明确内容"不等于"无冲突":输入声明与有效规范(知识库、ai_workspace 项目资料、仓库规范文档)或代码现状冲突时,保留证据并生成产品澄清问题,用户裁决前不得按优先级静默采用输入或规范。知识库事实只能填补项目规范,不得发明业务范围、业务规则或用户意图。
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
分页允许值与其他规则一样参与「输入↔规范一致性核对」:输入与有效知识库分页规范冲突(含集合差异、子集或超集)时进入澄清,用户裁决后以确认值为准;无冲突时遵循:原始需求/用户确认 > 有效知识库分页规范 > 固定兜底 `10/20/50/100`。即使知识库命中 API 文档,也不得自动带入路径、方法、参数名、必填性、默认值、响应结构、错误码或 DTO。
|
|
51
51
|
|
|
52
52
|
## 产物边界
|
|
53
53
|
|
|
@@ -18,7 +18,9 @@ Frontmatter 只允许以上五个字段,不得增加来源路径、项目根
|
|
|
18
18
|
|
|
19
19
|
固定章节:原始需求、需求概述、业务目标、需求分析、外部事实。原始需求必须包含 `- 原始需求身份:inline:sha256:<64位小写十六进制>` 或 `- 原始需求身份:file:sha256:<64位小写十六进制>`,并保留准确原文;inline 摘要只绑定正文,file 摘要同时绑定规范化真实路径与正文,均使用 `scripts/compute-source-identity.mjs` 生成。不得把原始路径另写入 frontmatter。
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
需求分析包含明确需求、推断需求、待确认问题、初步非目标;外部事实包含知识库事实、代码库事实。”知识库事实”必须先记录 `executed-hit | executed-no-match | unavailable` 状态;每个新 requirement 都必须真实执行知识检索,不允许未执行状态。若 complete 流程最终仍记录 `unavailable`,必须同时记录 `- 用户处置:已确认跳过知识库`,否则不得生成本产物。有效事实使用 `KB-FACT-*`,包含规范事实、来源文档及定位、版本/生效状态、适用范围、需求影响、置信度和与输入关系。”代码库事实”继续使用 `CODE-FACT-*`(ai_workspace 项目资料与仓库规范文档统一归入此节),除上述字段外必须标注证据类别(项目规范 | 代码现状)和与输入关系。
|
|
22
|
+
|
|
23
|
+
事实条目强制使用单行格式:`- <KB|CODE>-FACT-<编号>:<事实>;来源:<文档/证据定位>;证据类别:<项目规范|代码现状>(仅 CODE-FACT 必填);与输入关系:<一致|补充|冲突>`。与输入关系为”冲突”的事实,其 ID 必须被”待确认问题”的冲突条目引用。
|
|
22
24
|
|
|
23
25
|
按 scope 追加“初步前端用户故事/初步前端输出规范”或“初步后端用户故事/初步后端输出规范”。不得生成独立用户角色或验收标准汇总。
|
|
24
26
|
|
|
@@ -32,10 +34,12 @@ Frontmatter 只允许以上五个字段,不得增加来源路径、项目根
|
|
|
32
34
|
|
|
33
35
|
状态变量、UI 状态、空数据、loading、error、disabled、错误文案和兜底行为必须优先采用 `kb-design-assist` 查明的当前有效项目规范,再核验设计系统、共享组件和同类实现;未查明时标为 unknown,不得把通用模式写成项目事实。影响产品行为或验收的 unknown 进入待确认问题;纯实现/代码落点 unknown 只保留在外部事实中。
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
后端分页:每页条数允许值参与「输入↔规范一致性核对」。输入与有效分页规范冲突(含集合差异、子集或超集)时,该冲突必须进入待确认问题澄清,用户裁决后以确认值为准;输入未说明时优先使用 `kb-design-assist` 返回的当前有效分页规范,仍未查明才按默认集合 `10`、`20`、`50`、`100` 生成。不得因此把知识库/API 文档的路径、方法、参数名、必填性、默认值、响应、错误码或 DTO 自动带入。Validator 不解析或推断分页允许值集合;该规则由生成流程和 forward-test 核对。
|
|
36
38
|
|
|
37
39
|
Product Analysis 只记录验收关注点,不得出现正式 `AC-FE-*`、`AC-BE-*` 或 Given/When/Then 块。
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
推断需求一律属于未确认产品内容。任何推断需求,以及原始需求、知识库、项目资料、仓库规范文档、代码核验或分析过程中发现的含糊、缺失、冲突、多种合理解释或目标行为 unknown,都必须进入待确认问题并在后续逐题向用户澄清。纯代码位置、符号、复用点和实现方式不属于产品需求,继续留在代码库事实中;纯实现/技术细节冲突只记录"与输入关系:冲突"的事实,不生成问题。
|
|
42
|
+
|
|
43
|
+
「输入↔规范一致性核对」标记为"冲突"的条目必须进入待确认问题,采用如下结构:冲突描述(`输入声明:…` 与 `规范/代码声明:…` 成对列出)、`冲突来源:<KB-FACT-编号 | CODE-FACT-编号>`、影响范围(`common | frontend | backend | both`)与优先级(默认 P0)。冲突条目只陈述双方声明与来源,不得预选边;推荐职能由 Step 2 访谈轮承担。
|
|
40
44
|
|
|
41
|
-
`no-clarification-required`
|
|
45
|
+
`no-clarification-required` 只允许在”推断需求”包含独立一行 `- 无未确认的推断需求。` 且”待确认问题”包含独立一行 `- 无待确认问题。` 时使用;待确认问题可另写理由和一行 `- 一致性核对:…未发现冲突条目。`,但不得出现问题标记、优先级、问句或其他未确认产品内容;存在任何”与输入关系:冲突”的事实不得使用本状态。`ready-for-clarification` 至少包含一个带优先级或问号的问题。
|
|
@@ -16,7 +16,7 @@ Frontmatter 只允许以上五个字段,不得增加来源路径、项目根
|
|
|
16
16
|
|
|
17
17
|
固定章节:需求概述、业务目标、需求范围、业务规则、决策追溯。需求范围包含“已确认范围”和“非目标”。`pending` 与 `complete` 均禁止“默认假设”章节。`pending` 文档另含“未决事项”;`complete` 文档禁止“未决事项”。不得生成独立用户角色、验收标准汇总、前后端契约、Open Questions、测试建议或独立边界 case 章节。
|
|
18
18
|
|
|
19
|
-
Product Requirement 只描述目标产品行为,不承载知识检索或代码侦察记录。不得包含 `KB-FACT-*`、`CODE-FACT
|
|
19
|
+
Product Requirement 只描述目标产品行为,不承载知识检索或代码侦察记录。不得包含 `KB-FACT-*`、`CODE-FACT-*`、知识库/仓库文件路径、代码级类/函数/组件符号、模块调用关系、数据表名、证据位置、当前实现过程或实现算法。产品层的页面或组件名称仍可用于描述用户可见输出。当前有效知识库规范在不与用户决策或原始需求冲突时可转换为项目既定的产品规则;与输入冲突时必须先经澄清、由用户裁决,裁决后方可转换。代码库事实只可在经用户确认或被原始需求明确要求后转换为不含实现细节的产品规则。原始证据保留在 Product Analysis 或 Clarification。
|
|
20
20
|
|
|
21
21
|
机器校验至少拦截:`KB-FACT-*`、`CODE-FACT-*`、常见仓库路径(如 `src/`)、`*Controller/*Service/*Repository/*Handler/*Middleware` 符号,以及“证据位置”。其余实现泄漏仍按本契约人工遵守。知识库/仓库 API 技术惯例仅可在分析与澄清中查证;写入本产物的参数名、必填性、默认值必须来自原始需求或用户确认。
|
|
22
22
|
|
|
@@ -30,7 +30,7 @@ Product Requirement 只描述目标产品行为,不承载知识检索或代码
|
|
|
30
30
|
|
|
31
31
|
状态变量、UI 状态、空数据、loading、error、disabled、错误文案和兜底行为必须遵循 `kb-design-assist` 或项目资料查明的当前有效规范,保留项目真实枚举、共享组件、文案和交互方式;影响产品行为的 unknown 未澄清前不得 complete,纯实现/代码落点 unknown 不进入本产物。
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
后端分页允许值在澄清完成后按”用户确认/原始需求 > 当前有效知识库分页规范 > 默认集合 `10`、`20`、`50`、`100`”确定;输入与有效分页规范冲突(含集合差异、子集或超集)必须先经澄清、由用户裁决,未裁决不得 complete。参数名、必填性、默认值和其他 API 契约必须来自原始需求或用户确认,不得从知识库/API 文档自动带入。Validator 不解析或推断分页允许值集合;该规则由生成流程和 forward-test 核对。
|
|
34
34
|
|
|
35
35
|
正式 `AC-FE-*` 或 `AC-BE-*` 作为四级标题嵌入对应输出规范。故事的验收标准引用必须与该规范中的 AC 完全一致;AC 遵循 `acceptance-criteria.md`。
|
|
36
36
|
每个 AC ID 在整个 Product Requirement 中必须全局唯一,不得在不同故事或不同输出规范中复用。
|
|
@@ -53,7 +53,7 @@ Frontmatter 只允许以上六个字段,不得增加来源路径、项目根
|
|
|
53
53
|
|
|
54
54
|
Clarification 与 Product Requirement 的状态必须一致:`pending` 只能配对 `pending`,`complete` 只能配对 `complete`。`--allow-pending` 只允许校验前一种内部中间状态;不带参数的交付校验只接受后一种。无需澄清的精简结构只能直接生成 complete,不存在 pending 精简结构。
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
原始需求已经明确、与有效规范及代码现状核对一致且不存在冲突的产品行为作为 `source-requirement` 事实直接合并,不生成 `Q-*`、`DEC-Q-*` 或 `confirmed/user` 伪记录;输入与有效规范或代码现状冲突时不得免澄清。代码事实用于查证现状,不作为产品决策来源;实现事实 unknown 不生成澄清问题。
|
|
57
57
|
|
|
58
58
|
`complete` 要求:
|
|
59
59
|
|
|
@@ -58,6 +58,7 @@ analysis_status: no-clarification-required
|
|
|
58
58
|
- 无未确认的推断需求。
|
|
59
59
|
### 4.3 待确认问题
|
|
60
60
|
- 无待确认问题。
|
|
61
|
+
- 一致性核对:已逐条比对知识库、ai_workspace、仓库规范与代码现状,未发现冲突条目。
|
|
61
62
|
- 理由:范围、权限和结果已经明确。
|
|
62
63
|
### 4.4 初步非目标
|
|
63
64
|
- 不修改头像。
|
|
@@ -277,7 +278,7 @@ expectPass("valid V4 analysis", analysisValidator, [analysisPath, "--target", "f
|
|
|
277
278
|
expectFail("analysis target mismatch", analysisValidator, [analysisPath, "--target", "backend"], "does not match");
|
|
278
279
|
expectFail("analysis rejects extra frontmatter fields", analysisValidator, [variant("analysis-extra-frontmatter.md", analysis.replace("analysis_status: no-clarification-required", "analysis_status: no-clarification-required\nsource_path: /private/customer/prd.md"))], "unsupported field source_path");
|
|
279
280
|
expectFail("analysis requires source identity", analysisValidator, [variant("analysis-no-source-identity.md", analysis.replace(`- 原始需求身份:${sourceIdentity}\n`, ""))], "原始需求身份");
|
|
280
|
-
const analysisWithKnowledgeHit = analysis.replace("- 检索状态:executed-no-match。", "- 检索状态:executed-hit。\n- KB-FACT-001
|
|
281
|
+
const analysisWithKnowledgeHit = analysis.replace("- 检索状态:executed-no-match。", "- 检索状态:executed-hit。\n- KB-FACT-001:采用项目统一空状态组件;来源为当前有效设计系统;与输入关系:补充。");
|
|
281
282
|
writeFileSync(analysisPath, analysisWithKnowledgeHit);
|
|
282
283
|
expectPass("analysis accepts executed-hit with KB fact", analysisValidator, [analysisPath, "--target", "frontend"]);
|
|
283
284
|
writeFileSync(analysisPath, analysis);
|
|
@@ -290,6 +291,11 @@ const analysisWithKnowledgeUnavailable = analysis.replace("- 检索状态:exec
|
|
|
290
291
|
writeFileSync(analysisPath, analysisWithKnowledgeUnavailable);
|
|
291
292
|
expectPass("analysis unavailable accepts user skip confirmation", analysisValidator, [analysisPath, "--target", "frontend"]);
|
|
292
293
|
writeFileSync(analysisPath, analysis);
|
|
294
|
+
expectFail("analysis fact must declare 与输入关系", analysisValidator, [variant("analysis-fact-no-relation.md", analysis.replace("- 检索状态:executed-no-match。", "- 检索状态:executed-hit。\n- KB-FACT-001:采用项目统一空状态组件;来源为当前有效设计系统。"))], "must declare 与输入关系");
|
|
295
|
+
expectFail("analysis CODE-FACT must declare 证据类别", analysisValidator, [variant("analysis-code-fact-no-evidence-class.md", analysis.replace("- 未提供代码仓库。", "- CODE-FACT-001:昵称校验已在表单层实现;证据位置:表单校验;与输入关系:一致。"))], "must declare 证据类别");
|
|
296
|
+
expectFail("analysis conflict fact must be referenced by 待确认问题", analysisValidator, [variant("analysis-conflict-unreferenced.md", analysis.replace("- 检索状态:executed-no-match。", "- 检索状态:executed-hit。\n- KB-FACT-001:昵称允许 1–30 字符;来源:昵称规范 §2;与输入关系:冲突。"))], "not referenced by 待确认问题");
|
|
297
|
+
expectFail("no-clarification analysis rejects conflict facts", analysisValidator, [variant("analysis-conflict-no-clarification.md", analysis.replace("- 检索状态:executed-no-match。", "- 检索状态:executed-hit。\n- KB-FACT-001:昵称允许 1–30 字符;来源:昵称规范 §2;与输入关系:冲突。\n- P0:昵称长度冲突;冲突描述:输入声明「2–20 字符」vs 规范声明「1–30 字符」;冲突来源:KB-FACT-001;影响范围:frontend。"))], "cannot contain facts marked 与输入关系:冲突");
|
|
298
|
+
expectFail("no-clarification analysis requires 一致性核对 conclusion", analysisValidator, [variant("analysis-no-check-line.md", analysis.replace("- 一致性核对:已逐条比对知识库、ai_workspace、仓库规范与代码现状,未发现冲突条目。\n", ""))], "must record a 一致性核对 line");
|
|
293
299
|
expectFail("analysis rejects formal AC", analysisValidator, [variant("analysis-ac.md", analysis.replace("验收关注点:", "验收关注点:AC-FE-001 "))], "must use acceptance concerns");
|
|
294
300
|
expectFail("analysis requires matching spec", analysisValidator, [variant("analysis-no-spec.md", analysis.replace("### FE-US-001 修改昵称\n- 页面/组件", "### FE-US-002 修改昵称\n- 页面/组件"))], "missing output specification");
|
|
295
301
|
expectFail("analysis rejects standalone roles", analysisValidator, [variant("analysis-roles.md", analysis.replace("## 4. 需求分析", "## 用户角色\n- 已登录用户。\n## 4. 需求分析"))], "must not contain standalone");
|
|
@@ -488,6 +494,10 @@ expectPass("complete question clarification with DEC markers", clarificationVali
|
|
|
488
494
|
expectFail("complete clarification rejects unformed final decision", clarificationValidator, [analysisPath, variant("clarification-unformed-decision.md", completeQuestionClarification.replace("- 最终决策:保存成功后展示项目统一成功提示", "- 最终决策:未形成")), requirementPath], "must contain a formed final decision");
|
|
489
495
|
expectPass("requirement with DEC markers", requirementValidator, [requirementPath, "--target", "frontend"]);
|
|
490
496
|
expectFail("complete clarification requires shared-understanding marker", clarificationValidator, [analysisPath, variant("clarification-no-shared.md", completeQuestionClarification.replace("- 共同理解:已确认\n", "")), requirementPath], "共同理解:已确认");
|
|
497
|
+
const conflictReadyAnalysis = readyAnalysis
|
|
498
|
+
.replace("- P1:保存成功后使用哪种反馈?", "- P0:昵称长度冲突;冲突描述:输入声明「2–20 字符」vs 规范声明「1–30 字符」;冲突来源:KB-FACT-001;影响范围:frontend。")
|
|
499
|
+
.replace("- 检索状态:executed-no-match。", "- 检索状态:executed-hit。\n- KB-FACT-001:昵称允许 1–30 字符;来源:昵称规范 §2;与输入关系:冲突。");
|
|
500
|
+
expectFail("complete clarification must cover PA conflict facts", clarificationValidator, [variant("conflict-analysis-uncovered.md", conflictReadyAnalysis), clarificationPath, requirementPath], "must be covered by a Q-* record");
|
|
491
501
|
expectFail("analysis frontend output requires page route", analysisValidator, [variant("analysis-no-route.md", analysis.replace("- 页面路由:/account/profile\n", "")), "--target", "frontend"], "missing field 页面路由");
|
|
492
502
|
expectFail("analysis route must be a product path", analysisValidator, [variant("analysis-bad-route.md", analysis.replace("- 页面路由:/account/profile", "- 页面路由:ProfileRoute 组件")), "--target", "frontend"], "must start with /");
|
|
493
503
|
const embeddedRouteAnalysis = analysis.replace("- 页面路由:/account/profile", "- 页面路由:不适用;嵌入 /account/profile 页面");
|
|
@@ -54,11 +54,30 @@ const inferenceLines = contentLines(inferences);
|
|
|
54
54
|
const questionLines = contentLines(questions);
|
|
55
55
|
const noInferenceSentinel = /^-\s*无未确认的推断需求[。.]?$/.test(inferenceLines[0] ?? "");
|
|
56
56
|
const noQuestionSentinel = /^-\s*无待确认问题[。.]?$/.test(questionLines[0] ?? "");
|
|
57
|
-
const unexpectedQuestionLines = questionLines.slice(1).filter((line) => !/^-\s*理由[::]\s*\S/.test(line));
|
|
57
|
+
const unexpectedQuestionLines = questionLines.slice(1).filter((line) => !/^-\s*理由[::]\s*\S/.test(line) && !/^-\s*一致性核对[::]\s*\S/.test(line));
|
|
58
58
|
if (status === "no-clarification-required" && (!noInferenceSentinel || inferenceLines.length !== 1)) errors.push("no-clarification-required analysis must declare no unconfirmed inferred requirements.");
|
|
59
59
|
if (status === "no-clarification-required" && (!noQuestionSentinel || unexpectedQuestionLines.length)) errors.push("no-clarification-required analysis must declare no pending questions.");
|
|
60
60
|
if (status === "no-clarification-required" && /(?:\bQ-\d{3,}\b|\bBR-\d{3,}\b|\bP[012]\b|[??])/.test(questions)) errors.push("no-clarification-required analysis cannot contain question markers, priorities, branches, or question sentences.");
|
|
61
61
|
if (status === "ready-for-clarification" && !/(?:\bP[012]\b|[??])/.test(questions)) errors.push("ready-for-clarification analysis must contain at least one prioritized or explicit question.");
|
|
62
|
+
// 「输入↔规范一致性核对」检查:事实行格式、冲突标记与待确认问题引用
|
|
63
|
+
const factLines = facts.split(/\r?\n/).filter((line) => /^[ \t]*-[ \t]*(?:KB|CODE)-FACT-\d+\b/.test(line));
|
|
64
|
+
for (const line of factLines) {
|
|
65
|
+
const id = line.match(/\b(?:KB|CODE)-FACT-\d+\b/)?.[0];
|
|
66
|
+
if (!/与输入关系[::]\s*(?:一致|补充|冲突)/.test(line)) errors.push(`${id} must declare 与输入关系:一致|补充|冲突.`);
|
|
67
|
+
if (/^[ \t]*-[ \t]*CODE-FACT-\d+\b/.test(line) && !/证据类别[::]\s*(?:项目规范|代码现状)/.test(line)) errors.push(`${id} must declare 证据类别:项目规范|代码现状.`);
|
|
68
|
+
}
|
|
69
|
+
const conflictFactIds = factLines.filter((line) => /与输入关系[::]\s*冲突/.test(line)).map((line) => line.match(/\b(?:KB|CODE)-FACT-\d+\b/)?.[0]);
|
|
70
|
+
for (const id of conflictFactIds) {
|
|
71
|
+
if (!questions.includes(id)) errors.push(`${id} is marked 与输入关系:冲突 but is not referenced by 待确认问题.`);
|
|
72
|
+
}
|
|
73
|
+
const citedConflictIds = [...(questions.match(/冲突来源[::][^\n]*/g) ?? [])].flatMap((line) => line.match(/\b(?:KB|CODE)-FACT-\d+\b/g) ?? []);
|
|
74
|
+
for (const id of citedConflictIds) {
|
|
75
|
+
if (!conflictFactIds.includes(id)) errors.push(`${id} cited as 冲突来源 but its fact is not marked 与输入关系:冲突.`);
|
|
76
|
+
}
|
|
77
|
+
if (status === "no-clarification-required") {
|
|
78
|
+
if (conflictFactIds.length > 0) errors.push("no-clarification-required analysis cannot contain facts marked 与输入关系:冲突.");
|
|
79
|
+
if (!/^[ \t]*-[ \t]*一致性核对[::][^\n]*未发现冲突条目/m.test(questions)) errors.push("no-clarification-required analysis must record a 一致性核对 line stating no conflicts found.");
|
|
80
|
+
}
|
|
62
81
|
if (/\bAC-(?:FE|BE)-\d{3,}\b|^Given[::]|^When[::]|^Then[::]/m.test(text)) errors.push("Product Analysis must use acceptance concerns, not formal AC IDs or Given/When/Then blocks.");
|
|
63
82
|
if (/^##\s+(?:\d+[.、]?\s*)?(?:用户角色|初步验收标准汇总)\s*$/m.test(text)) errors.push("Product Analysis must not contain standalone 用户角色 or 初步验收标准汇总 sections.");
|
|
64
83
|
|
|
@@ -104,6 +104,15 @@ if (!questionBlocks.length) {
|
|
|
104
104
|
if (status === "complete" && !/^[ \t]*-[ \t]*共同理解[::][ \t]*已确认\s*$/m.test(section(clarification.text, 2, "决策索引") ?? "")) {
|
|
105
105
|
errors.push("Complete question-based clarification must record 共同理解:已确认 in 决策索引.");
|
|
106
106
|
}
|
|
107
|
+
// 「输入↔规范一致性核对」闭环:PA 待确认问题的冲突事实必须被 Q-* 覆盖
|
|
108
|
+
const analysisAnalysis = section(analysis.text, 2, "需求分析") ?? "";
|
|
109
|
+
const paQuestions = section(analysisAnalysis, 3, "待确认问题") ?? "";
|
|
110
|
+
const paConflictIds = [...(paQuestions.match(/冲突来源[::][^\n]*/g) ?? [])].flatMap((line) => line.match(/\b(?:KB|CODE)-FACT-\d+\b/g) ?? []);
|
|
111
|
+
for (const id of [...new Set(paConflictIds)]) {
|
|
112
|
+
const covering = questionBlocks.filter((block) => block.text.includes(id));
|
|
113
|
+
if (!covering.length) errors.push(`${id} referenced by Product Analysis pending questions must be covered by a Q-* record.`);
|
|
114
|
+
else if (status === "complete" && !covering.some((block) => (field(block.text, "状态") ?? "") === "confirmed")) errors.push(`${id} must be confirmed by an explicit user answer before clarification can be complete.`);
|
|
115
|
+
}
|
|
107
116
|
}
|
|
108
117
|
|
|
109
118
|
printResult("Requirement Clarification", clarification.path, errors);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: improve-codebase-architecture
|
|
3
|
+
description: Find deepening opportunities in a codebase, informed by the domain language in CONTEXT.md and the decisions in docs/adr/. Use when the user wants to improve architecture, find refactoring opportunities, consolidate tightly-coupled modules, or make a codebase more testable and AI-navigable.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Improve Codebase Architecture
|
|
7
|
+
|
|
8
|
+
Surface architectural friction and propose **deepening opportunities** — refactors that turn shallow modules into deep ones. The aim is testability and AI-navigability.
|
|
9
|
+
|
|
10
|
+
## Glossary
|
|
11
|
+
|
|
12
|
+
Use these terms exactly in every suggestion. Consistent language is the point — don't drift into "component," "service," "API," or "boundary." Full definitions in [language.md](language.md).
|
|
13
|
+
|
|
14
|
+
- **Module** — anything with an interface and an implementation (function, class, package, slice).
|
|
15
|
+
- **Interface** — everything a caller must know to use the module: types, invariants, error modes, ordering, config. Not just the type signature.
|
|
16
|
+
- **Implementation** — the code inside.
|
|
17
|
+
- **Depth** — leverage at the interface: a lot of behaviour behind a small interface. **Deep** = high leverage. **Shallow** = interface nearly as complex as the implementation.
|
|
18
|
+
- **Seam** — where an interface lives; a place behaviour can be altered without editing in place. (Use this, not "boundary.")
|
|
19
|
+
- **Adapter** — a concrete thing satisfying an interface at a seam.
|
|
20
|
+
- **Leverage** — what callers get from depth.
|
|
21
|
+
- **Locality** — what maintainers get from depth: change, bugs, knowledge concentrated in one place.
|
|
22
|
+
|
|
23
|
+
Key principles (see [language.md](language.md) for the full list):
|
|
24
|
+
|
|
25
|
+
- **Deletion test**: imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep.
|
|
26
|
+
- **The interface is the test surface.**
|
|
27
|
+
- **One adapter = hypothetical seam. Two adapters = real seam.**
|
|
28
|
+
|
|
29
|
+
This skill is _informed_ by the project's domain model. The domain language gives names to good seams; ADRs record decisions the skill should not re-litigate.
|
|
30
|
+
|
|
31
|
+
## Process
|
|
32
|
+
|
|
33
|
+
### 1. Explore
|
|
34
|
+
|
|
35
|
+
Read the project's domain glossary and any ADRs in the area you're touching first.
|
|
36
|
+
|
|
37
|
+
Then use the Agent tool with `subagent_type=Explore` to walk the codebase. Don't follow rigid heuristics — explore organically and note where you experience friction:
|
|
38
|
+
|
|
39
|
+
- Where does understanding one concept require bouncing between many small modules?
|
|
40
|
+
- Where are modules **shallow** — interface nearly as complex as the implementation?
|
|
41
|
+
- Where have pure functions been extracted just for testability, but the real bugs hide in how they're called (no **locality**)?
|
|
42
|
+
- Where do tightly-coupled modules leak across their seams?
|
|
43
|
+
- Which parts of the codebase are untested, or hard to test through their current interface?
|
|
44
|
+
|
|
45
|
+
Apply the **deletion test** to anything you suspect is shallow: would deleting it concentrate complexity, or just move it? A "yes, concentrates" is the signal you want.
|
|
46
|
+
|
|
47
|
+
### 2. Present candidates as an HTML report
|
|
48
|
+
|
|
49
|
+
Write a self-contained HTML file to the OS temp directory so nothing lands in the repo. Resolve the temp dir from `$TMPDIR`, falling back to `/tmp` (or `%TEMP%` on Windows), and write to `<tmpdir>/architecture-review-<timestamp>.html` so each run gets a fresh file. Open it for the user — `xdg-open <path>` on Linux, `open <path>` on macOS, `start <path>` on Windows — and tell them the absolute path.
|
|
50
|
+
|
|
51
|
+
The report uses **Tailwind via CDN** for layout and styling, and **Mermaid via CDN** for diagrams where a graph/flow/sequence reliably communicates the structure. Mix Mermaid with hand-crafted CSS/SVG visuals — use Mermaid when relationships are graph-shaped (call graphs, dependencies, sequences), and hand-built divs/SVG when you want something more editorial (mass diagrams, cross-sections, collapse animations). Each candidate gets a **before/after visualisation**. Be visual.
|
|
52
|
+
|
|
53
|
+
For each candidate, the same template as before, but rendered as a card:
|
|
54
|
+
|
|
55
|
+
- **Files** — which files/modules are involved
|
|
56
|
+
- **Problem** — why the current architecture is causing friction
|
|
57
|
+
- **Solution** — plain English description of what would change
|
|
58
|
+
- **Benefits** — explained in terms of locality and leverage, and how tests would improve
|
|
59
|
+
- **Before / After diagram** — side-by-side, custom-drawn, illustrating the shallowness and the deepening
|
|
60
|
+
- **Recommendation strength** — one of `Strong`, `Worth exploring`, `Speculative`, rendered as a badge
|
|
61
|
+
|
|
62
|
+
End the report with a **Top recommendation** section: which candidate you'd tackle first and why.
|
|
63
|
+
|
|
64
|
+
**Use CONTEXT.md vocabulary for the domain, and [language.md](language.md) vocabulary for the architecture.** If `CONTEXT.md` defines "Order," talk about "the Order intake module" — not "the FooBarHandler," and not "the Order service."
|
|
65
|
+
|
|
66
|
+
**ADR conflicts**: if a candidate contradicts an existing ADR, only surface it when the friction is real enough to warrant revisiting the ADR. Mark it clearly in the card (e.g. a warning callout: _"contradicts ADR-0007 — but worth reopening because…"_). Don't list every theoretical refactor an ADR forbids.
|
|
67
|
+
|
|
68
|
+
See [html-report.md](html-report.md) for the full HTML scaffold, diagram patterns, and styling guidance.
|
|
69
|
+
|
|
70
|
+
Do NOT propose interfaces yet. After the file is written, ask the user: "Which of these would you like to explore?"
|
|
71
|
+
|
|
72
|
+
### 3. Grilling loop
|
|
73
|
+
|
|
74
|
+
Once the user picks a candidate, drop into a grilling conversation. Walk the design tree with them — constraints, dependencies, the shape of the deepened module, what sits behind the seam, what tests survive.
|
|
75
|
+
|
|
76
|
+
Side effects happen inline as decisions crystallize:
|
|
77
|
+
|
|
78
|
+
- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md` — same discipline as `/grill-with-docs` (see [context-format.md](../grill-with-docs/context-format.md)). Create the file lazily if it doesn't exist.
|
|
79
|
+
- **Sharpening a fuzzy term during the conversation?** Update `CONTEXT.md` right there.
|
|
80
|
+
- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. See [adr-format.md](../grill-with-docs/adr-format.md).
|
|
81
|
+
- **Want to explore alternative interfaces for the deepened module?** See [interface-design.md](interface-design.md).
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Deepening
|
|
2
|
+
|
|
3
|
+
How to deepen a cluster of shallow modules safely, given its dependencies. Assumes the vocabulary in [language.md](language.md) — **module**, **interface**, **seam**, **adapter**.
|
|
4
|
+
|
|
5
|
+
## Dependency categories
|
|
6
|
+
|
|
7
|
+
When assessing a candidate for deepening, classify its dependencies. The category determines how the deepened module is tested across its seam.
|
|
8
|
+
|
|
9
|
+
### 1. In-process
|
|
10
|
+
|
|
11
|
+
Pure computation, in-memory state, no I/O. Always deepenable — merge the modules and test through the new interface directly. No adapter needed.
|
|
12
|
+
|
|
13
|
+
### 2. Local-substitutable
|
|
14
|
+
|
|
15
|
+
Dependencies that have local test stand-ins (PGLite for Postgres, in-memory filesystem). Deepenable if the stand-in exists. The deepened module is tested with the stand-in running in the test suite. The seam is internal; no port at the module's external interface.
|
|
16
|
+
|
|
17
|
+
### 3. Remote but owned (Ports & Adapters)
|
|
18
|
+
|
|
19
|
+
Your own services across a network boundary (microservices, internal APIs). Define a **port** (interface) at the seam. The deep module owns the logic; the transport is injected as an **adapter**. Tests use an in-memory adapter. Production uses an HTTP/gRPC/queue adapter.
|
|
20
|
+
|
|
21
|
+
Recommendation shape: *"Define a port at the seam, implement an HTTP adapter for production and an in-memory adapter for testing, so the logic sits in one deep module even though it's deployed across a network."*
|
|
22
|
+
|
|
23
|
+
### 4. True external (Mock)
|
|
24
|
+
|
|
25
|
+
Third-party services (Stripe, Twilio, etc.) you don't control. The deepened module takes the external dependency as an injected port; tests provide a mock adapter.
|
|
26
|
+
|
|
27
|
+
## Seam discipline
|
|
28
|
+
|
|
29
|
+
- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a port unless at least two adapters are justified (typically production + test). A single-adapter seam is just indirection.
|
|
30
|
+
- **Internal seams vs external seams.** A deep module can have internal seams (private to its implementation, used by its own tests) as well as the external seam at its interface. Don't expose internal seams through the interface just because tests use them.
|
|
31
|
+
|
|
32
|
+
## Testing strategy: replace, don't layer
|
|
33
|
+
|
|
34
|
+
- Old unit tests on shallow modules become waste once tests at the deepened module's interface exist — delete them.
|
|
35
|
+
- Write new tests at the deepened module's interface. The **interface is the test surface**.
|
|
36
|
+
- Tests assert on observable outcomes through the interface, not internal state.
|
|
37
|
+
- Tests should survive internal refactors — they describe behaviour, not implementation. If a test has to change when the implementation changes, it's testing past the interface.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# HTML Report Format
|
|
2
|
+
|
|
3
|
+
The architectural review is rendered as a single self-contained HTML file in the OS temp directory. Tailwind and Mermaid both come from CDNs. Mermaid handles graph-shaped diagrams reliably; hand-built divs and inline SVG handle the more editorial visuals (mass diagrams, cross-sections). Mix the two — don't lean on Mermaid for everything, it'll start to look generic.
|
|
4
|
+
|
|
5
|
+
## Scaffold
|
|
6
|
+
|
|
7
|
+
```html
|
|
8
|
+
<!doctype html>
|
|
9
|
+
<html lang="en">
|
|
10
|
+
<head>
|
|
11
|
+
<meta charset="utf-8" />
|
|
12
|
+
<title>Architecture review — {{repo name}}</title>
|
|
13
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
14
|
+
<script type="module">
|
|
15
|
+
import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs";
|
|
16
|
+
mermaid.initialize({ startOnLoad: true, theme: "neutral", securityLevel: "loose" });
|
|
17
|
+
</script>
|
|
18
|
+
<style>
|
|
19
|
+
/* small custom layer for things Tailwind doesn't cover cleanly:
|
|
20
|
+
dashed seam lines, hand-drawn-feeling arrow heads, etc. */
|
|
21
|
+
.seam { stroke-dasharray: 4 4; }
|
|
22
|
+
.leak { stroke: #dc2626; }
|
|
23
|
+
.deep { background: linear-gradient(135deg, #0f172a, #1e293b); }
|
|
24
|
+
</style>
|
|
25
|
+
</head>
|
|
26
|
+
<body class="bg-stone-50 text-slate-900 font-sans">
|
|
27
|
+
<main class="max-w-5xl mx-auto px-6 py-12 space-y-12">
|
|
28
|
+
<header>...</header>
|
|
29
|
+
<section id="candidates" class="space-y-10">...</section>
|
|
30
|
+
<section id="top-recommendation">...</section>
|
|
31
|
+
</main>
|
|
32
|
+
</body>
|
|
33
|
+
</html>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Header
|
|
37
|
+
|
|
38
|
+
Repo name, date, and a compact legend: solid box = module, dashed line = seam, red arrow = leakage, thick dark box = deep module. No introduction paragraph — straight into the candidates.
|
|
39
|
+
|
|
40
|
+
## Candidate card
|
|
41
|
+
|
|
42
|
+
The diagrams carry the weight. Prose is sparse, plain, and uses the glossary terms ([language.md](language.md)) without ceremony.
|
|
43
|
+
|
|
44
|
+
Each candidate is one `<article>`:
|
|
45
|
+
|
|
46
|
+
- **Title** — short, names the deepening (e.g. "Collapse the Order intake pipeline").
|
|
47
|
+
- **Badge row** — recommendation strength (`Strong` = emerald, `Worth exploring` = amber, `Speculative` = slate), plus a tag for the dependency category (`in-process`, `local-substitutable`, `ports & adapters`, `mock`).
|
|
48
|
+
- **Files** — monospaced list, `font-mono text-sm`.
|
|
49
|
+
- **Before / After diagram** — the centrepiece. Two columns, side by side. See patterns below.
|
|
50
|
+
- **Problem** — one sentence. What hurts.
|
|
51
|
+
- **Solution** — one sentence. What changes.
|
|
52
|
+
- **Wins** — bullets, ≤6 words each. e.g. "Tests hit one interface", "Pricing logic stops leaking", "Delete 4 shallow wrappers".
|
|
53
|
+
- **ADR callout** (if applicable) — one line in an amber-tinted box.
|
|
54
|
+
|
|
55
|
+
No paragraphs of explanation. If the diagram needs a paragraph to be understood, redraw the diagram.
|
|
56
|
+
|
|
57
|
+
## Diagram patterns
|
|
58
|
+
|
|
59
|
+
Pick the pattern that fits the candidate. Mix them. Don't make every diagram look the same — variety is part of the point.
|
|
60
|
+
|
|
61
|
+
### Mermaid graph (the workhorse for dependencies / call flow)
|
|
62
|
+
|
|
63
|
+
Use a Mermaid `flowchart` or `graph` when the point is "X calls Y calls Z, and look at the mess." Wrap it in a Tailwind-styled card so it doesn't feel parachuted in. Style with classDef to colour leakage edges red and the deep module dark. Sequence diagrams work well for "before: 6 round-trips; after: 1."
|
|
64
|
+
|
|
65
|
+
```html
|
|
66
|
+
<div class="rounded-lg border border-slate-200 bg-white p-4">
|
|
67
|
+
<pre class="mermaid">
|
|
68
|
+
flowchart LR
|
|
69
|
+
A[OrderHandler] --> B[OrderValidator]
|
|
70
|
+
B --> C[OrderRepo]
|
|
71
|
+
C -.leak.-> D[PricingClient]
|
|
72
|
+
classDef leak stroke:#dc2626,stroke-width:2px;
|
|
73
|
+
class C,D leak
|
|
74
|
+
</pre>
|
|
75
|
+
</div>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Hand-built boxes-and-arrows (when Mermaid's layout fights you)
|
|
79
|
+
|
|
80
|
+
Modules as `<div>`s with borders and labels. Arrows as inline SVG `<line>` or `<path>` elements positioned absolutely over a relative container. Reach for this when you want the "after" diagram to feel like one thick-bordered deep module with greyed-out internals — Mermaid won't render that with the right weight.
|
|
81
|
+
|
|
82
|
+
### Cross-section (good for layered shallowness)
|
|
83
|
+
|
|
84
|
+
Stack horizontal bands (`h-12 border-l-4`) to show layers a call passes through. Before: 6 thin layers each doing nothing. After: 1 thick band labelled with the consolidated responsibility.
|
|
85
|
+
|
|
86
|
+
### Mass diagram (good for "interface as wide as implementation")
|
|
87
|
+
|
|
88
|
+
Two rectangles per module — one for interface surface area, one for implementation. Before: interface rectangle is nearly as tall as the implementation rectangle (shallow). After: interface rectangle is short, implementation rectangle is tall (deep).
|
|
89
|
+
|
|
90
|
+
### Call-graph collapse
|
|
91
|
+
|
|
92
|
+
Before: a tree of function calls rendered as nested boxes. After: the same tree collapsed into one box, with the now-internal calls shown faded inside it.
|
|
93
|
+
|
|
94
|
+
## Style guidance
|
|
95
|
+
|
|
96
|
+
- Lean editorial, not corporate-dashboard. Generous whitespace. Serif optional for headings (`font-serif` works well with stone/slate).
|
|
97
|
+
- Colour sparingly: one accent (emerald or indigo) plus red for leakage and amber for warnings.
|
|
98
|
+
- Keep diagrams ~320px tall so before/after sits comfortably side by side without scrolling.
|
|
99
|
+
- Use `text-xs uppercase tracking-wider` for module labels inside diagrams — they should read as schematic, not as UI.
|
|
100
|
+
- The only scripts are the Tailwind CDN and the Mermaid ESM import. The report is otherwise static — no app code, no interactivity beyond Mermaid's own rendering.
|
|
101
|
+
|
|
102
|
+
## Top recommendation section
|
|
103
|
+
|
|
104
|
+
One larger card. Candidate name, one sentence on why, anchor link to its card. That's it.
|
|
105
|
+
|
|
106
|
+
## Tone
|
|
107
|
+
|
|
108
|
+
Plain English, concise — but the architectural nouns and verbs come straight from [language.md](language.md). Concision is not an excuse to drift.
|
|
109
|
+
|
|
110
|
+
**Use exactly:** module, interface, implementation, depth, deep, shallow, seam, adapter, leverage, locality.
|
|
111
|
+
|
|
112
|
+
**Never substitute:** component, service, unit (for module) · API, signature (for interface) · boundary (for seam) · layer, wrapper (for module, when you mean module).
|
|
113
|
+
|
|
114
|
+
**Phrasings that fit the style:**
|
|
115
|
+
|
|
116
|
+
- "Order intake module is shallow — interface nearly matches the implementation."
|
|
117
|
+
- "Pricing leaks across the seam."
|
|
118
|
+
- "Deepen: one interface, one place to test."
|
|
119
|
+
- "Two adapters justify the seam: HTTP in prod, in-memory in tests."
|
|
120
|
+
|
|
121
|
+
**Wins bullets** name the gain in glossary terms: *"locality: bugs concentrate in one module"*, *"leverage: one interface, N call sites"*, *"interface shrinks; implementation absorbs the wrappers"*. Don't write *"easier to maintain"* or *"cleaner code"* — those terms aren't in the glossary and don't earn their place.
|
|
122
|
+
|
|
123
|
+
No hedging, no throat-clearing, no "it's worth noting that…". If a sentence could be a bullet, make it a bullet. If a bullet could be cut, cut it. If a term isn't in [language.md](language.md), reach for one that is before inventing a new one.
|