dsh-gate-agent 0.1.6 → 0.1.7

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/README.md CHANGED
@@ -60,15 +60,12 @@ Host 插件:用 phase/node 门禁组织讨论、规划、实施、评审、验
60
60
  | phase / node | 用途 | 主代理/worker 与技能 |
61
61
  |---|---|---|
62
62
  | `discuss` | 理解需求、讨论方案、确认授权 | root;不派 worker;文件只读,可提交已有改动 |
63
- | `orchestrating/plan` | 把工作项整理成规划工件 | planning worker(文件只读、只读 shell、`gate_note_write`);`gate-planning` + `gate-write-agent-notes` |
63
+ | `orchestrating/plan` | 规划,或 review findings 后修订 | planning worker(文件只读、只读 shell、`gate_note_write`);`gate-planning` + `gate-write-agent-notes` |
64
64
  | `orchestrating/plan-review` | Plan Review 三轴评审 | review worker;`gate-plan-review` |
65
- | `orchestrating/plan-revise` | 按 findings 修计划 | planning worker;`gate-planning` |
66
- | `orchestrating/implement` | 按已确认计划实施 | implement worker;`gate-implement` |
65
+ | `orchestrating/implement` | 实施,或 review/verify findings 后修正 | implement worker;`gate-implement` |
67
66
  | `orchestrating/code-review` | 实现 review(Standards/Spec) | review worker;`gate-code-review` |
68
- | `orchestrating/implement-revise` | 按 review findings 修正 | implement worker;`gate-implement` |
69
67
  | `orchestrating/verify` | 最终验收与证据绑定 | verify worker;`gate-verify` |
70
68
  | `orchestrating/note-lifecycle` | 把 proposed Note 转 implemented、跑 notes 校验 | root;`gate-write-agent-notes` lifecycle 工具 |
71
- | `orchestrating/fix-bug` | 修复已授权缺陷并复核 | fix worker + review worker;`gate-fix-bug` + `gate-code-review` |
72
69
  | `reviewing/code-review-standalone` | 单独只读 code review | review worker;`gate-code-review` |
73
70
  | `reviewing/proposal-review` | 单独提案评审 | review worker;`gate-plan-review` |
74
71
  | `reviewing/verify-standalone` | 单独只读验收 | verify worker;`gate-user-verify` |
@@ -78,6 +75,16 @@ Host 插件:用 phase/node 门禁组织讨论、规划、实施、评审、验
78
75
 
79
76
  进入阶段不等于执行。主代理按当前 procedure 加载技能、派 worker,再用 `gate_record` 推进节点。
80
77
 
78
+ review findings 后不进入独立的 revise 节点:
79
+
80
+ ```text
81
+ plan-review findings → plan → plan-review
82
+ code-review findings → implement → code-review
83
+ verify FAIL → implement → code-review
84
+ ```
85
+
86
+ `plan` / `implement` 修订记录可省略 `workerSessionIds`;谁执行修订、是否复用或新开子代理由主代理判断,procedure 不规定。review 仍必须由独立 worker 完成。
87
+
81
88
  ## 权限
82
89
 
83
90
  | 阶段/角色 | 文件写 | Note 写 | shell | 仓库写 |
@@ -85,7 +92,6 @@ Host 插件:用 phase/node 门禁组织讨论、规划、实施、评审、验
85
92
  | discuss root | ❌ | ❌ | 只读 | add/commit/push |
86
93
  | planning worker | ❌ | ✅ gate_note_write | 只读 | ❌ |
87
94
  | plan-review / code-review / code-review-standalone / proposal-review worker | ❌ | ❌ | 只读 | ❌ |
88
- | implement / implement-revise / fix-bug worker | ✅ | ❌ | 可写 | add/commit/push |
89
95
  | verify / verify-standalone worker | ❌ | ❌ | 只读 | ❌ |
90
96
  | note-lifecycle root | ✅ | ✅ lifecycle 工具 | 可写 | add/commit/push |
91
97
  | docs root | ✅ | ❌ | 可写 | add/commit/push |
@@ -95,7 +101,7 @@ Host 插件:用 phase/node 门禁组织讨论、规划、实施、评审、验
95
101
 
96
102
  - discuss 文件只读;要改文件先进入 plan/implement。提交已有改动用 git add/commit/push,不受文件只读影响。
97
103
  - planning worker 的 shell 只读;产品文件和仓库写拒绝。
98
- - implement/fix worker 保留 push。
104
+ - implement worker 保留 push。
99
105
  - access 会显示在 gate_status、/gate-status、gate_record、gate_start_phase、命令 follow-up 和 worker prompt:
100
106
 
101
107
  ```text
@@ -109,13 +115,12 @@ Host 插件:用 phase/node 门禁组织讨论、规划、实施、评审、验
109
115
  | 命令 | 参数 | 作用 |
110
116
  |---|---|---|
111
117
  | `/gate-init` | 无 | 初始化 notes、AGENTS.md、`verify-notes`、CI、git 与基础 `.gitignore`,保持 `discuss` |
112
- | `/gate-enter-plan [具体工作事项或上下文语义]` | 可选 | 基于讨论共识、既有决策与用户输入进入 `orchestrating/plan` |
113
- | `/gate-enter-implement [具体工作事项或上下文语义]` | 可选 | 基于已确认计划或讨论后的实施说明进入 `orchestrating/implement` |
118
+ | `/gate-enter-plan [具体工作事项或上下文语义]` | 可选 | 进入 plan:planning worker 写/改 Note → plan-review 三轴评审;findings 回 plan 修订,通过后回 discuss |
119
+ | `/gate-enter-implement [具体工作事项或上下文语义]` | 可选 | 进入 implement:implement worker 实施 → code-review → verify;findings 回 implement;通过后 note-lifecycle 或 mechanical 回 discuss |
114
120
  | `/gate-prd [主题或上下文语义]` | 可选 | 用户级创建/更新 PRD;仅 discuss |
115
121
  | `/gate-docs [文档范围或上下文语义]` | 可选 | 进入文档治理,按项目文档规范处理 |
116
122
  | `/gate-implement-review [具体工作事项或上下文语义]` | 可选 | 对当前改动做独立只读 code review,只输出 findings |
117
123
  | `/gate-code-verify [具体工作事项或上下文语义]` | 可选 | 对当前改动做独立只读验收(gate-user-verify) |
118
- | `/gate-fix-bug [具体工作事项或上下文语义]` | 可选 | 基于描述或当前上下文派 fix worker 修复已授权缺陷 |
119
124
  | `/gate-propose-review [具体工作事项或上下文语义]` | 可选 | 对提案做独立只读三轴评审 |
120
125
  | `/gate-note-verify` | 无 | 只读检查 notes tree/format/lifecycle/archived |
121
126
  | `/gate-note-archive <note> [--superseded-by <new>]` | 必需 Note 路径 | 归档 implemented Note,写 Archived、移动、封印、报告入站链接 |
@@ -126,7 +131,7 @@ Host 插件:用 phase/node 门禁组织讨论、规划、实施、评审、验
126
131
  | `/gate-return-discuss` | 无 | 放弃当前节点,回到 discuss |
127
132
  | `/gate-status` | 无 | 只读显示当前 phase/node、procedure、access 与下一步命令 |
128
133
 
129
- 直接 implement(`/gate-enter-implement [具体工作事项或上下文语义]` 或 `gate_start_phase({node:'implement',brief})`)会自动标记 `mechanical`,跳过 Note lifecycle;不需要 `mechanical:` 前缀。plan/plan-revise 手动选择 `mechanical` 时也不要求前缀,只需 `notePaths: []`。
134
+ 直接 implement(`/gate-enter-implement [具体工作事项或上下文语义]` 或 `gate_start_phase({node:'implement',brief})`)会自动标记 `mechanical`,跳过 Note lifecycle;不需要 `mechanical:` 前缀。plan 手动选择 `mechanical` 时也不要求前缀,只需 `notePaths: []`。
130
135
 
131
136
  离开 discuss 的授权可来自对话(包括要求用户再输入 slash command)或 `ask_user_question`;明确授权后,主代理可调用 `gate_start_phase({node:'plan'|'implement', brief})`。
132
137
 
@@ -136,11 +141,10 @@ Host 插件:用 phase/node 门禁组织讨论、规划、实施、评审、验
136
141
  |---|---|---|
137
142
  | `gate-planning` | planning worker | 生成/更新规划 Note,组织工作项、验收和设计 |
138
143
  | `gate-plan-review` | plan/proposal review worker | Standards/Spec/Architecture 三轴评审 |
139
- | `gate-implement` | implement/fix worker | 按计划实施并返回改动/验证结果 |
144
+ | `gate-implement` | implement worker | 按计划实施并返回改动/验证结果 |
140
145
  | `gate-code-review` | code review worker | 对实现做 Standards/Spec 两轴 review |
141
146
  | `gate-verify` | verify worker | 最终验收、证据收集与汇报 |
142
147
  | `gate-user-verify` | standalone verify worker | 独立只读验收 |
143
- | `gate-fix-bug` | fix worker | 已授权缺陷修复流程 |
144
148
  | `gate-write-agent-notes` | planning worker / root note lifecycle | Note 检索、格式、finalize/verify |
145
149
 
146
150
  ## 典型用法
@@ -200,7 +204,7 @@ gate_record({
200
204
  })
201
205
  ```
202
206
 
203
- 进入 `plan-review`,由 review worker 做三轴评审;findings 交回 `plan-revise`,直到通过后回 `discuss`,`planReady=true`。
207
+ 进入 `plan-review`,由 review worker 做三轴评审;findings 记录后回到 `plan`;修订完成后可再次 review,直到通过后回 `discuss`,`planReady=true`。
204
208
 
205
209
  ### Implementation
206
210
 
@@ -208,7 +212,7 @@ gate_record({
208
212
  /gate-enter-implement
209
213
  ```
210
214
 
211
- 主代理派 `gate-implement` worker 实施;完成后 `gate_record({node:'implement', workerSessionIds})` 进入 `code-review`。review 通过后进入 `verify`;verify PASS 后:非 mechanical 进入 `note-lifecycle`,mechanical 直接回 discuss 并提示提交。
215
+ 主代理派 `gate-implement` worker 实施;完成后 `gate_record({node:'implement', workerSessionIds})` 进入 `code-review`。review findings 回到 `implement`,修复后再次 review;review 通过后进入 `verify`;verify PASS 后:非 mechanical 进入 `note-lifecycle`,mechanical 直接回 discuss 并提示提交。
212
216
 
213
217
  Note lifecycle:
214
218
 
@@ -234,14 +238,6 @@ gate 不自动 `git add`/`git commit`;完成 note-lifecycle 后由用户或主
234
238
 
235
239
  主代理派只读 verify worker,使用 `gate-user-verify`;PASS 后 `gate_record({node:'verify-standalone', verification, workerSessionIds})` 回 discuss。
236
240
 
237
- ### 缺陷修复
238
-
239
- ```text
240
- /gate-fix-bug 修复空指针异常
241
- ```
242
-
243
- 主代理派 fix worker 执行修复,再派独立 review worker 复核;完成后 `gate_record({node:'fix-bug', workerSessionIds})`。
244
-
245
241
  ### 提案评审
246
242
 
247
243
  ```text
@@ -322,9 +318,10 @@ gate_record({
322
318
  })
323
319
  ```
324
320
 
325
- - `node`:`plan`、`plan-review`、`proposal-review`、`plan-revise`、`implement`、`code-review`、`implement-revise`、`verify`、`verify-standalone`、`code-review-standalone`、`fix-bug`、`note-lifecycle`、`docs`。
326
- - `plan` 必须带 `task`。
327
- - worker 节点必须带当前 root 的、已 settled 的 child `workerSessionIds`。
321
+ - `node`:`plan`、`plan-review`、`proposal-review`、`implement`、`code-review`、`verify`、`verify-standalone`、`code-review-standalone`、`note-lifecycle`、`docs`。
322
+ - 首次 `plan` 必须带 `task`;review findings 后的修订记录不重置 task。
323
+ - 首次 plan/implement、review、verify 等 worker 节点必须带当前 root 的、已 settled 的 child `workerSessionIds`。
324
+ - plan/implement 修订记录可省略 workerSessionIds;root 自己修订时直接记录。
328
325
  - `plan-review`/`proposal-review` 需要 Standards/Spec/Architecture 三轴;`code-review`/`code-review-standalone` 需要 Standards/Spec 两轴。
329
326
  - `requiresDiscussion=true` 进入 blocked,等待用户决定。
330
327
  - review 达到 `reviewLimit` 仍有 findings 时 blocked,不能靠重新进入 implement 绕过。
@@ -446,17 +443,16 @@ discuss 和 plan 默认不允许普通文件写。`handoff`、PRD、research 等
446
443
  - `complete`
447
444
  - `orchestrating/plan`
448
445
  - `orchestrating/plan-review`
449
- - `orchestrating/plan-revise`
450
446
  - `orchestrating/implement`
451
447
  - `orchestrating/code-review`
452
- - `orchestrating/implement-revise`
453
448
  - `orchestrating/verify`
454
449
  - `orchestrating/note-lifecycle`
455
- - `orchestrating/fix-bug`
456
450
  - `reviewing/code-review-standalone`
457
451
  - `reviewing/proposal-review`
458
452
  - `reviewing/verify-standalone`
459
453
 
454
+ 旧 artifact policy 中的 `orchestrating/plan-revise` / `orchestrating/implement-revise` 仍可解析,但当前状态不会再产生这些 key;可删除。
455
+
460
456
  `*` 表示任意**非 blocked** 状态。`blocked` 始终拒绝,即使规则写了 `*`。
461
457
 
462
458
  #### roles
package/lib/index.js CHANGED
@@ -82,7 +82,7 @@ notePaths \u662F [{path,class,lifecycle}] \u6570\u7EC4\uFF1Bpath \u63A5\u53D7 .a
82
82
  \u7ED9 worker \u5DE5\u4F5C\u9879\u3001Note\u3001\u56FA\u5B9A\u70B9\u548C\u8BC4\u5BA1\u65B9\u6CD5\uFF1B\u4E0D\u8981\u5728 review worker prompt \u4E2D\u9644\u5E26\u9879\u76EE\u73AF\u5883\u9A8C\u8BC1\uFF08package.json\u3001Node \u7248\u672C\u3001git \u72B6\u6001\u3001\u6587\u4EF6\u5B58\u5728\u6027\u3001\u521D\u59CB\u5316 smoke \u7ED3\u679C\uFF09\u3002
83
83
  \u5B8C\u6210\u540E\u8C03 gate_record({node:'plan-review',findings,reviewAxes,workerSessionIds,requiresDiscussion})\u3002
84
84
  reviewAxes \u5FC5\u987B\u5305\u542B standards\u3001spec\u3001architecture \u4E09\u8F74\u3002
85
- \u9700\u8981\u7528\u6237\u51B3\u5B9A\uFF1A\u8FDB\u5165 blocked\uFF0C\u7B49\u5F85 /gate-resume\uFF1B\u4ECD\u6709 findings\uFF1A\u5148 gate_record \u672C\u8F6E plan-review\uFF0C\u786E\u8BA4 node \u5DF2\u53D8\u4E3A plan-revise\uFF0C\u518D\u590D\u7528\u5DF2\u52A0\u8F7D\u7684 gate-planning\uFF0C\u53EA\u5E26 findings \u548C Note \u8DEF\u5F84\u6D3E revise\uFF0C\u518D review\u3002
85
+ \u9700\u8981\u7528\u6237\u51B3\u5B9A\uFF1A\u8FDB\u5165 blocked\uFF0C\u7B49\u5F85 /gate-resume\uFF1B\u4ECD\u6709 findings\uFF1A\u5148 gate_record \u672C\u8F6E plan-review\uFF0Cgate \u4F1A\u56DE\u5230 plan\uFF1B\u4FEE\u8BA2\u5B8C\u6210\u540E\u8BB0\u5F55 plan\uFF0C\u518D review\u3002
86
86
 
87
87
  ## Step 3 \u2014 \u56DE\u5230 Discuss
88
88
  review \u4E3A\u7A7A\u65F6\u56DE\u5230 discuss\uFF0CplanReady=true\u3002
@@ -97,34 +97,20 @@ worker \u4E0D\u52A0\u8F7D gate \u6280\u80FD\u3002
97
97
 
98
98
  ## Step 2 \u2014 Implementation Review
99
99
  \u4E3B agent \u9996\u6B21\u8FDB\u5165 code-review \u65F6\u52A0\u8F7D\u6280\u80FD gate-code-review\uFF1B\u82E5\u672C\u4F1A\u8BDD\u5DF2\u52A0\u8F7D\u4E14\u5185\u5BB9\u4ECD\u5728\u4E0A\u6587\uFF0C\u540E\u7EED review \u8F6E\u6B21\u76F4\u63A5\u590D\u7528\uFF0C\u4E0D\u8981\u91CD\u590D\u8C03\u7528 skill\u3002\u8BFB\u53D6\u8BE5\u6280\u80FD\u7684 assets/worker-briefs/gate-implement-review.md \u5199 review \u4EFB\u52A1\uFF0C\u6309\u6539\u52A8\u89C4\u6A21\u81EA\u884C\u51B3\u5B9A\u6D3E\u4E00\u4E2A\u6216\u591A\u4E2A\u53EA\u8BFB review worker\uFF0C\u8986\u76D6 Standards \u4E0E Spec \u4E24\u8F74\u3002
100
- \u5B8C\u6210\u540E\u8C03 gate_record({node:'code-review', findings, reviewAxes, workerSessionIds})\uFF1B\u6709 findings \u65F6\u5148\u8BB0\u5F55\uFF0C\u786E\u8BA4 node \u5DF2\u53D8\u4E3A implement-revise\uFF0C\u518D\u6D3E revise worker\u3002
100
+ \u5B8C\u6210\u540E\u8C03 gate_record({node:'code-review', findings, reviewAxes, workerSessionIds})\uFF1B\u6709 findings \u65F6\u5148\u8BB0\u5F55\uFF0Cgate \u4F1A\u56DE\u5230 implement\uFF1B\u4FEE\u8BA2\u5B8C\u6210\u540E\u8BB0\u5F55 implement\uFF0C\u518D review\u3002
101
101
  \u5BA1\u67E5\u8981\u6C42\u6EE1\u8DB3\u540E\u7EE7\u7EED Step 3\uFF0C\u65E0\u9700\u518D\u6B21\u6388\u6743\u3002
102
102
  \u5B9E\u73B0\u4E2D\u53D1\u73B0\u8303\u56F4\u5916\u95EE\u9898\u3001\u5408\u540C\u53D8\u5316\u6216\u9700\u8981\u91CD\u65B0\u8BA8\u8BBA\u65F6\uFF0Cworker \u505C\u6B62\u5E76\u8FD4\u56DE receipt\uFF1B\u4E3B agent \u5411\u7528\u6237\u8BF4\u660E\uFF0C\u4F7F\u7528 gate_record \u7684 requiresDiscussion \u6216\u63D0\u793A\u7528\u6237\u6267\u884C /gate-return-discuss\u3002\u4E0D\u8981\u505C\u5728 implement \u91CC\u7EE7\u7EED\u6269\u5927\u8303\u56F4\u3002
103
103
 
104
104
  ## Step 3 \u2014 Verify
105
105
  \u4E3B agent \u9996\u6B21\u8FDB\u5165 verify \u65F6\u52A0\u8F7D\u6280\u80FD gate-verify\uFF1B\u82E5\u672C\u4F1A\u8BDD\u5DF2\u52A0\u8F7D\u4E14\u5185\u5BB9\u4ECD\u5728\u4E0A\u6587\uFF0C\u76F4\u63A5\u590D\u7528\uFF0C\u4E0D\u8981\u91CD\u590D\u8C03\u7528 skill\u3002\u8BFB\u53D6\u8BE5\u6280\u80FD\u7684 assets/worker-briefs/gate-verify.md \u5199 verify \u4EFB\u52A1\uFF0C\u6D3E verify worker \u5B8C\u6210\u6700\u7EC8\u9A8C\u6536\u3002
106
106
  \u5B8C\u6210\u540E\u8C03 gate_record({node:'verify', verification, workerSessionIds})\uFF1Bverification.toolResults \u5FC5\u987B\u662F verify worker session log \u4E2D\u771F\u5B9E tool/result \u7684 call_... id\uFF0Cevidence \u662F workspace \u5185\u7684\u666E\u901A\u6587\u4EF6\u3002
107
- \u53EA\u6709\u6700\u7EC8 PASS \u624D\u5B8C\u6210\u4EA4\u4ED8\uFF1BFAIL \u56DE\u5230 implement-revise\u3002
107
+ \u53EA\u6709\u6700\u7EC8 PASS \u624D\u5B8C\u6210\u4EA4\u4ED8\uFF1BFAIL \u56DE\u5230 implement\u3002
108
108
  \u72B6\u6001\u66F4\u65B0\u9075\u5FAA\u9879\u76EE\u767B\u8BB0\u7684\u5DE5\u4F5C\u9879\u4E0E\u51B3\u7B56\u8BB0\u5F55\u751F\u547D\u5468\u671F\u3002
109
109
 
110
110
  ## Step 4 \u2014 Note lifecycle
111
111
  Verify PASS \u540E\u8FDB\u5165 note-lifecycle\uFF0C\u4E0D\u5F97\u76F4\u63A5 complete\u3002
112
112
  \u4E3B agent \u8C03 gate_note_finalize\uFF0C\u518D\u8C03 gate_note_verify\uFF1B\u901A\u8FC7\u540E gate_record({node:'note-lifecycle'})\u3002
113
113
  mechanical \u5DE5\u4F5C\u9879\u81EA\u52A8\u8DF3\u8FC7\uFF1B\u8DE8\u4F1A\u8BDD journal \u53EA\u62A5\u544A\u4E0D\u6062\u590D\uFF1Barchived manifest \u53EA\u7531\u7528\u6237\u6267\u884C /gate-note-seal\u3002note-lifecycle \u5B8C\u6210\u540E\u5EFA\u8BAE\u63D0\u4EA4\u672C\u6B21\u5B9E\u73B0\u4E0E Note\uFF1Bgate \u4E0D\u81EA\u52A8\u6267\u884C git add/commit\u3002`;
114
- var FIX_BUG_ORCHESTRATION = `## /gate-fix-bug \u7F16\u6392
115
- \u4E3B agent \u8BFB\u53D6 gate-fix-bug\uFF1B\u4E3B agent \u53EA\u6C47\u603B\uFF0C\u4E0D\u81EA\u884C\u4FEE\u590D\u3002
116
-
117
- ## Step 1 \u2014 Fix
118
- \u4E3B agent \u9996\u6B21\u8FDB\u5165 fix-bug \u65F6\u8BFB\u53D6/\u52A0\u8F7D gate-fix-bug\uFF1B\u5DF2\u52A0\u8F7D\u5219\u590D\u7528\uFF0C\u4E0D\u8981\u91CD\u590D\u8C03\u7528 skill\u3002\u8BFB\u53D6 gate-fix-bug \u6280\u80FD\u7684 assets/worker-briefs/gate-fix-bug.md\uFF0C\u6D3E fix worker\u3002fix worker \u4F7F\u7528 gate-fix-bug \u6267\u884C Process 1-9\uFF1A\u590D\u73B0\u3001\u56DE\u5F52\u8986\u76D6\u3001\u6839\u56E0\u3001\u6700\u5C0F\u4FEE\u590D\u3001\u539F\u590D\u73B0\u4E0E\u76F8\u5173\u6D4B\u8BD5\u3002\u5B8C\u6210\u540E\u8FD4\u56DE\u4FEE\u590D receipt\uFF1B\u4E0D\u8981\u81EA\u884C\u5B8C\u6210 Step 10-12\uFF0C\u4E5F\u4E0D\u8981\u63D0\u4EA4\u3002
119
-
120
- ## Step 2 \u2014 Independent review
121
- \u4E3B agent \u9996\u6B21\u8FDB\u5165 review \u65F6\u52A0\u8F7D gate-code-review\uFF1B\u5DF2\u52A0\u8F7D\u5219\u590D\u7528\uFF0C\u4E0D\u8981\u91CD\u590D\u8C03\u7528 skill\u3002\u63D0\u70BC\u4E24\u8F74\u8BC4\u5BA1\u8981\u6C42\uFF0C\u518D\u8BFB\u53D6 gate-fix-bug \u6280\u80FD\u7684 assets/worker-briefs/fix-bug-review.md\uFF0C\u6D3E\u4E00\u4E2A\u72EC\u7ACB review worker\uFF1B\u4FEE\u590D\u57FA\u7EBF\u3001\u9009\u5B9A\u5931\u8D25\u3001\u5408\u540C\u5F15\u7528\u548C\u5B8C\u6574 diff \u5199\u8FDB\u7B80\u62A5\u3002review \u53EA\u62A5 findings\u3002
122
-
123
- ## Step 3 \u2014 Resolve
124
- \u628A material in-scope findings \u4EA4\u56DE fix worker\uFF08send_message \u6216\u65B0 worker\uFF09\uFF0C\u5B8C\u6210 gate-fix-bug Step 11-12\uFF0C\u91CD\u8DD1\u539F\u590D\u73B0\u548C\u76F8\u5173\u6D4B\u8BD5\uFF1B\u91CD\u590D Step 2-3 \u76F4\u5230\u6CA1\u6709 material findings\u3002
125
-
126
- ## Step 4 \u2014 Record
127
- \u5B8C\u6210\u540E\u8C03 gate_record({node:'fix-bug', workerSessionIds})\uFF0CworkerSessionIds \u5305\u542B fix \u4E0E review worker\uFF1Bgate \u4E0D\u518D\u81EA\u52A8\u63D0\u4EA4\u3002`;
128
114
  var DOCS_ORCHESTRATION = `## /gate-docs \u7F16\u6392
129
115
  \u8303\u56F4\u7531\u6A21\u578B\u6309\u9879\u76EE\u5B9E\u9645\u6587\u6863\u9700\u8981\u5224\u65AD\u3002
130
116
  \u5B8C\u6210\u540E\u8C03 gate_record({node:'docs'}) \u56DE\u5230 discuss\u3002`;
@@ -133,21 +119,18 @@ Verify \u5DF2 PASS\uFF1B\u5F53\u524D\u4E0D\u6D3E worker\uFF0C\u4E5F\u4E0D\u5199\
133
119
  \u6309\u987A\u5E8F\u6267\u884C\uFF1Agate_note_finalize \u2192 gate_note_verify \u2192 gate_record({node:'note-lifecycle'})\u3002
134
120
  finalize/verify \u5931\u8D25\u7559\u5728\u672C\u8282\u70B9\u4FEE\u590D\uFF1Barchived manifest \u7F3A\u5931\u65F6\u63D0\u793A\u7528\u6237\u6267\u884C /gate-note-seal\u3002
135
121
  \u53EA\u6709 noteVerified=true \u624D\u80FD gate_record \u5B8C\u6210\uFF1Bmechanical \u5DE5\u4F5C\u9879\u53EF\u8DF3\u8FC7 finalize\u3002\u5B8C\u6210\u540E\u5EFA\u8BAE\u63D0\u4EA4\u672C\u6B21\u5B9E\u73B0\u4E0E Note\uFF1Bgate \u4E0D\u81EA\u52A8 git add/commit\u3002\u5B8C\u6210\u540E\u68C0\u67E5\u672C\u6B21\u65B0 Note \u662F\u5426\u5B8C\u5168\u53D6\u4EE3\u4E86\u67D0\u7BC7 implemented Note\uFF1A\u6709\u72EC\u7ACB\u53C2\u8003\u4EF7\u503C\u5C31\u5728\u6700\u7EC8\u6C47\u62A5\u4E2D\u7ED9\u51FA\u5F52\u6863\u5019\u9009\u548C\u76EE\u6807\u547D\u4EE4\uFF0C\u6CA1\u6709\u72EC\u7ACB\u4EF7\u503C\u5219\u5EFA\u8BAE\u5220\u9664\uFF1B\u4E0D\u8981\u81EA\u52A8\u5F52\u6863\u3002`;
136
- var GATE_RECORD_NODES = ["plan", "plan-review", "proposal-review", "plan-revise", "implement", "code-review", "implement-revise", "verify", "verify-standalone", "note-lifecycle", "docs", "code-review-standalone", "fix-bug"];
122
+ var GATE_RECORD_NODES = ["plan", "plan-review", "proposal-review", "implement", "code-review", "verify", "verify-standalone", "note-lifecycle", "docs", "code-review-standalone"];
137
123
  var NODE_INFO = {
138
124
  plan: { variant: "plan", method: "`gate-planning` + `gate-write-agent-notes`" },
139
125
  "plan-review": { variant: "plan", method: "`gate-plan-review`" },
140
- "plan-revise": { variant: "plan", method: "`gate-planning` + `gate-write-agent-notes`" },
141
126
  "proposal-review": { variant: "reviewing-proposal", method: "`gate-plan-review`\uFF08\u4E09\u8F74\uFF09" },
142
127
  implement: { variant: "implement", method: "`gate-implement`" },
143
- "implement-revise": { variant: "implement", method: "`gate-implement`" },
144
128
  "code-review": { variant: "implement", method: "`gate-code-review` (one skill, both axes)" },
145
129
  "code-review-standalone": { variant: "reviewing-code", method: "`gate-code-review` (one skill, both axes)" },
146
130
  verify: { variant: "implement", method: "`gate-verify`" },
147
131
  "verify-standalone": { variant: "reviewing-verify", method: "\u65E0" },
148
132
  "note-lifecycle": { variant: "note-lifecycle", method: "`gate-write-agent-notes`\uFF08lifecycle \u5DE5\u5177\uFF0C\u4E0D\u662F worker\uFF09" },
149
- docs: { variant: "docs", method: "\u65E0" },
150
- "fix-bug": { variant: "fix-bug", method: "`gate-fix-bug`" }
133
+ docs: { variant: "docs", method: "\u65E0" }
151
134
  };
152
135
  var NODE_METHODS = Object.fromEntries(Object.entries(NODE_INFO).map(([node, info]) => [node, info.method]));
153
136
  var WORKER_NODES = new Set(GATE_RECORD_NODES.filter((node) => node !== "docs" && node !== "note-lifecycle"));
@@ -155,7 +138,7 @@ var DISPATCH_RULE = `## \u6280\u80FD\u52A0\u8F7D\u89C4\u5219
155
138
  - \u672C\u4F1A\u8BDD\u5DF2\u7ECF\u901A\u8FC7 skill \u5DE5\u5177\u52A0\u8F7D\u8FC7\u7684\u6280\u80FD\uFF0C\u5185\u5BB9\u4ECD\u5728\u4E0A\u6587\u65F6\u76F4\u63A5\u590D\u7528\uFF0C\u4E0D\u8981\u91CD\u590D\u8C03\u7528 skill\u3002
156
139
  - \u53EA\u6709\u4EE5\u4E0B\u60C5\u51B5\u624D\u91CD\u65B0\u52A0\u8F7D\uFF1A\u672C\u4F1A\u8BDD\u9996\u6B21\u8FDB\u5165\u8BE5\u6280\u80FD\uFF1Bcompaction \u540E\u5185\u5BB9\u5DF2\u4E0D\u5728\u4E0A\u4E0B\u6587\uFF1B\u6280\u80FD\u6587\u4EF6/\u7248\u672C\u53D1\u751F\u53D8\u5316\uFF1B\u7528\u6237\u660E\u786E\u8981\u6C42\u5237\u65B0\u3002
157
140
  - gate_record / gate_status \u8FD4\u56DE\u65B0\u7684 procedure \u53EA\u4EE3\u8868 node\u3001\u8F6E\u6B21\u6216 findings \u53D8\u5316\uFF0C\u4E0D\u4EE3\u8868\u8981\u91CD\u65B0\u52A0\u8F7D\u6280\u80FD\u3002
158
- - \u591A\u8F6E review/revise \u590D\u7528\u540C\u4E00\u4EFD\u6280\u80FD\u5185\u5BB9\uFF1B\u628A\u65B0\u7684 findings\u3001\u6587\u4EF6\u8303\u56F4\u548C\u8981\u6C42\u4F20\u7ED9 worker\uFF0C\u4E0D\u8981\u91CD\u65B0\u52A0\u8F7D\u6280\u80FD\u3002`;
141
+ - \u591A\u8F6E review/\u4FEE\u8BA2\u590D\u7528\u540C\u4E00\u4EFD\u6280\u80FD\u5185\u5BB9\uFF1B\u628A\u65B0\u7684 findings\u3001\u6587\u4EF6\u8303\u56F4\u548C\u8981\u6C42\u4EA4\u7ED9\u5B9E\u9645\u6267\u884C\u8005\uFF0C\u4E0D\u8981\u91CD\u65B0\u52A0\u8F7D\u6280\u80FD\u3002`;
159
142
  var REVIEWING_CODE_PROCEDURE = `## /gate-implement-review \u7F16\u6392
160
143
  \u4E3B agent \u9996\u6B21\u8FDB\u5165\u65F6\u52A0\u8F7D gate-code-review\uFF1B\u5DF2\u52A0\u8F7D\u5219\u590D\u7528\uFF0C\u4E0D\u8981\u91CD\u590D\u8C03\u7528 skill\u3002\u6D3E\u53EA\u8BFB review worker \u8986\u76D6 Standards \u4E0E Spec \u4E24\u8F74\uFF1B\u5B8C\u6210\u540E gate_record({node:'code-review-standalone', findings, reviewAxes, workerSessionIds}) \u56DE discuss\u3002`;
161
144
  var REVIEWING_PROPOSAL_PROCEDURE = `## /gate-propose-review \u7F16\u6392
@@ -173,18 +156,17 @@ var PLAN_STEP_2 = stepSection(PLAN_ORCHESTRATION, "## Step 2", "## Step 3");
173
156
  var IMPLEMENT_STEP_1 = stepSection(IMPLEMENT_ORCHESTRATION, "## Step 1", "## Step 2");
174
157
  var IMPLEMENT_STEP_2 = stepSection(IMPLEMENT_ORCHESTRATION, "## Step 2", "## Step 3");
175
158
  var IMPLEMENT_STEP_3 = stepSection(IMPLEMENT_ORCHESTRATION, "## Step 3", "## Step 4");
159
+ var PLAN_REVISION_PROCEDURE = `## Plan revision
160
+ \u4E0A\u4E00\u8F6E review findings \u5DF2\u8BB0\u5F55\uFF1B\u5F53\u524D node \u4E3A plan\u3002\u4FEE\u8BA2\u5B8C\u6210\u540E\u8C03\u7528 gate_record({node:'plan'}) \u56DE\u5230 plan-review\u3002`;
161
+ var IMPLEMENT_REVISION_PROCEDURE = `## Implement revision
162
+ \u4E0A\u4E00\u8F6E review/verify findings \u5DF2\u8BB0\u5F55\uFF1B\u5F53\u524D node \u4E3A implement\u3002\u4FEE\u8BA2\u5B8C\u6210\u540E\u8C03\u7528 gate_record({node:'implement'}) \u56DE\u5230 code-review\u3002`;
176
163
  var NODE_PROCEDURES = {
177
164
  plan: PLAN_STEP_1,
178
165
  "plan-review": PLAN_STEP_2,
179
- "plan-revise": `## Plan revise
180
- \u6839\u636E findings \u7528 gate_note_write \u66F4\u65B0 Note\uFF1B\u5B8C\u6210\u540E gate_record({node:'plan-revise'}) \u56DE\u5230 plan-review\uFF0C\u518D\u6309 plan-review procedure review\u3002`,
181
166
  implement: IMPLEMENT_STEP_1,
182
167
  "code-review": IMPLEMENT_STEP_2,
183
- "implement-revise": `## Implement revise
184
- \u4FEE\u590D findings\uFF1B\u91CD\u8DD1\u6D4B\u8BD5\uFF1B\u5B8C\u6210\u540E gate_record({node:'implement-revise'}) \u56DE\u5230 code-review\uFF0C\u518D\u6309 code-review procedure review\u3002`,
185
168
  verify: IMPLEMENT_STEP_3,
186
169
  "note-lifecycle": NOTE_LIFECYCLE_ORCHESTRATION,
187
- "fix-bug": FIX_BUG_ORCHESTRATION,
188
170
  "code-review-standalone": REVIEWING_CODE_PROCEDURE,
189
171
  "proposal-review": REVIEWING_PROPOSAL_PROCEDURE,
190
172
  "verify-standalone": REVIEWING_VERIFY_PROCEDURE
@@ -193,13 +175,10 @@ var METHODOLOGY_KEYS = [
193
175
  "discuss",
194
176
  "orchestrating/plan",
195
177
  "orchestrating/plan-review",
196
- "orchestrating/plan-revise",
197
178
  "orchestrating/implement",
198
179
  "orchestrating/code-review",
199
- "orchestrating/implement-revise",
200
180
  "orchestrating/verify",
201
181
  "orchestrating/note-lifecycle",
202
- "orchestrating/fix-bug",
203
182
  "docs",
204
183
  "reviewing/code-review-standalone",
205
184
  "reviewing/proposal-review",
@@ -209,6 +188,7 @@ var METHODOLOGY_KEYS = [
209
188
  "orchestrating",
210
189
  "reviewing"
211
190
  ];
191
+ var LEGACY_METHODOLOGY_KEYS = ["orchestrating/plan-revise", "orchestrating/implement-revise"];
212
192
  var METHODOLOGY_KEY_SET = new Set(METHODOLOGY_KEYS);
213
193
  function methodologyKeyFor(state) {
214
194
  if (state.phase === "orchestrating" || state.phase === "reviewing") {
@@ -222,23 +202,21 @@ var GATE_METHODOLOGY = `## Gate \u65B9\u6CD5\u8BBA
222
202
 
223
203
  ${DISCUSS_ORCHESTRATION}
224
204
 
225
- ## orchestrating/plan \xB7 orchestrating/plan-review \xB7 orchestrating/plan-revise
226
- \u628A\u8BA8\u8BBA\u5171\u8BC6\u3001\u65E2\u6709\u51B3\u7B56\u4E0E\u7528\u6237\u9700\u6C42\u6536\u655B\u6210\u53EF\u5B9E\u65BD\u8BA1\u5212\u4E0E proposed Note\uFF1B\u8BA1\u5212\u5FC5\u987B\u5199\u6E05\u8303\u56F4\u3001\u9A8C\u6536\u3001\u5907\u9009\u4E0E\u98CE\u9669\u3002Plan Review \u72EC\u7ACB\u5224\u65AD\uFF1Bfindings \u5148\u8BB0\u5F55\u518D revise\uFF1Breview \u901A\u8FC7\u540E\u56DE discuss\u3002\u4E0D\u8981\u5728\u89C4\u5212\u91CC\u5F00\u59CB\u5B9E\u73B0\u3002
205
+ ## orchestrating/plan \xB7 orchestrating/plan-review
206
+ \u628A\u8BA8\u8BBA\u5171\u8BC6\u3001\u65E2\u6709\u51B3\u7B56\u4E0E\u7528\u6237\u9700\u6C42\u6536\u655B\u6210\u53EF\u5B9E\u65BD\u8BA1\u5212\u4E0E proposed Note\uFF1B\u8BA1\u5212\u5FC5\u987B\u5199\u6E05\u8303\u56F4\u3001\u9A8C\u6536\u3001\u5907\u9009\u4E0E\u98CE\u9669\u3002Plan Review \u72EC\u7ACB\u5224\u65AD\uFF1Bfindings \u5148\u8BB0\u5F55\uFF0C\u4FEE\u8BA2\u540E\u518D review\uFF1Breview \u901A\u8FC7\u540E\u56DE discuss\u3002\u4E0D\u8981\u5728\u89C4\u5212\u91CC\u5F00\u59CB\u5B9E\u73B0\u3002
227
207
 
228
- ## orchestrating/implement \xB7 orchestrating/implement-revise
208
+ ## orchestrating/implement
229
209
  \u6309\u5DF2\u786E\u8BA4\u7684\u8BA1\u5212\u6216\u8BA8\u8BBA\u540E\u7684\u5B9E\u65BD\u8BF4\u660E\u5B9E\u65BD\u5E76\u5B8C\u6210\u6D4B\u8BD5\uFF1B\u5B9E\u73B0\u540E\u505A\u72EC\u7ACB review\uFF0C\u518D\u7528\u53EF\u6267\u884C\u8BC1\u636E verify\uFF1B\u6700\u540E\u5B8C\u6210 Note lifecycle\u3002\u4E0D\u6269\u5927\u8303\u56F4\uFF0C\u4E0D\u5728\u5B9E\u73B0\u4E2D\u91CD\u65B0\u89C4\u5212\u3002
230
210
 
231
211
  ## orchestrating/code-review
232
- \u72EC\u7ACB\u5224\u65AD\u6539\u52A8\u662F\u5426\u6EE1\u8DB3\u5408\u540C\u4E0E\u6807\u51C6\uFF1B\u53EA\u62A5 findings\uFF0C\u4E0D\u4FEE\u4EE3\u7801\u3001\u4E0D\u66FF\u4EE3 verify\uFF1Bfindings \u8BB0\u5F55\u540E\u518D\u8FDB\u5165 revise\u3002
212
+ \u72EC\u7ACB\u5224\u65AD\u6539\u52A8\u662F\u5426\u6EE1\u8DB3\u5408\u540C\u4E0E\u6807\u51C6\uFF1B\u53EA\u62A5 findings\uFF0C\u4E0D\u4FEE\u4EE3\u7801\u3001\u4E0D\u66FF\u4EE3 verify\uFF1Bfindings \u8BB0\u5F55\u540E\u518D\u8FDB\u884C\u4FEE\u8BA2\u3002
233
213
 
234
214
  ## orchestrating/verify
235
- \u7528\u53EF\u6267\u884C\u8BC1\u636E\u5224\u5B9A PASS/FAIL\uFF1B\u4E0D\u4FEE\u6539\u4EA7\u54C1/\u6D4B\u8BD5\u8BA9\u7ED3\u679C\u53D8\u7EFF\uFF1BFAIL \u56DE implement-revise\u3002
215
+ \u7528\u53EF\u6267\u884C\u8BC1\u636E\u5224\u5B9A PASS/FAIL\uFF1B\u4E0D\u4FEE\u6539\u4EA7\u54C1/\u6D4B\u8BD5\u8BA9\u7ED3\u679C\u53D8\u7EFF\uFF1BFAIL \u56DE implement\u3002
236
216
 
237
217
  ## orchestrating/note-lifecycle
238
218
  \u5B8C\u6210 Note \u7684 finalize \u4E0E\u6821\u9A8C\uFF1B\u4E0D\u5199\u4E1A\u52A1\u4EE3\u7801\uFF1B\u68C0\u67E5\u662F\u5426\u4EA7\u751F\u5F52\u6863\u5019\u9009\uFF1B\u5B8C\u6210\u540E\u56DE discuss\u3002
239
219
 
240
- ## orchestrating/fix-bug
241
- \u5BF9\u5DF2\u6388\u6743\u7684\u5B9E\u73B0\u7F3A\u9677\uFF1A\u590D\u73B0\u3001\u56DE\u5F52\u8986\u76D6\u3001\u6839\u56E0\u3001\u6700\u5C0F\u4FEE\u590D\u3001\u72EC\u7ACB review\uFF1B\u4E0D\u505A\u65B0\u529F\u80FD\u3001\u4E0D\u6269\u5927\u8303\u56F4\uFF1B\u5B8C\u6210\u540E\u56DE discuss\u3002
242
220
 
243
221
  ## docs
244
222
  \u6587\u6863\u6CBB\u7406\uFF1B\u4E0D\u6539\u53D8\u529F\u80FD\u884C\u4E3A\uFF1B\u8303\u56F4\u7531\u6A21\u578B\u6309\u9879\u76EE\u5B9E\u9645\u6587\u6863\u9700\u8981\u5224\u65AD\uFF1B\u5B8C\u6210\u540E\u56DE discuss\u3002
@@ -280,13 +258,17 @@ function procedureFor(state, { reviewLimit = DEFAULT_REVIEW_LIMIT } = {}) {
280
258
  text = "Gate \u5DF2\u5B8C\u6210\uFF1B\u65B0\u4EFB\u52A1\u9700\u8981\u91CD\u65B0\u6388\u6743\u3002";
281
259
  } else if (variant === "docs") {
282
260
  text = DOCS_ORCHESTRATION;
261
+ } else if (state.node === "plan" && state.revision !== null) {
262
+ text = PLAN_REVISION_PROCEDURE;
263
+ } else if (state.node === "implement" && state.revision !== null) {
264
+ text = IMPLEMENT_REVISION_PROCEDURE;
283
265
  } else {
284
266
  text = NODE_PROCEDURES[state.node ?? ""] ?? "";
285
267
  }
286
268
  if (text === "") {
287
269
  text = "\u5F53\u524D phase/node \u6CA1\u6709\u5339\u914D\u7684 procedure\uFF1B\u8C03\u7528 gate_status \u91CD\u65B0\u8BFB\u53D6\uFF1B\u82E5\u4ECD\u4E0D\u4E00\u81F4\uFF0C\u56DE discuss \u4FEE\u590D Gate \u72B6\u6001\u3002";
288
270
  }
289
- if (["plan", "implement", "fix-bug", "reviewing-code", "reviewing-proposal", "reviewing-verify"].includes(variant)) {
271
+ if (["plan", "implement", "reviewing-code", "reviewing-proposal", "reviewing-verify"].includes(variant)) {
290
272
  text = [text, DISPATCH_RULE].filter(Boolean).join("\n\n");
291
273
  }
292
274
  if (variant === "plan" || variant === "implement") {
@@ -323,7 +305,8 @@ function statusText(state, reviewLimit = DEFAULT_REVIEW_LIMIT, { includeRounds =
323
305
  `work\uFF1A${state.work}`,
324
306
  `blockReason\uFF1A${state.blockReason ?? "\u65E0"}`,
325
307
  `planReady\uFF1A${state.planReady ? "\u662F" : "\u5426"}`,
326
- ...includeRounds ? [`rounds\uFF1A${roundsText(state, reviewLimit)}`] : []
308
+ ...includeRounds ? [`rounds\uFF1A${roundsText(state, reviewLimit)}`] : [],
309
+ ...state.revision === null ? [] : [`revision\uFF1A${state.revision.from} \u540E / round ${state.revision.round} / findings ${state.revision.findings.length}`]
327
310
  ];
328
311
  if (state.notePaths?.length > 0 || isMechanicalDecision(state.noteDecision)) {
329
312
  lines.push(`notes\uFF1A${state.noteDecision ?? "\u65E0"} ${state.notePaths?.length ?? 0} \u7BC7\uFF0Cverified=${state.noteVerified === true ? "\u662F" : "\u5426"}`);
@@ -370,6 +353,7 @@ function defaultState() {
370
353
  work: "active",
371
354
  blockReason: null,
372
355
  rounds: { planReview: 0, codeReview: 0 },
356
+ revision: null,
373
357
  exhausted: { plan: false, code: false },
374
358
  planReady: false,
375
359
  verification: null,
@@ -387,15 +371,37 @@ function defaultState() {
387
371
  function textOrNull(value) {
388
372
  return typeof value === "string" ? value : null;
389
373
  }
374
+ function revisionOf(value) {
375
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return null;
376
+ const source = value;
377
+ if (source.from !== "plan-review" && source.from !== "code-review" && source.from !== "verify") return null;
378
+ if (!Array.isArray(source.findings)) return null;
379
+ return {
380
+ from: source.from,
381
+ findings: source.findings.filter((entry) => entry !== null && typeof entry === "object" && !Array.isArray(entry)).map((entry) => ({ ...entry })),
382
+ round: Number(source.round) || 0
383
+ };
384
+ }
385
+ function legacyNode(node) {
386
+ if (node === "plan-revise") return "plan";
387
+ if (node === "implement-revise") return "implement";
388
+ return node;
389
+ }
390
390
  function normalizeState(value) {
391
391
  const base = defaultState();
392
392
  if (value === null || typeof value !== "object" || Array.isArray(value)) return base;
393
393
  const source = value;
394
394
  const phase = PHASES.includes(source.phase) ? source.phase : "discuss";
395
- const blockedFrom = source.blockedFrom !== null && typeof source.blockedFrom === "object" && !Array.isArray(source.blockedFrom) ? { phase: textOrNull(source.blockedFrom.phase), node: textOrNull(source.blockedFrom.node) } : null;
395
+ let node = legacyNode(textOrNull(source.node));
396
+ let revision = revisionOf(source.revision);
397
+ if (revision === null && source.node === "plan-revise") revision = { from: "plan-review", findings: [], round: Number(source.rounds?.planReview) || 0 };
398
+ if (revision === null && source.node === "implement-revise") revision = { from: "code-review", findings: [], round: Number(source.rounds?.codeReview) || 0 };
399
+ if (revision === null && source.blockedFrom?.node === "plan-revise") revision = { from: "plan-review", findings: [], round: Number(source.rounds?.planReview) || 0 };
400
+ if (revision === null && source.blockedFrom?.node === "implement-revise") revision = { from: "code-review", findings: [], round: Number(source.rounds?.codeReview) || 0 };
401
+ const blockedFrom = source.blockedFrom !== null && typeof source.blockedFrom === "object" && !Array.isArray(source.blockedFrom) ? { phase: textOrNull(source.blockedFrom.phase), node: legacyNode(textOrNull(source.blockedFrom.node)) } : null;
396
402
  return {
397
403
  phase,
398
- node: textOrNull(source.node),
404
+ node,
399
405
  task: textOrNull(source.task),
400
406
  work: textOrNull(source.work) ?? "active",
401
407
  blockReason: textOrNull(source.blockReason),
@@ -403,6 +409,7 @@ function normalizeState(value) {
403
409
  planReview: Number(source.rounds?.planReview) || 0,
404
410
  codeReview: Number(source.rounds?.codeReview) || 0
405
411
  },
412
+ revision,
406
413
  exhausted: {
407
414
  plan: source.exhausted?.plan === true,
408
415
  code: source.exhausted?.code === true
@@ -778,7 +785,8 @@ function applyCommandEvent(state, name, args) {
778
785
  noteDecision: null,
779
786
  noteSearch: null,
780
787
  noteVerified: false,
781
- noteFinalizeRecovery: []
788
+ noteFinalizeRecovery: [],
789
+ revision: null
782
790
  };
783
791
  case "gate-enter-implement":
784
792
  return {
@@ -791,18 +799,17 @@ function applyCommandEvent(state, name, args) {
791
799
  blockedFrom: null,
792
800
  verification: null,
793
801
  noteVerified: false,
794
- noteFinalizeRecovery: []
802
+ noteFinalizeRecovery: [],
803
+ revision: null
795
804
  };
796
- case "gate-fix-bug":
797
- return { ...state, phase: "orchestrating", task: text === "" ? state.task ?? "\u5F53\u524D\u4E0A\u4E0B\u6587\u4E2D\u7684\u7F3A\u9677" : text, node: "fix-bug", work: "active", blockReason: null, blockedFrom: null };
798
805
  case "gate-docs":
799
- return { ...state, phase: "docs", task: text, node: null, work: "active", blockReason: null, blockedFrom: null };
806
+ return { ...state, phase: "docs", task: text, node: null, work: "active", blockReason: null, blockedFrom: null, revision: null };
800
807
  case "gate-implement-review":
801
- return { ...state, phase: "reviewing", task: text, node: "code-review-standalone", work: "active", blockReason: null, blockedFrom: null };
808
+ return { ...state, phase: "reviewing", task: text, node: "code-review-standalone", work: "active", blockReason: null, blockedFrom: null, revision: null };
802
809
  case "gate-code-verify":
803
- return { ...state, phase: "reviewing", task: text, node: "verify-standalone", work: "active", blockReason: null, blockedFrom: null };
810
+ return { ...state, phase: "reviewing", task: text, node: "verify-standalone", work: "active", blockReason: null, blockedFrom: null, revision: null };
804
811
  case "gate-propose-review":
805
- return { ...state, phase: "reviewing", task: text, node: "proposal-review", work: "active", blockReason: null, blockedFrom: null };
812
+ return { ...state, phase: "reviewing", task: text, node: "proposal-review", work: "active", blockReason: null, blockedFrom: null, revision: null };
806
813
  case "gate-block":
807
814
  return {
808
815
  ...state,
@@ -822,7 +829,7 @@ function applyCommandEvent(state, name, args) {
822
829
  blockedFrom: null
823
830
  };
824
831
  case "gate-return-discuss":
825
- return { ...state, phase: "discuss", node: null, work: "active", blockReason: null, blockedFrom: null };
832
+ return { ...state, phase: "discuss", node: null, work: "active", blockReason: null, blockedFrom: null, revision: null };
826
833
  default:
827
834
  return state;
828
835
  }
@@ -1059,10 +1066,10 @@ function accessFor(state, worker) {
1059
1066
  repoWrite: "push"
1060
1067
  };
1061
1068
  }
1062
- if (state.node === "plan" || state.node === "plan-revise") {
1069
+ if (state.node === "plan") {
1063
1070
  return { read: true, write: "none", noteWrite: true, shell: "read", repoWrite: "none" };
1064
1071
  }
1065
- if (state.node === "implement" || state.node === "implement-revise" || state.node === "fix-bug") {
1072
+ if (state.node === "implement") {
1066
1073
  return { read: true, write: "workspace", noteWrite: false, shell: "write", repoWrite: "push" };
1067
1074
  }
1068
1075
  return { read: true, write: "none", noteWrite: false, shell: "read", repoWrite: "none" };
@@ -1152,8 +1159,8 @@ function workerProtocol(node) {
1152
1159
  return [
1153
1160
  "## Gate worker",
1154
1161
  "\u4F60\u662F gate \u4E3A\u8BE5\u8282\u70B9\u6D3E\u53D1\u7684 worker\u3002\u53EA\u6267\u884C\u8BE5\u8282\u70B9\uFF1B\u4E0D\u8981\u8C03\u7528 gate_record\uFF0C\u4E0D\u8981\u63A8\u8FDB gate\u3002",
1155
- node === "verify-standalone" ? "\u52A0\u8F7D\u4F7F\u7528 gate-user-verify \u5B8C\u6210\u9A8C\u6536\uFF0C\u5E76\u6309\u8BE5\u6280\u80FD Step 6 \u6C47\u62A5\u3002\u4EFB\u52A1\u4E0E\u6C47\u62A5\u6A21\u677F\u89C1\u8BE5\u6280\u80FD assets/worker-briefs/gate-code-verify.md\u3002\u4E0D\u4FEE\u6539\u4EA7\u54C1\u4EE3\u7801\u3001\u6D4B\u8BD5\u3001\u9700\u6C42\u6216\u8BBE\u8BA1\uFF1B\u53EF\u4EE5\u8FD0\u884C\u6D4B\u8BD5/\u547D\u4EE4\u4F5C\u4E3A\u8BC1\u636E\uFF0C\u4F46\u4E0D\u5F97\u4FEE\u6539\u3001\u653E\u5BBD\u6216\u91CD\u5199\u6D4B\u8BD5\uFF1B\u4E0D\u8981\u81EA\u884C\u63D0\u4EA4\u3002" : node === "fix-bug" ? "\u4E3B\u4EE3\u7406\u5DF2\u8BFB\u53D6 gate-fix-bug\uFF1B\u4F60\u6267\u884C gate-fix-bug \u7684 Process 1-9\uFF08\u590D\u73B0\u3001\u56DE\u5F52\u8986\u76D6\u3001\u6839\u56E0\u3001\u6700\u5C0F\u4FEE\u590D\u3001\u6D4B\u8BD5\uFF09\uFF0C\u8FD4\u56DE\u4FEE\u590D receipt\uFF1B\u4E0D\u8981\u81EA\u884C\u5B8C\u6210 Step 10-12\uFF0C\u4E0D\u8981\u63D0\u4EA4\u3002\u4E0D\u6539\u4EA7\u54C1\u5408\u540C\u3001\u4E0D\u6269\u5927\u8303\u56F4\u3002" : "\u4E3B\u4EE3\u7406\u5DF2\u7ECF\u52A0\u8F7D\u6240\u9700 gate \u6280\u80FD\uFF0C\u5E76\u628A\u5177\u4F53\u4EFB\u52A1\u4E0E\u76F8\u5173\u65B9\u6CD5\u8981\u6C42\u4EA4\u7ED9\u4F60\u3002\u4E0D\u8981\u81EA\u5DF1\u52A0\u8F7D gate \u6280\u80FD\u3002",
1156
- node === "plan" || node === "plan-revise" ? "\u7528 gate_note_write \u5728 .agents/notes/proposed \u4E0B\u521B\u5EFA\u6216\u66F4\u65B0 proposed Agent Note\uFF1B\u539F\u5730\u540C\u6B65\u65E2\u6709 implemented Note \u65F6\u8DEF\u5F84\u5199 implemented/<class>/...\uFF1Bplanning \u4E2D write/edit/apply_patch \u548C\u4ED3\u5E93\u5199\u88AB\u62D2\u7EDD\uFF0C\u53EA\u8BFB shell \u53EF\u7528\u3002" : ""
1162
+ node === "verify-standalone" ? "\u52A0\u8F7D\u4F7F\u7528 gate-user-verify \u5B8C\u6210\u9A8C\u6536\uFF0C\u5E76\u6309\u8BE5\u6280\u80FD Step 6 \u6C47\u62A5\u3002\u4EFB\u52A1\u4E0E\u6C47\u62A5\u6A21\u677F\u89C1\u8BE5\u6280\u80FD assets/worker-briefs/gate-code-verify.md\u3002\u4E0D\u4FEE\u6539\u4EA7\u54C1\u4EE3\u7801\u3001\u6D4B\u8BD5\u3001\u9700\u6C42\u6216\u8BBE\u8BA1\uFF1B\u53EF\u4EE5\u8FD0\u884C\u6D4B\u8BD5/\u547D\u4EE4\u4F5C\u4E3A\u8BC1\u636E\uFF0C\u4F46\u4E0D\u5F97\u4FEE\u6539\u3001\u653E\u5BBD\u6216\u91CD\u5199\u6D4B\u8BD5\uFF1B\u4E0D\u8981\u81EA\u884C\u63D0\u4EA4\u3002" : "\u4E3B\u4EE3\u7406\u5DF2\u7ECF\u52A0\u8F7D\u6240\u9700 gate \u6280\u80FD\uFF0C\u5E76\u628A\u5177\u4F53\u4EFB\u52A1\u4E0E\u76F8\u5173\u65B9\u6CD5\u8981\u6C42\u4EA4\u7ED9\u4F60\u3002\u4E0D\u8981\u81EA\u5DF1\u52A0\u8F7D gate \u6280\u80FD\u3002",
1163
+ node === "plan" ? "\u7528 gate_note_write \u5728 .agents/notes/proposed \u4E0B\u521B\u5EFA\u6216\u66F4\u65B0 proposed Agent Note\uFF1B\u539F\u5730\u540C\u6B65\u65E2\u6709 implemented Note \u65F6\u8DEF\u5F84\u5199 implemented/<class>/...\uFF1Bplanning \u4E2D write/edit/apply_patch \u548C\u4ED3\u5E93\u5199\u88AB\u62D2\u7EDD\uFF0C\u53EA\u8BFB shell \u53EF\u7528\u3002" : ""
1157
1164
  ].filter(Boolean).join("\n\n");
1158
1165
  }
1159
1166
  var REVIEW_NODES = /* @__PURE__ */ new Set(["plan-review", "proposal-review", "code-review", "code-review-standalone"]);
@@ -1170,9 +1177,11 @@ function reviewAxesError(args) {
1170
1177
  }
1171
1178
  return void 0;
1172
1179
  }
1173
- async function workerEvidenceError(ctx, root, args) {
1180
+ async function workerEvidenceError(ctx, root, args, state) {
1174
1181
  if (!WORKER_NODES.has(args.node)) return void 0;
1175
1182
  const ids = Array.isArray(args.workerSessionIds) ? [...new Set(args.workerSessionIds.filter((value) => typeof value === "string" && value !== ""))] : [];
1183
+ const revisionNode = args.node === "plan" && state?.revision?.from === "plan-review" || args.node === "implement" && (state?.revision?.from === "code-review" || state?.revision?.from === "verify");
1184
+ if (ids.length === 0 && revisionNode) return void 0;
1176
1185
  if (ids.length === 0) return { code: "worker-required", reason: "gate_record \u9700\u8981 workerSessionIds\uFF1B\u6CA1\u6709 worker \u4E0D\u80FD\u63A8\u8FDB\u3002" };
1177
1186
  const service = ctx.get("subagents");
1178
1187
  if (service === void 0 || typeof service.listDescendants !== "function") {
@@ -1291,7 +1300,7 @@ var GATE_FROZEN_REASON = "Gate \u5DF2\u51BB\u7ED3\uFF1A\u5148 /gate-resume";
1291
1300
  function fileWriteDenied(state, effective) {
1292
1301
  if (state.phase === "blocked") return GATE_FROZEN_REASON;
1293
1302
  if (!effective.worker && state.phase === "discuss") return DISCUSS_READ_ONLY;
1294
- if (effective.worker && (state.node === "plan" || state.node === "plan-revise")) return "planning worker \u53EA\u5141\u8BB8 gate_note_write\uFF1B\u4EA7\u54C1\u6587\u4EF6\u548C\u4ED3\u5E93\u5199\u88AB\u62D2\u7EDD\u3002";
1303
+ if (effective.worker && state.node === "plan") return "planning worker \u53EA\u5141\u8BB8 gate_note_write\uFF1B\u4EA7\u54C1\u6587\u4EF6\u548C\u4ED3\u5E93\u5199\u88AB\u62D2\u7EDD\u3002";
1295
1304
  if (effective.worker) return `\u5F53\u524D ${state.node ?? "worker"} worker \u4E0D\u5141\u8BB8\u5199\u6587\u4EF6\uFF1Breview/verify worker \u53EA\u8BFB\u3002`;
1296
1305
  return "\u5F53\u524D\u89D2\u8272\u4E0D\u5141\u8BB8\u5199\u6587\u4EF6";
1297
1306
  }
@@ -1503,7 +1512,7 @@ var BASE_ARTIFACT_POLICY = {
1503
1512
  }
1504
1513
  }
1505
1514
  };
1506
- var PHASES2 = new Set(METHODOLOGY_KEYS);
1515
+ var PHASES2 = /* @__PURE__ */ new Set([...METHODOLOGY_KEYS, ...LEGACY_METHODOLOGY_KEYS]);
1507
1516
  var RESERVED = [".agents/gate/artifact-policy.json", ".agents/notes/"];
1508
1517
  function normalizeArtifactPath(value) {
1509
1518
  return path9.posix.normalize(String(value).replaceAll("\\", "/").replace(/^\.\//u, ""));
@@ -1810,7 +1819,6 @@ var GATE_COMMANDS = [
1810
1819
  { name: "gate-enter-plan", description: "\u57FA\u4E8E\u8BA8\u8BBA\u5171\u8BC6\u3001\u65E2\u6709\u51B3\u7B56\u4E0E\u7528\u6237\u9700\u6C42\u8FDB\u5165 planning", hint: "<\u5177\u4F53\u5DE5\u4F5C\u4E8B\u9879\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49>", when: "discuss/complete" },
1811
1820
  { name: "gate-enter-implement", description: "\u57FA\u4E8E\u5DF2\u786E\u8BA4\u8BA1\u5212\u6216\u8BA8\u8BBA\u540E\u7684\u5B9E\u65BD\u8BF4\u660E\u8FDB\u5165 implementation", hint: "<\u5177\u4F53\u5DE5\u4F5C\u4E8B\u9879\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49>", when: "discuss/complete" },
1812
1821
  { name: "gate-prd", description: "\u5728 discuss \u4E2D\u6309\u7528\u6237\u8981\u6C42\u521B\u5EFA\u6216\u66F4\u65B0 PRD", hint: "[\u4E3B\u9898\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49]", when: "discuss" },
1813
- { name: "gate-fix-bug", description: "\u4E3A\u5DF2\u6388\u6743\u7F3A\u9677\u6D3E\u53D1 fix worker\uFF0C\u57FA\u4E8E\u63CF\u8FF0\u6216\u5F53\u524D\u4E0A\u4E0B\u6587\u4FEE\u590D", hint: "<\u5177\u4F53\u5DE5\u4F5C\u4E8B\u9879\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49>", when: "discuss/complete" },
1814
1822
  { name: "gate-docs", description: "\u8FDB\u5165\u6587\u6863\u6CBB\u7406\uFF0C\u6309\u9879\u76EE\u6587\u6863\u89C4\u8303\u5904\u7406", hint: "[\u6587\u6863\u8303\u56F4\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49]", when: "discuss/complete" },
1815
1823
  { name: "gate-implement-review", description: "\u5BF9\u5F53\u524D\u6539\u52A8\u505A\u72EC\u7ACB\u53EA\u8BFB code review", hint: "<\u5177\u4F53\u5DE5\u4F5C\u4E8B\u9879\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49>", when: "discuss/complete" },
1816
1824
  { name: "gate-code-verify", description: "\u5BF9\u5F53\u524D\u6539\u52A8\u505A\u72EC\u7ACB\u53EA\u8BFB\u9A8C\u6536\uFF08gate-user-verify\uFF09", hint: "<\u5177\u4F53\u5DE5\u4F5C\u4E8B\u9879\u6216\u4E0A\u4E0B\u6587\u8BED\u4E49>", when: "discuss/complete" },
@@ -1941,23 +1949,6 @@ ignore\uFF1A${projectGit.ignore}` };
1941
1949
  wake(invocation, state, ["\u8BF7\u6309 gate-prd \u6280\u80FD\u521B\u5EFA\u6216\u66F4\u65B0 PRD\u3002", "\u4E3B\u9898/\u4E0A\u4E0B\u6587\uFF1A" + topic, skill].filter(Boolean).join("\n\n"), "gate-prd");
1942
1950
  return { kind: "success", text: "\u5DF2\u8BF7\u6C42 PRD\uFF1A" + topic };
1943
1951
  });
1944
- command2("gate-fix-bug", async (invocation) => {
1945
- const brief = String(invocation.rawInput ?? "").trim();
1946
- const gate = resolveGate(ctx, invocation.agent);
1947
- const state = store.read(gate.root, invocation.agent);
1948
- if (state.phase !== "discuss" && state.phase !== "complete") return { kind: "error", text: `\u5F53\u524D phase \u662F ${state.phase}` };
1949
- if (state.work === "blocked" || state.blockReason !== null) return { kind: "error", text: `\u5F53\u524D\u88AB blocked\uFF1A${state.blockReason ?? "unknown"}\uFF1B\u5148 /gate-resume` };
1950
- const scope2 = brief === "" ? state.task ?? "\u5F53\u524D\u4E0A\u4E0B\u6587\u4E2D\u7684\u7F3A\u9677" : brief;
1951
- state.phase = "orchestrating";
1952
- state.node = "fix-bug";
1953
- state.task = scope2;
1954
- state.work = "active";
1955
- state.blockReason = null;
1956
- state.blockedFrom = null;
1957
- store.write(gate.root, invocation.agent, state);
1958
- wake(invocation, state, `Gate \u5DF2\u8FDB\u5165 fix-bug\uFF1A${scope2}\u3002`, "gate-fix-bug");
1959
- return { kind: "success", text: `\u8FDB\u5165 fix-bug\uFF1A${scope2}` };
1960
- });
1961
1952
  command2("gate-docs", async (invocation) => {
1962
1953
  const scope2 = String(invocation.rawInput ?? "").trim() || "\u6587\u6863\u6CBB\u7406";
1963
1954
  const gate = resolveGate(ctx, invocation.agent);
@@ -1965,6 +1956,7 @@ ignore\uFF1A${projectGit.ignore}` };
1965
1956
  if (state.phase !== "discuss" && state.phase !== "complete") return { kind: "error", text: `\u5F53\u524D phase \u662F ${state.phase}` };
1966
1957
  if (state.work === "blocked" || state.blockReason !== null) return { kind: "error", text: `\u5F53\u524D\u88AB blocked\uFF1A${state.blockReason ?? "unknown"}\uFF1B\u5148 /gate-resume` };
1967
1958
  state.phase = "docs";
1959
+ state.revision = null;
1968
1960
  state.task = scope2;
1969
1961
  state.work = "active";
1970
1962
  state.blockReason = null;
@@ -1984,6 +1976,7 @@ ignore\uFF1A${projectGit.ignore}` };
1984
1976
  state.phase = "reviewing";
1985
1977
  state.task = scope2;
1986
1978
  state.node = "code-review-standalone";
1979
+ state.revision = null;
1987
1980
  state.work = "active";
1988
1981
  state.blockReason = null;
1989
1982
  state.blockedFrom = null;
@@ -2001,6 +1994,7 @@ ignore\uFF1A${projectGit.ignore}` };
2001
1994
  state.phase = "reviewing";
2002
1995
  state.task = scope2;
2003
1996
  state.node = "verify-standalone";
1997
+ state.revision = null;
2004
1998
  state.work = "active";
2005
1999
  state.blockReason = null;
2006
2000
  state.blockedFrom = null;
@@ -2018,6 +2012,7 @@ ignore\uFF1A${projectGit.ignore}` };
2018
2012
  state.phase = "reviewing";
2019
2013
  state.task = scope2;
2020
2014
  state.node = "proposal-review";
2015
+ state.revision = null;
2021
2016
  state.work = "active";
2022
2017
  state.blockReason = null;
2023
2018
  state.blockedFrom = null;
@@ -2063,6 +2058,7 @@ ignore\uFF1A${projectGit.ignore}` };
2063
2058
  if (state.phase === "blocked") return { kind: "error", text: `\u5F53\u524D blocked\uFF1A${state.blockReason ?? "unknown"}\uFF1B\u5148 /gate-resume` };
2064
2059
  state.phase = "discuss";
2065
2060
  state.node = null;
2061
+ state.revision = null;
2066
2062
  state.work = "active";
2067
2063
  state.blockReason = null;
2068
2064
  state.blockedFrom = null;
@@ -2205,7 +2201,7 @@ function registerRecord(ctx, deps) {
2205
2201
  const { store, reviewLimit, wake } = deps;
2206
2202
  ctx.tools.register({
2207
2203
  name: "gate_record",
2208
- description: "\u8BB0\u5F55 root agent \u6D3E\u53D1\u7684\u8282\u70B9 worker \u7ED3\u679C\u5E76\u63A8\u8FDB gate \u72B6\u6001\u3002worker \u8282\u70B9\u8981\u6C42 workerSessionIds\uFF1Breview \u8282\u70B9\u8981\u6C42\u4E24\u8F74\u7ED3\u679C\uFF1Bverify \u8981\u6C42 toolResults\u3002\u4EC5 root agent \u53EF\u8C03\u7528\u3002",
2204
+ description: "\u8BB0\u5F55 root agent \u6D3E\u53D1\u7684\u8282\u70B9 worker \u7ED3\u679C\u5E76\u63A8\u8FDB gate \u72B6\u6001\u3002\u9996\u6B21 plan/implement\u3001review\u3001verify \u7B49 worker \u8282\u70B9\u8981\u6C42 workerSessionIds\uFF1Bplan/implement \u4FEE\u8BA2\u53EF\u7701\u7565\uFF1Breview \u8282\u70B9\u8981\u6C42\u4E24\u8F74\u7ED3\u679C\uFF1Bverify \u8981\u6C42 toolResults\u3002\u4EC5 root agent \u53EF\u8C03\u7528\u3002",
2209
2205
  parameters: {
2210
2206
  type: "object",
2211
2207
  additionalProperties: false,
@@ -2261,6 +2257,7 @@ function registerRecord(ctx, deps) {
2261
2257
  if (args.node !== "docs") return fail({ code: "wrong-node", expected: "docs", got: args.node ?? null, reason: 'docs \u9636\u6BB5\u53EA\u80FD\u901A\u8FC7 gate_record({node:"docs"}) \u7ED3\u675F\u3002' });
2262
2258
  state.phase = "discuss";
2263
2259
  state.node = null;
2260
+ state.revision = null;
2264
2261
  state.work = "active";
2265
2262
  state.blockReason = null;
2266
2263
  state.blockedFrom = null;
@@ -2274,7 +2271,7 @@ function registerRecord(ctx, deps) {
2274
2271
  if (state.node !== args.node) return fail({ code: "wrong-node", expected: state.node ?? null, got: args.node ?? null, reason: `\u5F53\u524D\u8282\u70B9\u662F ${state.node ?? "\u65E0"}\uFF0C\u8BF7\u6C42\u7684 node \u662F ${args.node ?? "\u672A\u63D0\u4F9B"}\u3002` });
2275
2272
  const axesError = reviewAxesError(args);
2276
2273
  if (axesError !== void 0) return fail(axesError);
2277
- const workerError = await workerEvidenceError(ctx, root, args);
2274
+ const workerError = await workerEvidenceError(ctx, root, args, state);
2278
2275
  if (workerError !== void 0) return fail(workerError);
2279
2276
  const topFindings = Array.isArray(args.findings) ? args.findings : [];
2280
2277
  const axesFindings = REVIEW_NODES.has(args.node) ? [
@@ -2301,44 +2298,53 @@ function registerRecord(ctx, deps) {
2301
2298
  state.work = "active";
2302
2299
  state.blockReason = null;
2303
2300
  state.blockedFrom = null;
2301
+ state.revision = null;
2304
2302
  } else if (args.node === "code-review-standalone") {
2305
2303
  state.phase = "discuss";
2306
2304
  state.node = null;
2305
+ state.revision = null;
2307
2306
  state.work = "active";
2308
2307
  state.blockReason = null;
2309
2308
  } else if (args.node === "plan") {
2310
- if (typeof args.task !== "string" || args.task.trim() === "") {
2311
- return fail({ code: "task-required", reason: "node=plan \u5FC5\u987B\u643A\u5E26 task\uFF08\u5DE5\u4F5C\u9879\u7B80\u8FF0\uFF1Bmechanical \u7528 noteDecision \u8868\u793A\uFF09\u3002" });
2312
- }
2313
- const decision = args.noteDecision;
2314
- if (!isNoteDecision(decision)) {
2315
- return fail({ code: "note-decision-required", reason: "node=plan \u9700\u8981 noteDecision\uFF08new/update/in-place/mechanical\uFF09\u3002" });
2316
- }
2317
- const optionNotePaths = notePathsForDecision(args.notePaths, decision);
2318
- const noteError = validateNotePaths(gate.root, optionNotePaths, decision);
2319
- if (noteError !== void 0) return fail(noteError);
2320
- state.task = args.task.trim();
2321
- state.notePaths = isMechanicalDecision(decision) ? [] : optionNotePaths;
2322
- state.noteDecision = decision;
2323
- state.noteSearch = typeof args.noteSearch === "string" ? args.noteSearch : null;
2324
- state.noteVerified = isMechanicalDecision(decision);
2325
- state.node = "plan-review";
2326
- } else if (args.node === "plan-revise") {
2327
- if (args.noteDecision !== void 0 || args.notePaths !== void 0) {
2309
+ if (state.revision?.from === "plan-review") {
2328
2310
  const decision = args.noteDecision ?? state.noteDecision;
2311
+ if (args.noteDecision !== void 0 && !isNoteDecision(args.noteDecision)) {
2312
+ return fail({ code: "note-decision-required", reason: "plan \u4FEE\u8BA2\u7684 noteDecision \u5FC5\u987B\u662F new/update/in-place/mechanical\u3002" });
2313
+ }
2314
+ if (args.noteDecision !== void 0 || args.notePaths !== void 0) {
2315
+ if (!isNoteDecision(decision)) {
2316
+ return fail({ code: "note-decision-required", reason: "plan \u4FEE\u8BA2\u66F4\u65B0 notePaths \u9700\u8981\u5408\u6CD5 noteDecision\u3002" });
2317
+ }
2318
+ const requestedNotePaths = args.notePaths ?? state.notePaths;
2319
+ const optionNotePaths = notePathsForDecision(requestedNotePaths, decision);
2320
+ const noteError = validateNotePaths(gate.root, optionNotePaths, decision);
2321
+ if (noteError !== void 0) return fail(noteError);
2322
+ state.notePaths = isMechanicalDecision(decision) ? [] : optionNotePaths;
2323
+ state.noteDecision = decision;
2324
+ if (typeof args.noteSearch === "string") state.noteSearch = args.noteSearch;
2325
+ state.noteVerified = isMechanicalDecision(decision);
2326
+ }
2327
+ state.revision = null;
2328
+ state.node = "plan-review";
2329
+ } else {
2330
+ if (typeof args.task !== "string" || args.task.trim() === "") {
2331
+ return fail({ code: "task-required", reason: "node=plan \u5FC5\u987B\u643A\u5E26 task\uFF08\u5DE5\u4F5C\u9879\u7B80\u8FF0\uFF1Bmechanical \u7528 noteDecision \u8868\u793A\uFF09\u3002" });
2332
+ }
2333
+ const decision = args.noteDecision;
2329
2334
  if (!isNoteDecision(decision)) {
2330
- return fail({ code: "note-decision-required", reason: "plan-revise \u9700\u8981\u5408\u6CD5 noteDecision\u3002" });
2335
+ return fail({ code: "note-decision-required", reason: "node=plan \u9700\u8981 noteDecision\uFF08new/update/in-place/mechanical\uFF09\u3002" });
2331
2336
  }
2332
- const requestedNotePaths = args.notePaths ?? state.notePaths;
2333
- const optionNotePaths = notePathsForDecision(requestedNotePaths, decision);
2337
+ const optionNotePaths = notePathsForDecision(args.notePaths, decision);
2334
2338
  const noteError = validateNotePaths(gate.root, optionNotePaths, decision);
2335
2339
  if (noteError !== void 0) return fail(noteError);
2340
+ state.task = args.task.trim();
2336
2341
  state.notePaths = isMechanicalDecision(decision) ? [] : optionNotePaths;
2337
2342
  state.noteDecision = decision;
2338
- if (typeof args.noteSearch === "string") state.noteSearch = args.noteSearch;
2343
+ state.noteSearch = typeof args.noteSearch === "string" ? args.noteSearch : null;
2339
2344
  state.noteVerified = isMechanicalDecision(decision);
2345
+ state.revision = null;
2346
+ state.node = "plan-review";
2340
2347
  }
2341
- state.node = "plan-review";
2342
2348
  } else if (args.node === "plan-review") {
2343
2349
  state.rounds.planReview += 1;
2344
2350
  if (findings.length === 0) {
@@ -2347,6 +2353,7 @@ function registerRecord(ctx, deps) {
2347
2353
  state.planReady = true;
2348
2354
  state.work = "active";
2349
2355
  state.blockReason = null;
2356
+ state.revision = null;
2350
2357
  commitHint = "\u5EFA\u8BAE\u63D0\u4EA4 planning baseline\uFF08Note + \u8BA1\u5212\uFF09";
2351
2358
  } else if (state.rounds.planReview >= reviewLimit) {
2352
2359
  state.exhausted.plan = true;
@@ -2355,45 +2362,74 @@ function registerRecord(ctx, deps) {
2355
2362
  state.node = null;
2356
2363
  state.work = "blocked";
2357
2364
  state.blockReason = "plan-review-rounds-exhausted";
2358
- } else state.node = "plan-revise";
2359
- } else if (args.node === "implement") {
2360
- if (args.noteDecision !== void 0 && !isNoteDecision(args.noteDecision)) {
2361
- return fail({ code: "note-decision-required", reason: "implement \u7684 noteDecision \u5FC5\u987B\u662F new/update/in-place/mechanical\u3002" });
2362
- }
2363
- const decision = args.noteDecision ?? state.noteDecision;
2364
- if (decision !== null && !isNoteDecision(decision)) {
2365
- return fail({ code: "note-decision-required", reason: "implement \u7684 noteDecision \u5FC5\u987B\u662F new/update/in-place/mechanical\u3002" });
2366
- }
2367
- if (isMechanicalDecision(args.noteDecision)) {
2368
- state.noteDecision = MECHANICAL_DECISION;
2369
- state.notePaths = [];
2370
- state.noteVerified = true;
2371
- } else if (args.noteDecision === void 0 && isMechanicalDecision(state.noteDecision)) {
2365
+ state.revision = null;
2372
2366
  } else {
2373
- if (Array.isArray(args.notePaths)) {
2367
+ state.revision = { from: "plan-review", findings, round: state.rounds.planReview };
2368
+ state.node = "plan";
2369
+ }
2370
+ } else if (args.node === "implement") {
2371
+ if (state.revision?.from === "code-review" || state.revision?.from === "verify") {
2372
+ if (args.noteDecision !== void 0 && !isNoteDecision(args.noteDecision)) {
2373
+ return fail({ code: "note-decision-required", reason: "implement \u4FEE\u8BA2\u7684 noteDecision \u5FC5\u987B\u662F new/update/in-place/mechanical\u3002" });
2374
+ }
2375
+ if (args.notePaths !== void 0) {
2376
+ const decision = args.noteDecision ?? state.noteDecision;
2374
2377
  if (!isNoteDecision(decision)) {
2375
- return fail({ code: "note-decision-required", reason: "implement \u5199 notePaths \u9700\u8981\u5408\u6CD5 noteDecision\u3002" });
2378
+ return fail({ code: "note-decision-required", reason: "implement \u4FEE\u8BA2\u66F4\u65B0 notePaths \u9700\u8981\u5408\u6CD5 noteDecision\u3002" });
2376
2379
  }
2377
2380
  const nextNotePaths = normalizeNotePaths(args.notePaths);
2378
2381
  const noteError = validateNotePaths(gate.root, nextNotePaths, decision);
2379
2382
  if (noteError !== void 0) return fail(noteError);
2380
2383
  state.notePaths = nextNotePaths;
2384
+ state.noteDecision = decision;
2385
+ state.noteVerified = isMechanicalDecision(decision);
2386
+ }
2387
+ state.revision = null;
2388
+ state.node = "code-review";
2389
+ } else {
2390
+ if (args.noteDecision !== void 0 && !isNoteDecision(args.noteDecision)) {
2391
+ return fail({ code: "note-decision-required", reason: "implement \u7684 noteDecision \u5FC5\u987B\u662F new/update/in-place/mechanical\u3002" });
2392
+ }
2393
+ const decision = args.noteDecision ?? state.noteDecision;
2394
+ if (decision !== null && !isNoteDecision(decision)) {
2395
+ return fail({ code: "note-decision-required", reason: "implement \u7684 noteDecision \u5FC5\u987B\u662F new/update/in-place/mechanical\u3002" });
2396
+ }
2397
+ if (isMechanicalDecision(args.noteDecision)) {
2398
+ state.noteDecision = MECHANICAL_DECISION;
2399
+ state.notePaths = [];
2400
+ state.noteVerified = true;
2401
+ } else if (args.noteDecision === void 0 && isMechanicalDecision(state.noteDecision)) {
2402
+ } else {
2403
+ if (Array.isArray(args.notePaths)) {
2404
+ if (!isNoteDecision(decision)) {
2405
+ return fail({ code: "note-decision-required", reason: "implement \u5199 notePaths \u9700\u8981\u5408\u6CD5 noteDecision\u3002" });
2406
+ }
2407
+ const nextNotePaths = normalizeNotePaths(args.notePaths);
2408
+ const noteError = validateNotePaths(gate.root, nextNotePaths, decision);
2409
+ if (noteError !== void 0) return fail(noteError);
2410
+ state.notePaths = nextNotePaths;
2411
+ }
2412
+ if (isNoteDecision(args.noteDecision) && !isMechanicalDecision(args.noteDecision)) state.noteDecision = args.noteDecision;
2381
2413
  }
2382
- if (isNoteDecision(args.noteDecision) && !isMechanicalDecision(args.noteDecision)) state.noteDecision = args.noteDecision;
2414
+ state.revision = null;
2415
+ state.node = "code-review";
2383
2416
  }
2384
- state.node = "code-review";
2385
- } else if (args.node === "implement-revise") state.node = "code-review";
2386
- else if (args.node === "code-review") {
2417
+ } else if (args.node === "code-review") {
2387
2418
  state.rounds.codeReview += 1;
2388
- if (findings.length === 0) state.node = "verify";
2389
- else if (state.rounds.codeReview >= reviewLimit) {
2419
+ if (findings.length === 0) {
2420
+ state.node = "verify";
2421
+ state.revision = null;
2422
+ } else if (state.rounds.codeReview >= reviewLimit) {
2390
2423
  state.exhausted.code = true;
2391
2424
  state.blockedFrom = { phase: "discuss", node: null };
2392
2425
  state.phase = "blocked";
2393
2426
  state.node = null;
2394
2427
  state.work = "blocked";
2395
2428
  state.blockReason = "code-review-rounds-exhausted";
2396
- } else state.node = "implement-revise";
2429
+ } else {
2430
+ state.revision = { from: "code-review", findings, round: state.rounds.codeReview };
2431
+ state.node = "implement";
2432
+ }
2397
2433
  } else if (args.node === "verify" || args.node === "verify-standalone") {
2398
2434
  const verification = args.verification;
2399
2435
  const commands = Array.isArray(verification?.commands) ? verification.commands.filter((item) => typeof item === "string" && item.trim() !== "") : [];
@@ -2430,14 +2466,17 @@ function registerRecord(ctx, deps) {
2430
2466
  };
2431
2467
  if (args.node === "verify-standalone") {
2432
2468
  state.phase = "discuss";
2469
+ state.revision = null;
2433
2470
  state.node = null;
2434
2471
  state.work = "active";
2435
2472
  state.blockReason = null;
2436
2473
  state.blockedFrom = null;
2437
2474
  } else if (verification.passed !== true) {
2438
- state.node = "implement-revise";
2475
+ state.revision = { from: "verify", findings: [], round: state.rounds.codeReview };
2476
+ state.node = "implement";
2439
2477
  state.noteVerified = false;
2440
2478
  } else if (isMechanicalDecision(state.noteDecision)) {
2479
+ state.revision = null;
2441
2480
  state.noteVerified = true;
2442
2481
  state.noteFinalized = true;
2443
2482
  commitHint = "\u5EFA\u8BAE\u63D0\u4EA4\u5B9E\u73B0";
@@ -2449,6 +2488,7 @@ function registerRecord(ctx, deps) {
2449
2488
  state.task = null;
2450
2489
  state.planReady = false;
2451
2490
  } else {
2491
+ state.revision = null;
2452
2492
  state.phase = "orchestrating";
2453
2493
  state.node = "note-lifecycle";
2454
2494
  state.work = "active";
@@ -2456,18 +2496,11 @@ function registerRecord(ctx, deps) {
2456
2496
  state.noteFinalized = false;
2457
2497
  state.noteFinalizeRecovery = [];
2458
2498
  }
2459
- } else if (args.node === "fix-bug") {
2460
- state.phase = "discuss";
2461
- state.node = null;
2462
- state.work = "active";
2463
- state.blockReason = null;
2464
- state.blockedFrom = null;
2465
- state.task = null;
2466
- state.planReady = false;
2467
2499
  } else if (args.node === "note-lifecycle") {
2468
2500
  if (state.noteVerified !== true) {
2469
2501
  return fail({ code: "note-lifecycle-incomplete", reason: "note-lifecycle \u9700\u8981\u5148 gate_note_finalize + gate_note_verify\u3002" });
2470
2502
  }
2503
+ state.revision = null;
2471
2504
  commitHint = "\u5EFA\u8BAE\u63D0\u4EA4\u672C\u6B21\u5B9E\u73B0\u4E0E Note";
2472
2505
  state.phase = "discuss";
2473
2506
  state.node = null;
@@ -2552,8 +2585,8 @@ function registerNoteTools(ctx, deps) {
2552
2585
  async execute(args, exec) {
2553
2586
  const gate = resolveGate(ctx, exec.agent);
2554
2587
  const effective = effectiveState(ctx, exec.agent, gate, store);
2555
- if (!effective.worker || !["plan", "plan-revise"].includes(effective.state.node ?? "")) {
2556
- return { ok: false, code: "planning-only", reason: "gate_note_write \u53EA\u5141\u8BB8 planning worker \u5728 plan/plan-revise \u8282\u70B9\u4F7F\u7528\u3002" };
2588
+ if (!effective.worker || effective.state.node !== "plan") {
2589
+ return { ok: false, code: "planning-only", reason: "gate_note_write \u53EA\u5141\u8BB8 planning worker \u5728 plan \u8282\u70B9\u4F7F\u7528\u3002" };
2557
2590
  }
2558
2591
  let relative = String(args.path ?? "").replaceAll("\\", "/").replace(/^\.?\//u, "");
2559
2592
  if (relative === "" || relative.includes("..") || path12.isAbsolute(relative) || !relative.endsWith(".md")) {
@@ -2912,7 +2945,6 @@ export {
2912
2945
  Config,
2913
2946
  DISCUSS_ORCHESTRATION,
2914
2947
  DOCS_ORCHESTRATION,
2915
- FIX_BUG_ORCHESTRATION,
2916
2948
  GATE_RECORD_NODES,
2917
2949
  IMPLEMENT_ORCHESTRATION,
2918
2950
  NODE_METHODS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-gate-agent",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
5
  "description": "Phase/node workflow gate with built-in commands, tools, and skills.",
6
6
  "exports": {
@@ -1,143 +0,0 @@
1
- ---
2
- name: gate-diagnosing-bugs
3
- description: Diagnosis loop for hard bugs and performance regressions. Use when the user says "diagnose"/"debug this", or reports something broken/throwing/failing/slow.
4
- user-invocable: false
5
- ---
6
-
7
- # Diagnosing Bugs
8
-
9
- A discipline for hard bugs. Skip phases only when explicitly justified.
10
-
11
- When exploring the codebase, use the domain glossary and applicable contracts, designs and decisions identified by project instructions and the work item to form testable hypotheses. Report required-input gaps or conflicts and their effect on the diagnosis; keep dependent expectations unverified.
12
-
13
- ## Redact
14
-
15
- This skill has you show commands, outputs and captured artifacts. **Redact every secret first**: write `<REDACTED>` in its place. Build loops against env vars, so the credential stays in the environment rather than in what you show. Captured artifacts carry auth headers: quote only the lines that carry the signal.
16
-
17
- If the redacted output is not enough to diagnose the bug, say so and ask the user.
18
-
19
- ## Phase 1: Build a feedback loop
20
-
21
- **This is the skill.** Everything else is mechanical. If you have a **tight** pass/fail signal for the bug (one that goes red on _this_ bug), you will find the cause; bisection, hypothesis-testing, and instrumentation all just consume it. If you don't have one, no amount of staring at code will save you.
22
-
23
- Spend disproportionate effort here. **Be aggressive. Be creative. Refuse to give up.**
24
-
25
- ### Ways to construct one, in roughly this order
26
-
27
- 1. **Failing test** at whatever seam reaches the bug: unit, integration, e2e.
28
- 2. **Curl / HTTP script** against a running dev server.
29
- 3. **CLI invocation** with a fixture input, diffing stdout against a known-good snapshot.
30
- 4. **Headless browser script** (Playwright / Puppeteer) that drives the UI and asserts on DOM/console/network.
31
- 5. **Replay a captured trace.** Save a real network request / payload / event log to disk; replay it through the code path in isolation.
32
- 6. **Throwaway harness.** Spin up a minimal subset of the system (one service, mocked deps) that exercises the bug code path with a single function call.
33
- 7. **Property / fuzz loop.** If the bug is "sometimes wrong output", run 1000 random inputs and look for the failure mode.
34
- 8. **Bisection harness.** If the bug appeared between two known states (commit, dataset, version), automate "boot at state X, check, repeat" so you can `git bisect run` it.
35
- 9. **Differential loop.** Run the same input through old-version vs new-version (or two configs) and diff outputs.
36
- 10. **HITL bash script.** Last resort. If a human must click, drive _them_ with `scripts/hitl-loop.template.sh` so the loop is still structured. Captured output feeds back to you.
37
-
38
- Build the right feedback loop, and the bug is 90% fixed.
39
-
40
- ### Tighten the loop
41
-
42
- Treat the loop as a product. Once you have _a_ loop, **tighten** it:
43
-
44
- - Can I make it faster? (Cache setup, skip unrelated init, narrow the test scope.)
45
- - Can I make the signal sharper? (Assert on the specific symptom, not "didn't crash".)
46
- - Can I make it more deterministic? (Pin time, seed RNG, isolate filesystem, freeze network.)
47
-
48
- A 30-second flaky loop is barely better than no loop; a 2-second deterministic one is tight, a debugging superpower.
49
-
50
- ### Non-deterministic bugs
51
-
52
- The goal is not a clean repro but a **higher reproduction rate**. Loop the trigger 100×, parallelise, add stress, narrow timing windows, inject sleeps. A 50%-flake bug is debuggable; 1% is not, so keep raising the rate until it's debuggable.
53
-
54
- ### When you genuinely cannot build a loop
55
-
56
- List attempts and evidence gaps. Continue useful read-only analysis of code, logs and contracts, labeling hypotheses as unverified. Ask for missing access or redacted artifacts only when needed; production instrumentation requires explicit authorization. Do not claim a confirmed cause or verified fix without sufficient evidence.
57
-
58
- ### Completion criterion: a tight loop that goes red
59
-
60
- Phase 1 is done when the loop is **tight** and **red-capable**: you can name **one command** (a script path, a test invocation, a curl) that you have **already run at least once** (show the invocation and its output, redacted), and that is:
61
-
62
- - [ ] **Red-capable**: it drives the actual bug code path and asserts the **user's exact symptom**, so it can go red on this bug and green once fixed. Not "runs without erroring"; it must be able to _catch this specific bug_.
63
- - [ ] **Deterministic**: same verdict every run (flaky bugs: a pinned, high reproduction rate, per above).
64
- - [ ] **Fast**: seconds, not minutes.
65
- - [ ] **Agent-runnable**: you can run it unattended; a human in the loop only via `scripts/hitl-loop.template.sh`.
66
-
67
- Reading code, logs and contracts before a runnable reproduction is allowed to form testable hypotheses and construct the loop. Until exercised, these remain hypotheses. If the environment prevents reproduction, continue available read-only diagnosis and report the limitation without declaring reproduction complete.
68
-
69
- ## Phase 2: Reproduce + minimise
70
-
71
- Run the loop. Watch it go red as the bug appears.
72
-
73
- Confirm:
74
-
75
- - [ ] The loop produces the failure mode the **user** described, not a different failure that happens to be nearby. Wrong bug = wrong fix.
76
- - [ ] The failure is reproducible across multiple runs (or, for non-deterministic bugs, reproducible at a high enough rate to debug against).
77
- - [ ] You have captured the exact symptom (error message, wrong output, slow timing) so later phases can verify the fix actually addresses it.
78
-
79
- ### Minimise
80
-
81
- Once it's red, shrink the repro to the **smallest scenario that still goes red**. Cut inputs, callers, config, data, and steps **one at a time**, re-running the loop after each cut, and keep only what's load-bearing for the failure.
82
-
83
- Why bother: a minimal repro shrinks the hypothesis space in Phase 3 (fewer moving parts left to suspect) and becomes the clean regression test in Phase 5.
84
-
85
- Done when **every remaining element is load-bearing**: removing any one of them makes the loop go green.
86
-
87
- Do not proceed until you have reproduced **and** minimised.
88
-
89
- ## Phase 3: Hypothesise
90
-
91
- Generate **3–5 ranked hypotheses** before testing any of them. Single-hypothesis generation anchors on the first plausible idea.
92
-
93
- Each hypothesis must be **falsifiable**: state the prediction it makes.
94
-
95
- > Format: "If <X> is the cause, then <changing Y> will make the bug disappear / <changing Z> will make it worse."
96
-
97
- If you cannot state the prediction, the hypothesis is a vibe: discard or sharpen it.
98
-
99
- **Show the ranked list to the user before testing.** They often have domain knowledge that re-ranks instantly ("we just deployed a change to #3"), or know hypotheses they've already ruled out. Cheap checkpoint, big time saver. Don't block on it; proceed with your ranking if the user is AFK.
100
-
101
- ## Phase 4: Instrument
102
-
103
- Each probe must map to a specific prediction from Phase 3. **Change one variable at a time.**
104
-
105
- Tool preference:
106
-
107
- 1. **Debugger / REPL inspection** if the env supports it. One breakpoint beats ten logs.
108
- 2. **Targeted logs** at the boundaries that distinguish hypotheses.
109
- 3. Never "log everything and grep".
110
-
111
- **Tag every debug log** with a unique prefix, e.g. `[DEBUG-a4f2]`. Cleanup at the end becomes a single grep. Untagged logs survive; tagged logs die.
112
-
113
- **Perf branch.** For performance regressions, logs are usually wrong. Instead: establish a baseline measurement (timing harness, `performance.now()`, profiler, query plan), then bisect. Measure first, fix second.
114
-
115
- ## Phase 5: Fix + regression test
116
-
117
- Write the regression test **before the fix**, but only if there is a **correct seam** for it.
118
-
119
- A correct seam is one where the test exercises the **real bug pattern** as it occurs at the call site. If the only available seam is too shallow (single-caller test when the bug needs multiple callers, unit test that can't replicate the chain that triggered the bug), a regression test there gives false confidence.
120
-
121
- **If no correct seam exists, that itself is the finding.** Note it. The codebase architecture is preventing the bug from being locked down. Flag this for the next phase.
122
-
123
- If a correct seam exists:
124
-
125
- 1. Turn the minimised repro into a failing test at that seam.
126
- 2. Watch it fail.
127
- 3. Apply the fix.
128
- 4. Watch it pass.
129
- 5. Re-run the Phase 1 feedback loop against the original (un-minimised) scenario.
130
-
131
- ## Phase 6: Cleanup
132
-
133
- Required before declaring done:
134
-
135
- - [ ] Original repro no longer reproduces (re-run the Phase 1 loop)
136
- - [ ] Regression test passes (or absence of seam is documented)
137
- - [ ] All `[DEBUG-...]` instrumentation removed (`grep` the prefix)
138
- - [ ] Throwaway prototypes deleted (or moved to a clearly-marked debug location)
139
- - [ ] The hypothesis that turned out correct is stated in the commit / PR message, so the next debugger learns
140
-
141
-
142
-
143
-
@@ -1,44 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Human-in-the-loop reproduction loop.
3
- # Copy this file, edit the steps below, and run it.
4
- # The agent runs the script; the user follows prompts in their terminal.
5
- #
6
- # Usage:
7
- # bash hitl-loop.template.sh
8
- #
9
- # Two helpers:
10
- # step "<instruction>" → show instruction, wait for Enter
11
- # capture VAR "<question>" → show question, read response into VAR
12
- #
13
- # At the end, captured values are printed as KEY=VALUE for the agent to parse.
14
- #
15
- # `capture` prints its value back to the terminal, where the agent reads it,
16
- # so capture observations, and leave signing in to the user as a `step`.
17
-
18
- set -euo pipefail
19
-
20
- step() {
21
- printf '\n>>> %s\n' "$1"
22
- read -r -p " [Enter when done] " _
23
- }
24
-
25
- capture() {
26
- local var="$1" question="$2" answer
27
- printf '\n>>> %s\n' "$question"
28
- read -r -p " > " answer
29
- printf -v "$var" '%s' "$answer"
30
- }
31
-
32
- # --- edit below ---------------------------------------------------------
33
-
34
- step "Open the app at http://localhost:3000 and sign in."
35
-
36
- capture ERRORED "Click the 'Export' button. Did it throw an error? (y/n)"
37
-
38
- capture ERROR_MSG "Paste the error message (or 'none'):"
39
-
40
- # --- edit above ---------------------------------------------------------
41
-
42
- printf '\n--- Captured ---\n'
43
- printf 'ERRORED=%s\n' "$ERRORED"
44
- printf 'ERROR_MSG=%s\n' "$ERROR_MSG"
@@ -1,99 +0,0 @@
1
- ---
2
- name: gate-fix-bug
3
- description: "Fix a user-requested post-delivery implementation defect against its authoritative contract, using available diagnosis, focused correction, review, and regression verification."
4
- user-invocable: false
5
- ---
6
-
7
- # Fix Bug
8
-
9
- Fix a post-delivery **Implementation Bug** that the user has explicitly asked to correct.
10
-
11
- This skill changes code. It does not redesign product behavior or architecture.
12
-
13
- ## Gate worker assets
14
-
15
- 主 agent 使用本技能的 `assets/worker-briefs/gate-fix-bug.md` 派 fix worker;独立 review 使用 `assets/worker-briefs/fix-bug-review.md`。
16
-
17
- ## Preconditions
18
-
19
- Before fixing, establish:
20
-
21
- - observed failure
22
- - expected behavior
23
- - authoritative contract establishing the expected behavior
24
- - available diagnosis and supporting evidence
25
- - enough evidence to treat this as an implementation defect
26
-
27
- Reuse an existing acceptance report or diagnosis when available, identifying the selected failure items and checking that its evidence still applies to the current delivery. A diagnosis explains the cause; it does not replace the contract. A prior report is not required for a direct user bug report.
28
-
29
- The user requests the correction; determine its technical classification from evidence rather than requiring the user to confirm the root cause. When the cause is uncertain, investigate using `gate-diagnosing-bugs` before changing code. If evidence identifies a test, contract, design, or environment problem instead, report its ownership and required next action rather than treating it as an implementation bug.
30
-
31
- Establish the selected repair scope and execution authorization under the project's workflow rules. Reuse authorization throughout in-scope correction, review, and re-verification.
32
-
33
- Inspect the applicable product contract, design and decisions identified by project configuration and the work item, together with code and tests. Report missing or conflicting required inputs and the affected behavior before choosing its expected result. A defect spanning layers is not itself a reason to stop. Pause affected work only if fixing it requires an unresolved change to product behavior, an approved contract, acceptance, compatibility, migration strategy or authorized scope; surface that decision and continue independent authorized work. Do not guess a new contract in code.
34
-
35
- ## Process
36
-
37
- 1. Reproduce the reported failure.
38
- 2. Identify the smallest stable seam that captures the real bug.
39
- 3. Add or confirm regression coverage when practical; it should fail before the fix.
40
- 4. Locate the root implementation cause.
41
- 5. Apply the smallest coherent correction.
42
- 6. If unexpected technical failures arise during the fix, use `gate-diagnosing-bugs`.
43
- 7. Re-run the regression check and original reproduction.
44
- 8. Run directly related tests, then broader relevant tests when necessary.
45
- 9. Run typechecking/build checks where applicable.
46
- 10. The main agent uses `gate-code-review` to dispatch an independent review worker with the repair baseline, selected failures, contract references, and the complete repair diff, including new files.
47
- 11. Resolve material in-scope review findings by ownership. Return unresolved contract decisions to Discuss and obtain the required planning or implementation authorization under project gates; keep unrelated findings outside the repair scope.
48
- 12. Re-verify behavior affected by review corrections, including the original reproduction, affected acceptance criteria, and relevant regressions. Continue the correction and review loop until the completion conditions hold or further progress requires an unavailable dependency, a user-owned decision, or additional authorization.
49
-
50
- Verify the original observable failure at an appropriate stable boundary. A passing lower-level regression test alone does not demonstrate that the original acceptance condition is restored. Complete this repair's verification within this skill; a separate user invocation of `gate-user-verify` is not a completion prerequisite.
51
-
52
- ## Scope Rules
53
-
54
- Do not use a bug fix to introduce unrelated:
55
-
56
- - refactoring
57
- - architecture changes
58
- - API redesign
59
- - dependencies
60
- - optimization
61
- - cleanup
62
- - product behavior
63
-
64
- Small refactoring is allowed only when required to implement the correct fix safely.
65
-
66
- Do not weaken or delete a valid test merely to make the suite pass.
67
-
68
- ## Completion
69
-
70
- A fix is complete when:
71
-
72
- - the original problem no longer reproduces
73
- - expected behavior is restored
74
- - the selected failed acceptance criteria have evidence of passing on the repaired delivery
75
- - regression coverage passes when practical
76
- - relevant tests/build checks pass
77
- - no established contract was silently changed
78
- - material in-scope review findings are resolved and affected behavior has been re-verified
79
- - no blocker to this repair's completion remains
80
-
81
- ## Report
82
-
83
- Lead with whether the selected repair is complete and verified or remains incomplete. Report:
84
-
85
- - selected failure items and their latest results
86
- - root implementation cause
87
- - correction made
88
- - regression coverage
89
- - original reproduction and acceptance re-verification evidence
90
- - review outcome and relevant regression results
91
- - remaining failures, blockers, verification gaps, and required next actions, if any
92
-
93
- Limit the conclusion to the selected repair. Unselected failures or blockers in the original acceptance report remain outside this completion claim. If the original behavior cannot be reliably verified, report the repair as incomplete rather than inferring success from code changes or passing checks alone.
94
-
95
-
96
-
97
-
98
-
99
-
@@ -1,23 +0,0 @@
1
- # gate-fix-bug independent review worker
2
-
3
- ```markdown
4
- 你是 Gate 的独立 review worker。只评审 fix worker 的修复 diff,返回 findings,不修复。
5
-
6
- ## 修复基线
7
- <fix 前 commit / 固定点、当前 diff 范围>
8
-
9
- ## 选定失败与合同
10
- <原失败项、期望行为、验收/合同引用>
11
-
12
- ## 修复报告
13
- <fix worker 的根因、改动、回归测试和验证结果>
14
-
15
- ## 评审范围
16
- Standards / Spec 两轴;重点确认修复没有改变合同、没有扩大范围、没有削弱测试。
17
-
18
- ## 输出
19
- 返回 standards、spec 两组 findings,注明证据与严重度;不修改代码,不提交。
20
- ```
21
-
22
-
23
-
@@ -1,33 +0,0 @@
1
- # /gate-fix-bug — fix worker
2
-
3
- ```markdown
4
- 你是 Gate 的 fix-bug worker。使用 gate-fix-bug 完成这次已授权的实现缺陷修复;执行 Process 1-9,返回修复 receipt。独立 review 由主 agent 另派,不要自行完成 Step 10-12。
5
-
6
- ## 选定失败
7
- <现象、复现步骤、最新结果>
8
-
9
- ## 期望行为与合同
10
- <需求/验收/设计决定引用>
11
-
12
- ## 证据/诊断
13
- <日志、失败测试、已有报告>
14
-
15
- ## 修复范围
16
- <只修什么;明确不修什么>
17
-
18
- ## 基线
19
- <commit、diff、相关文件>
20
-
21
- ## 约束
22
- - 只修选定缺陷;不重构、不改产品行为、不加依赖、不做无关清理。
23
- - 先复现;回归测试应先失败,修复后通过。
24
- - 不通过削弱/删除有效测试让套件变绿。
25
- - 若发现是测试/合同/设计/环境问题,停止并报告属主。
26
- - 只执行 Process 1-9;不自行 review,不提交。
27
-
28
- ## 验证
29
- <复现命令、相关测试、类型检查/构建>
30
- ```
31
-
32
-
33
-