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 +25 -29
- package/lib/index.js +168 -136
- package/package.json +1 -1
- package/skills/gate-diagnosing-bugs/SKILL.md +0 -143
- package/skills/gate-diagnosing-bugs/scripts/hitl-loop.template.sh +0 -44
- package/skills/gate-fix-bug/SKILL.md +0 -99
- package/skills/gate-fix-bug/assets/worker-briefs/fix-bug-review.md +0 -23
- package/skills/gate-fix-bug/assets/worker-briefs/gate-fix-bug.md +0 -33
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` |
|
|
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/
|
|
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
|
|
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 [具体工作事项或上下文语义]` | 可选 |
|
|
113
|
-
| `/gate-enter-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
|
|
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
|
|
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
|
|
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`、`
|
|
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\
|
|
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\
|
|
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
|
|
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", "
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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\
|
|
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
|
|
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", "
|
|
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
|
-
|
|
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
|
|
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"
|
|
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"
|
|
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" :
|
|
1156
|
-
node === "plan"
|
|
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 &&
|
|
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\
|
|
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 (
|
|
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
|
|
2335
|
+
return fail({ code: "note-decision-required", reason: "node=plan \u9700\u8981 noteDecision\uFF08new/update/in-place/mechanical\uFF09\u3002" });
|
|
2331
2336
|
}
|
|
2332
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 \
|
|
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
|
-
|
|
2414
|
+
state.revision = null;
|
|
2415
|
+
state.node = "code-review";
|
|
2383
2416
|
}
|
|
2384
|
-
|
|
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)
|
|
2389
|
-
|
|
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
|
|
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.
|
|
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 ||
|
|
2556
|
-
return { ok: false, code: "planning-only", reason: "gate_note_write \u53EA\u5141\u8BB8 planning worker \u5728 plan
|
|
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,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
|
-
|