@fitlab-ai/agent-infra 0.7.4 → 0.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.ts +13 -11
- package/dist/bin/cli.js +13 -11
- package/dist/lib/init.js +1 -1
- package/dist/lib/merge.js +1 -1
- package/dist/lib/sandbox/index.js +21 -21
- package/dist/lib/task/index.js +13 -13
- package/dist/lib/update.js +1 -1
- package/lib/init.ts +1 -1
- package/lib/merge.ts +1 -1
- package/lib/sandbox/index.ts +21 -21
- package/lib/task/index.ts +13 -13
- package/lib/update.ts +1 -1
- package/package.json +1 -1
- package/templates/.agents/rules/README.en.md +7 -3
- package/templates/.agents/rules/README.zh-CN.md +7 -3
- package/templates/.agents/rules/cli-help-format.en.md +49 -0
- package/templates/.agents/rules/cli-help-format.zh-CN.md +49 -0
- package/templates/.agents/rules/no-mid-flow-questions.en.md +14 -2
- package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +14 -2
- package/templates/.agents/rules/pr-sync.github.en.md +8 -6
- package/templates/.agents/rules/pr-sync.github.zh-CN.md +8 -6
- package/templates/.agents/rules/review-handshake.en.md +83 -0
- package/templates/.agents/rules/review-handshake.zh-CN.md +83 -0
- package/templates/.agents/scripts/lib/post-review-commit.js +56 -0
- package/templates/.agents/scripts/lib/review-artifacts.js +117 -0
- package/templates/.agents/scripts/review-diff-fingerprint.js +99 -0
- package/templates/.agents/scripts/validate-artifact.js +240 -0
- package/templates/.agents/skills/analyze-task/SKILL.en.md +52 -6
- package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +52 -6
- package/templates/.agents/skills/code-task/config/verify.en.json +3 -0
- package/templates/.agents/skills/code-task/config/verify.zh-CN.json +3 -0
- package/templates/.agents/skills/code-task/reference/fix-mode.en.md +5 -3
- package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +5 -3
- package/templates/.agents/skills/code-task/reference/report-template.en.md +4 -4
- package/templates/.agents/skills/code-task/reference/report-template.zh-CN.md +4 -4
- package/templates/.agents/skills/code-task/scripts/detect-mode.js +2 -107
- package/templates/.agents/skills/commit/SKILL.en.md +6 -0
- package/templates/.agents/skills/commit/SKILL.zh-CN.md +6 -0
- package/templates/.agents/skills/commit/reference/task-status-update.en.md +8 -0
- package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +8 -0
- package/templates/.agents/skills/complete-task/SKILL.en.md +10 -0
- package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +10 -0
- package/templates/.agents/skills/complete-task/config/verify.en.json +2 -0
- package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +2 -0
- package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +1 -1
- package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +1 -1
- package/templates/.agents/skills/plan-task/SKILL.en.md +1 -1
- package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +1 -1
- package/templates/.agents/skills/plan-task/config/verify.en.json +3 -0
- package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +3 -0
- package/templates/.agents/skills/review-analysis/config/verify.en.json +2 -1
- package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +2 -1
- package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +5 -4
- package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +5 -4
- package/templates/.agents/skills/review-analysis/reference/report-template.en.md +4 -0
- package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +4 -0
- package/templates/.agents/skills/review-code/SKILL.en.md +4 -1
- package/templates/.agents/skills/review-code/SKILL.zh-CN.md +4 -1
- package/templates/.agents/skills/review-code/config/verify.en.json +5 -2
- package/templates/.agents/skills/review-code/config/verify.zh-CN.json +5 -2
- package/templates/.agents/skills/review-code/reference/output-templates.en.md +5 -4
- package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +5 -4
- package/templates/.agents/skills/review-code/reference/report-template.en.md +6 -0
- package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +6 -0
- package/templates/.agents/skills/review-plan/config/verify.en.json +2 -1
- package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +2 -1
- package/templates/.agents/skills/review-plan/reference/output-templates.en.md +5 -4
- package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +5 -4
- package/templates/.agents/skills/review-plan/reference/report-template.en.md +4 -0
- package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +4 -0
- package/templates/.agents/templates/task.en.md +7 -0
- package/templates/.agents/templates/task.zh-CN.md +7 -0
- package/templates/.github/workflows/metadata-sync.yml +1 -1
- package/templates/.github/workflows/pr-label.yml +1 -1
- package/templates/.github/workflows/status-label.yml +1 -1
|
@@ -2,6 +2,8 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import process from "node:process";
|
|
4
4
|
|
|
5
|
+
import { artifactName, maxRound, parseVerdict } from "../../../scripts/lib/review-artifacts.js";
|
|
6
|
+
|
|
5
7
|
function main() {
|
|
6
8
|
const taskDir = process.argv[2];
|
|
7
9
|
if (!taskDir) {
|
|
@@ -170,26 +172,6 @@ function main() {
|
|
|
170
172
|
}
|
|
171
173
|
}
|
|
172
174
|
|
|
173
|
-
function maxRound(entries, stem) {
|
|
174
|
-
let max = 0;
|
|
175
|
-
for (const entry of entries) {
|
|
176
|
-
if (entry === `${stem}.md`) {
|
|
177
|
-
max = Math.max(max, 1);
|
|
178
|
-
continue;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const match = entry.match(new RegExp(`^${escapeRegExp(stem)}-r(\\d+)\\.md$`));
|
|
182
|
-
if (match) {
|
|
183
|
-
max = Math.max(max, Number(match[1]));
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
return max;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function artifactName(stem, round) {
|
|
190
|
-
return round === 1 ? `${stem}.md` : `${stem}-r${round}.md`;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
175
|
function checkPlanAheadOfCode({ resolvedTaskDir, codeMax, planMax, reviewPlanMax }) {
|
|
194
176
|
if (planMax === 0 || reviewPlanMax === 0) {
|
|
195
177
|
return { replan: false };
|
|
@@ -275,96 +257,9 @@ function safeStat(filePath) {
|
|
|
275
257
|
}
|
|
276
258
|
}
|
|
277
259
|
|
|
278
|
-
function parseVerdict(reviewPath) {
|
|
279
|
-
if (!fs.existsSync(reviewPath)) {
|
|
280
|
-
return { ok: false, verdict: null, message: `Review artifact not found: ${path.basename(reviewPath)}` };
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
const content = fs.readFileSync(reviewPath, "utf8");
|
|
284
|
-
const summary = extractSection(content, ["审查摘要", "Review Summary"]);
|
|
285
|
-
const fileName = path.basename(reviewPath);
|
|
286
|
-
if (!summary) {
|
|
287
|
-
return { ok: false, verdict: null, message: `cannot locate review summary section in ${fileName}` };
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
const verdictMatch = summary.match(/^[-*]?\s*\*\*(?:总体结论|Overall Verdict)\*\*[::]\s*(.+?)\s*$/im);
|
|
291
|
-
if (!verdictMatch) {
|
|
292
|
-
return { ok: false, verdict: null, message: `cannot parse verdict in ${fileName}` };
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
const verdict = normalizeVerdict(verdictMatch[1]);
|
|
296
|
-
if (!verdict) {
|
|
297
|
-
return {
|
|
298
|
-
ok: false,
|
|
299
|
-
verdict: null,
|
|
300
|
-
message: `unrecognized verdict '${verdictMatch[1].trim()}' in ${fileName}`
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
if (verdict !== "Approved") {
|
|
305
|
-
return { ok: true, verdict };
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
const findingsMatch = summary.match(/^[-*]?\s*\*\*(?:发现(AI 可处理)|Findings \(AI-actionable\))\*\*[::]\s*(.+?)\s*$/im);
|
|
309
|
-
if (!findingsMatch) {
|
|
310
|
-
return { ok: false, verdict, message: `cannot parse findings count in ${fileName}` };
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
const counts = findingsMatch[1].match(/(\d+)\s*(?:阻塞项|blockers?).*?(\d+)\s*(?:主要|majors?).*?(\d+)\s*(?:次要|minors?)/i);
|
|
314
|
-
if (!counts) {
|
|
315
|
-
return { ok: false, verdict, message: `cannot parse findings count in ${fileName}` };
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
const [, blockers, majors, minors] = counts.map(Number);
|
|
319
|
-
return {
|
|
320
|
-
ok: true,
|
|
321
|
-
verdict: blockers === 0 && majors === 0 && minors === 0 ? "Approved" : "Approved-with-issues"
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
function normalizeVerdict(raw) {
|
|
326
|
-
const value = String(raw).trim().toLowerCase();
|
|
327
|
-
if (value === "通过" || value === "approved") {
|
|
328
|
-
return "Approved";
|
|
329
|
-
}
|
|
330
|
-
if (value === "需要修改" || value === "changes requested") {
|
|
331
|
-
return "Changes Requested";
|
|
332
|
-
}
|
|
333
|
-
if (value === "拒绝" || value === "rejected") {
|
|
334
|
-
return "Rejected";
|
|
335
|
-
}
|
|
336
|
-
return "";
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
function extractSection(content, names) {
|
|
340
|
-
const lines = content.split(/\r?\n/);
|
|
341
|
-
const nameSet = new Set(names);
|
|
342
|
-
const start = lines.findIndex((line) => {
|
|
343
|
-
const match = line.trim().match(/^##\s+(.+?)\s*$/);
|
|
344
|
-
return match ? nameSet.has(match[1]) : false;
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
if (start === -1) {
|
|
348
|
-
return "";
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
const sectionLines = [];
|
|
352
|
-
for (let index = start + 1; index < lines.length; index += 1) {
|
|
353
|
-
if (/^##\s+/.test(lines[index])) {
|
|
354
|
-
break;
|
|
355
|
-
}
|
|
356
|
-
sectionLines.push(lines[index]);
|
|
357
|
-
}
|
|
358
|
-
return sectionLines.join("\n");
|
|
359
|
-
}
|
|
360
|
-
|
|
361
260
|
function writeResult(result, code) {
|
|
362
261
|
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
363
262
|
process.exitCode = code;
|
|
364
263
|
}
|
|
365
264
|
|
|
366
|
-
function escapeRegExp(value) {
|
|
367
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
368
|
-
}
|
|
369
|
-
|
|
370
265
|
main();
|
|
@@ -48,6 +48,12 @@ Review status, diff, and recent history, then prepare a Conventional Commit with
|
|
|
48
48
|
|
|
49
49
|
Stage specific files only and run `git commit` with the prepared message.
|
|
50
50
|
|
|
51
|
+
If this commit is associated with a task and a `review-code` artifact exists, read the highest-round `review-code` artifact before committing:
|
|
52
|
+
- If that artifact's `Overall Verdict` / `总体结论` is Approved, parse `Review Baseline Commit` / `审查基线提交` as `R`, and `Reviewed Diff Fingerprint` / `审查差异指纹` as `F`
|
|
53
|
+
- After staging the explicit files, run `node .agents/scripts/review-diff-fingerprint.js staged <R>` to get `S`, and record `pre_head=$(git rev-parse HEAD)`
|
|
54
|
+
- After committing, write `last_reviewed_commit: <new_head>` to task.md frontmatter only when `pre_head == R` and `S == F`; otherwise do not advance that field
|
|
55
|
+
- Do not scan backward to earlier Approved artifacts; the highest-round `review-code` artifact is the only authoritative source
|
|
56
|
+
|
|
51
57
|
## 5. Update Task Status When Applicable
|
|
52
58
|
|
|
53
59
|
Get the current time:
|
|
@@ -48,6 +48,12 @@ git diff
|
|
|
48
48
|
|
|
49
49
|
只暂存明确列出的文件,然后执行 `git commit`。
|
|
50
50
|
|
|
51
|
+
如果本次提交关联任务且存在 `review-code` 产物,在提交前读取最高轮 `review-code` 产物:
|
|
52
|
+
- 若该产物 `总体结论` / `Overall Verdict` 为 Approved,解析 `审查基线提交` / `Review Baseline Commit` 为 `R`,解析 `审查差异指纹` / `Reviewed Diff Fingerprint` 为 `F`
|
|
53
|
+
- 暂存明确文件后运行 `node .agents/scripts/review-diff-fingerprint.js staged <R>` 得到 `S`,并记录 `pre_head=$(git rev-parse HEAD)`
|
|
54
|
+
- 提交后仅当 `pre_head == R` 且 `S == F` 时,在 task.md frontmatter 写入 `last_reviewed_commit: <new_head>`;否则不推进该字段
|
|
55
|
+
- 不向后扫描更早的 Approved 产物;最高轮 `review-code` 产物是唯一权威来源
|
|
56
|
+
|
|
51
57
|
## 5. 按需更新任务状态
|
|
52
58
|
|
|
53
59
|
获取当前时间:
|
|
@@ -18,6 +18,14 @@ For every task-related commit, append this Activity Log entry in `task.md`:
|
|
|
18
18
|
- {YYYY-MM-DD HH:mm:ss±HH:MM} — **Commit** by {agent} — {commit hash short} {commit subject}
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
If the commit stage confirmed that the highest-round `review-code` artifact is Approved, `pre_head` equals its review baseline commit `R`, and the staged diff fingerprint `S` equals its reviewed diff fingerprint `F`, also write or refresh:
|
|
22
|
+
|
|
23
|
+
```yaml
|
|
24
|
+
last_reviewed_commit: {new_head}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This field is the preferred baseline for the `complete-task` `post-review-commit` gate. When any condition is not met, do not write or advance it.
|
|
28
|
+
|
|
21
29
|
Before selecting the next step, verify:
|
|
22
30
|
- `current_step` and the latest workflow progress in `task.md`
|
|
23
31
|
- whether the latest `review-code.md` / `review-code-r{N}.md` passed without findings
|
|
@@ -18,6 +18,14 @@ date "+%Y-%m-%d %H:%M:%S%:z"
|
|
|
18
18
|
- {YYYY-MM-DD HH:mm:ss±HH:MM} — **Commit** by {agent} — {commit hash short} {commit subject}
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
如果提交阶段已确认最高轮 `review-code` 产物 Approved、`pre_head` 等于其审查基线提交 `R`、且 staged 差异指纹 `S` 等于其审查差异指纹 `F`,同时写入或刷新:
|
|
22
|
+
|
|
23
|
+
```yaml
|
|
24
|
+
last_reviewed_commit: {new_head}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
该字段是 `complete-task` 的 `post-review-commit` gate 优先 baseline。条件不满足时不要写入或推进该字段。
|
|
28
|
+
|
|
21
29
|
在决定下一步之前,先确认:
|
|
22
30
|
- `task.md` 中的 `current_step` 和最新工作流进度
|
|
23
31
|
- 最新的 `review-code.md` / `review-code-r{N}.md` 是否无问题通过
|
|
@@ -77,6 +77,16 @@ Before marking complete, verify ALL of these:
|
|
|
77
77
|
- [ ] Code has been reviewed (`review-code.md` or `review-code-r{N}.md` exists, and the latest review verdict is Approved; or review was done externally)
|
|
78
78
|
- [ ] Code has been committed (no uncommitted changes related to this task)
|
|
79
79
|
- [ ] Tests are passing
|
|
80
|
+
- [ ] The disagreement ledger has no unclosed disagreements and there are no un-re-reviewed post-review commits (mechanically checked by the "Pre-completion hard gate" below)
|
|
81
|
+
|
|
82
|
+
**Pre-completion hard gate (run BEFORE moving the directory or releasing the short id)**: the Step 7 `gate complete-task` runs only after the directory has been `mv`-ed to `completed/` and the short id released; to avoid a gate failure occurring after those irreversible operations, run the two new completion gates on the **active directory** first:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
node .agents/scripts/validate-artifact.js check review-ledger .agents/workspace/active/{task-id} --skill complete-task --format text
|
|
86
|
+
node .agents/scripts/validate-artifact.js check post-review-commit .agents/workspace/active/{task-id} --skill complete-task --format text
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
A non-zero exit from either (fail/blocked) -> treat as an unmet prerequisite and **stop**, do not run Steps 3-7. `--force` does **NOT** lift this hard gate: unclosed disagreements must first be closed in the ledger (`confirmed`/`closed`/`human-decided`), and un-re-reviewed post-review commits must be re-reviewed via `review-code` or covered by a `post-review-commit` / `human-decided` exemption row in the ledger.
|
|
80
90
|
|
|
81
91
|
> **⚠️ Prerequisite Branch Check — you must decide whether to continue or stop before proceeding:**
|
|
82
92
|
>
|
|
@@ -76,6 +76,16 @@ tail .agents/workspace/active/{task-id}/task.md
|
|
|
76
76
|
- [ ] 代码已审查(`review-code.md` 或 `review-code-r{N}.md` 存在,且最新审查结论为 Approved;或已在外部完成审查)
|
|
77
77
|
- [ ] 代码已提交(没有与此任务相关的未提交变更)
|
|
78
78
|
- [ ] 测试通过
|
|
79
|
+
- [ ] 审查分歧账本无未关闭分歧,且无未复审的 post-review 提交(由下方「预完成硬门禁」机械校验)
|
|
80
|
+
|
|
81
|
+
**预完成硬门禁(在移动目录、释放短号之前运行)**:步骤 7 的 `gate complete-task` 在目录已 `mv` 到 `completed/`、短号已释放之后才运行;为避免门禁失败发生在不可逆操作之后,必须在 **active 目录**上预先运行新增的两项完成门禁:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
node .agents/scripts/validate-artifact.js check review-ledger .agents/workspace/active/{task-id} --skill complete-task --format text
|
|
85
|
+
node .agents/scripts/validate-artifact.js check post-review-commit .agents/workspace/active/{task-id} --skill complete-task --format text
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
任一退出码非 0(fail/blocked)→ 按前置条件未满足处理,**停止**,不执行步骤 3-7。`--force` **不解除**本硬门禁:未关闭分歧必须先在账本闭合(`confirmed`/`closed`/`human-decided`),未复审 post-review 提交必须重新 `review-code` 或在账本追加 `post-review-commit` / `human-decided` 豁免行。
|
|
79
89
|
|
|
80
90
|
> **⚠️ 前置条件分支判断 — 你必须先判断“继续”还是“停止”:**
|
|
81
91
|
>
|
|
@@ -9,7 +9,7 @@ Read this file before creating or updating the single reviewer-facing PR summary
|
|
|
9
9
|
- Generate or update the `<!-- sync-pr:{task-id}:summary -->` comment with the canonical template from `.agents/rules/pr-sync.md`
|
|
10
10
|
- When a matching summary comment already exists, PATCH only when the body changed; otherwise skip the write
|
|
11
11
|
- In this skill, summary sync failures follow the existing `create-pr` error handling and must not roll back an already-created PR
|
|
12
|
-
- Populate
|
|
12
|
+
- Populate `{manual-verify-section}` per the aggregation rules in `.agents/rules/pr-sync.md`: include only post-code-stage checks that the AI cannot close on its own and that require a human to execute or judge; sources are `review-code*` "Environment-Blocked Findings" plus `code*` items that satisfy the admission boundary; each item must state "what to verify + location + why only a human can verify it". Render in two branches: **with retained items** → `### ⚠️ Manual Verification Required` heading + item list; **with none** → `### ✅ No Manual Verification Needed` heading + a single line (no ⚠️, no old list placeholder)
|
|
13
13
|
|
|
14
14
|
## Result Reporting
|
|
15
15
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
- 按 `.agents/rules/pr-sync.md` 中的唯一权威模板生成或更新 `<!-- sync-pr:{task-id}:summary -->` 评论
|
|
10
10
|
- PR 已存在同标记评论时,只在正文变化时 PATCH;否则跳过写入
|
|
11
11
|
- 本 skill 中,摘要同步失败沿用 `create-pr` 的现有错误处理,不回滚已经创建的 PR
|
|
12
|
-
- 按 `.agents/rules/pr-sync.md`
|
|
12
|
+
- 按 `.agents/rules/pr-sync.md` 的聚合规则填充 `{manual-verify-section}`:只收进入 code 阶段后 AI 无法自行关闭、需要人实际执行或判断的校验点;来源为 `review-code*` 的「环境性遗留」以及 `code*` 中满足准入边界的校验点;每条写明「校验什么 + 定位 + 为什么只能由人校验」。按两分支渲染:**有保留项** → `### ⚠️ 需人工校验` 标题 + 条目列表;**无保留项** → `### ✅ 无需人工校验` 标题 + 单行说明(不带 ⚠️、不写旧的列表占位)
|
|
13
13
|
|
|
14
14
|
## 结果回传
|
|
15
15
|
|
|
@@ -66,7 +66,7 @@ Use it to understand:
|
|
|
66
66
|
- identified technical risks
|
|
67
67
|
- effort and complexity assessment
|
|
68
68
|
|
|
69
|
-
**Round ≥ 2: respond to the prior review (only when a review artifact exists)**: if the task directory contains `review-plan.md` / `review-plan-r{N}.md`, read the highest-round review report; add a `## Response to Prior Review` section to this round's plan artifact, and for each finding verify it via Read/Grep
|
|
69
|
+
**Round ≥ 2: respond to the prior review (only when a review artifact exists)**: if the task directory contains `review-plan.md` / `review-plan-r{N}.md`, read the highest-round review report; add a `## Response to Prior Review` section to this round's plan artifact, and for each finding verify it via Read/Grep, then dispose of it with one of the four states in `.agents/rules/review-handshake.md` (`accepted` / `adjusted` / `refuted` / `cannot-judge`) — every state needs commensurate evidence, never defaulting to compliance; write the disposition back to the matching row in the task.md disagreement ledger (stage=plan, round +1). Record any open disagreement under `## Open Questions`. Round 1 has no review, so skip this section.
|
|
70
70
|
|
|
71
71
|
### 4. Understand the Problem
|
|
72
72
|
|
|
@@ -65,7 +65,7 @@ tail .agents/workspace/active/{task-id}/task.md
|
|
|
65
65
|
- 已识别的技术风险
|
|
66
66
|
- 工作量和复杂度评估
|
|
67
67
|
|
|
68
|
-
**Round ≥ 2:响应上一轮审查(仅当存在审查产物时)**:若任务目录存在 `review-plan.md` / `review-plan-r{N}.md`,读取最高轮次的审查报告;在本轮方案产物中新增 `## 对上一轮审查的响应` 段,对每条发现先 Read/Grep
|
|
68
|
+
**Round ≥ 2:响应上一轮审查(仅当存在审查产物时)**:若任务目录存在 `review-plan.md` / `review-plan-r{N}.md`,读取最高轮次的审查报告;在本轮方案产物中新增 `## 对上一轮审查的响应` 段,对每条发现先 Read/Grep 核实,再按 `.agents/rules/review-handshake.md` 的四态(`accepted` / `adjusted` / `refuted` / `cannot-judge`)处置——每态都要附相称证据,不默认顺从;并把处置回写 task.md `## 审查分歧账本` 对应行(stage=plan,round +1)。未决分歧写入 `## 未决问题`。Round 1 无审查,跳过本段。
|
|
69
69
|
|
|
70
70
|
### 4. 理解问题
|
|
71
71
|
|
|
@@ -36,6 +36,9 @@
|
|
|
36
36
|
"expected_action_pattern": "(Plan Task|Technical Design) \\(Round \\d+\\)",
|
|
37
37
|
"freshness_minutes": 30
|
|
38
38
|
},
|
|
39
|
+
"review-ledger": {
|
|
40
|
+
"stage_scope": ["analysis"]
|
|
41
|
+
},
|
|
39
42
|
"platform-sync": {
|
|
40
43
|
"when": "issue_number_exists",
|
|
41
44
|
"expected_status_label": "status: pending-design-work",
|
|
@@ -36,6 +36,9 @@
|
|
|
36
36
|
"expected_action_pattern": "(Plan Task|Technical Design) \\(Round \\d+\\)",
|
|
37
37
|
"freshness_minutes": 30
|
|
38
38
|
},
|
|
39
|
+
"review-ledger": {
|
|
40
|
+
"stage_scope": ["analysis"]
|
|
41
|
+
},
|
|
39
42
|
"platform-sync": {
|
|
40
43
|
"when": "issue_number_exists",
|
|
41
44
|
"expected_status_label": "status: pending-design-work",
|
|
@@ -16,12 +16,13 @@ Rules:
|
|
|
16
16
|
- If `Blocker > 0`, never use an approved template
|
|
17
17
|
- Never count env-blocked items as blocker / major / minor or use them to trigger Scenario B/C/D
|
|
18
18
|
- The selected scenario must include all TUI command formats
|
|
19
|
+
- The count line always shows 4 numbers: the first three (Blockers / Major / Minor) must be 0 to proceed; the fourth, `Human-decision` (`{h}`), is the number of rows in task.md `## 审查分歧账本` with `stage=analysis` and `status=needs-human-decision` — a "pending human ruling" item that need not be zero and does not participate in scenario selection
|
|
19
20
|
|
|
20
21
|
### Scenario A: Approved with no findings
|
|
21
22
|
|
|
22
23
|
```text
|
|
23
24
|
Task {task-id} requirement analysis review completed. Verdict: approved.
|
|
24
|
-
- Blockers: 0 | Major issues: 0 | Minor issues: 0
|
|
25
|
+
- Blockers: 0 | Major issues: 0 | Minor issues: 0 | Human-decision: {h}
|
|
25
26
|
[- Review report: .agents/workspace/active/{task-id}/{review-artifact}]
|
|
26
27
|
|
|
27
28
|
Next step - write the technical plan:
|
|
@@ -37,7 +38,7 @@ Reminder: env-blocked items belong in the PR description manual verification che
|
|
|
37
38
|
|
|
38
39
|
```text
|
|
39
40
|
Task {task-id} requirement analysis review completed. Verdict: approved.
|
|
40
|
-
- Blockers: 0 | Major issues: {n} | Minor issues: {n}
|
|
41
|
+
- Blockers: 0 | Major issues: {n} | Minor issues: {n} | Human-decision: {h}
|
|
41
42
|
- Review report: .agents/workspace/active/{task-id}/{review-artifact}
|
|
42
43
|
|
|
43
44
|
Next step - revise analysis before continuing (recommended):
|
|
@@ -58,7 +59,7 @@ Reminder: env-blocked items belong in the PR description manual verification che
|
|
|
58
59
|
|
|
59
60
|
```text
|
|
60
61
|
Task {task-id} requirement analysis review completed. Verdict: changes requested.
|
|
61
|
-
- Blockers: {n} | Major issues: {n} | Minor issues: {n}
|
|
62
|
+
- Blockers: {n} | Major issues: {n} | Minor issues: {n} | Human-decision: {h}
|
|
62
63
|
- Review report: .agents/workspace/active/{task-id}/{review-artifact}
|
|
63
64
|
|
|
64
65
|
Next step - revise requirement analysis:
|
|
@@ -74,7 +75,7 @@ Reminder: env-blocked items belong in the PR description manual verification che
|
|
|
74
75
|
|
|
75
76
|
```text
|
|
76
77
|
Task {task-id} requirement analysis review completed. Verdict: rejected, fresh analysis or requirement clarification required.
|
|
77
|
-
- Blockers: {n} | Major issues: {n} | Minor issues: {n}
|
|
78
|
+
- Blockers: {n} | Major issues: {n} | Minor issues: {n} | Human-decision: {h}
|
|
78
79
|
- Review report: .agents/workspace/active/{task-id}/{review-artifact}
|
|
79
80
|
|
|
80
81
|
Next step - re-analyze:
|
|
@@ -16,12 +16,13 @@
|
|
|
16
16
|
- 只要 `Blocker > 0`,就绝对不能输出通过模板
|
|
17
17
|
- env-blocked 项绝对不能被计入 blocker / major / minor 计数,也不能用作触发场景 B/C/D 的依据
|
|
18
18
|
- 所选场景中必须包含所有 TUI 命令格式
|
|
19
|
+
- 计数行固定显示 4 个数字:前三项(阻塞 / 主要 / 次要)必须为 0 才进下一步;第四项 `人工裁决`(`{h}`)= task.md `## 审查分歧账本` 中 `stage=analysis` 且 `status=needs-human-decision` 的行数,是「待人裁」项、不要求归零,也不参与场景判断
|
|
19
20
|
|
|
20
21
|
### 场景 A:通过且无问题
|
|
21
22
|
|
|
22
23
|
```text
|
|
23
24
|
任务 {task-id} 需求分析审查完成。结论:通过。
|
|
24
|
-
- 阻塞项:0 | 主要问题:0 | 次要问题:0
|
|
25
|
+
- 阻塞项:0 | 主要问题:0 | 次要问题:0 | 人工裁决:{h}
|
|
25
26
|
[- 审查报告:.agents/workspace/active/{task-id}/{review-artifact}]
|
|
26
27
|
|
|
27
28
|
下一步 - 编写技术方案:
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
|
|
38
39
|
```text
|
|
39
40
|
任务 {task-id} 需求分析审查完成。结论:通过。
|
|
40
|
-
- 阻塞项:0 | 主要问题:{n} | 次要问题:{n}
|
|
41
|
+
- 阻塞项:0 | 主要问题:{n} | 次要问题:{n} | 人工裁决:{h}
|
|
41
42
|
- 审查报告:.agents/workspace/active/{task-id}/{review-artifact}
|
|
42
43
|
|
|
43
44
|
下一步 - 修订分析后继续(推荐):
|
|
@@ -58,7 +59,7 @@
|
|
|
58
59
|
|
|
59
60
|
```text
|
|
60
61
|
任务 {task-id} 需求分析审查完成。结论:需要修改。
|
|
61
|
-
- 阻塞项:{n} | 主要问题:{n} | 次要问题:{n}
|
|
62
|
+
- 阻塞项:{n} | 主要问题:{n} | 次要问题:{n} | 人工裁决:{h}
|
|
62
63
|
- 审查报告:.agents/workspace/active/{task-id}/{review-artifact}
|
|
63
64
|
|
|
64
65
|
下一步 - 修订需求分析:
|
|
@@ -74,7 +75,7 @@
|
|
|
74
75
|
|
|
75
76
|
```text
|
|
76
77
|
任务 {task-id} 需求分析审查完成。结论:拒绝,需要重新分析或补充需求澄清。
|
|
77
|
-
- 阻塞项:{n} | 主要问题:{n} | 次要问题:{n}
|
|
78
|
+
- 阻塞项:{n} | 主要问题:{n} | 次要问题:{n} | 人工裁决:{h}
|
|
78
79
|
- 审查报告:.agents/workspace/active/{task-id}/{review-artifact}
|
|
79
80
|
|
|
80
81
|
下一步 - 重新分析:
|
|
@@ -59,6 +59,10 @@ Use this template when writing `review-analysis.md` or `review-analysis-r{N}.md`
|
|
|
59
59
|
> If this round has no env-blocked findings, keep the section heading and write "None".
|
|
60
60
|
|
|
61
61
|
|
|
62
|
+
## Review Disagreement Ledger Writeback
|
|
63
|
+
|
|
64
|
+
> Upsert each finding this round into the task.md disagreement ledger: append an `open` row for new findings (id prefix `AN-`, stage=analysis); per the hand-back duty set the executor's prior-round responses to `confirmed` / back to `open` / `needs-human-decision`. State machine and evidence rules: `.agents/rules/review-handshake.md`.
|
|
65
|
+
|
|
62
66
|
## Evidence
|
|
63
67
|
|
|
64
68
|
> Pair each "I verified X" claim with the corresponding raw tool output; the gate only checks that this section exists and at least one `$ ` line is present. Every Blocker must be backed by a reproducible command (rg/grep/sed/nl) and its raw output; a judgment that cannot be reproduced must be downgraded or moved to Self-Doubt.
|
|
@@ -60,6 +60,10 @@
|
|
|
60
60
|
> 如本轮无 env-blocked 项,保留段落标题并写「(无)」。
|
|
61
61
|
|
|
62
62
|
|
|
63
|
+
## 审查分歧账本回写
|
|
64
|
+
|
|
65
|
+
> 把本轮每条 finding upsert 到 task.md `## 审查分歧账本`:新 finding 追加 `open` 行(id 前缀 `AN-`,stage=analysis),对执行方上一轮响应按回交义务改 `confirmed` / 置回 `open` / `needs-human-decision`。状态机与证据规则见 `.agents/rules/review-handshake.md`。
|
|
66
|
+
|
|
63
67
|
## 证据原文
|
|
64
68
|
|
|
65
69
|
> 每条“我验证了 X”断言都要配对对应 tool output 原文;gate 仅校验本段存在和至少一行 `$ `。每条 Blocker 必须配可复现命令(rg/grep/sed/nl)及其原文;无法复现的判断须降级或移入「自我质疑」。
|
|
@@ -61,7 +61,10 @@ Read the highest-round code artifact and, if present, the highest-round fix arti
|
|
|
61
61
|
|
|
62
62
|
### 4. Perform the Review
|
|
63
63
|
|
|
64
|
-
Follow `.agents/workflows/feature-development.yaml` and inspect
|
|
64
|
+
Follow `.agents/workflows/feature-development.yaml` and inspect the full change context:
|
|
65
|
+
- `git diff --binary HEAD -- <post-review-globs>` for tracked changes
|
|
66
|
+
- `git ls-files -o --exclude-standard -z -- <post-review-globs>` for untracked new files
|
|
67
|
+
- `node .agents/scripts/review-diff-fingerprint.js worktree HEAD` for the reviewed diff fingerprint; write it into the report
|
|
65
68
|
|
|
66
69
|
> Detailed review criteria, severity rules, and reviewer expectations live in `reference/review-criteria.md`. Read `reference/review-criteria.md` before reviewing.
|
|
67
70
|
> Test review gate: when `git diff` touches test files, read `.agents/rules/testing-discipline.md` first and check it item by item, especially "do not add negative assertions when a positive assertion already covers the behavior".
|
|
@@ -60,7 +60,10 @@ tail .agents/workspace/active/{task-id}/task.md
|
|
|
60
60
|
|
|
61
61
|
### 4. 执行审查
|
|
62
62
|
|
|
63
|
-
遵循 `.agents/workflows/feature-development.yaml
|
|
63
|
+
遵循 `.agents/workflows/feature-development.yaml`,并同时检查完整变更上下文:
|
|
64
|
+
- `git diff --binary HEAD -- <post-review-globs>` 覆盖已跟踪变更
|
|
65
|
+
- `git ls-files -o --exclude-standard -z -- <post-review-globs>` 覆盖未跟踪新文件
|
|
66
|
+
- `node .agents/scripts/review-diff-fingerprint.js worktree HEAD` 生成审查差异指纹,并写入报告
|
|
64
67
|
|
|
65
68
|
> 详细审查标准、严重程度划分和 reviewer 关注点见 `reference/review-criteria.md`。执行此步骤前先读取 `reference/review-criteria.md`。
|
|
66
69
|
> 测试审查硬门禁:当 `git diff` 触及测试文件时,必须先读取 `.agents/rules/testing-discipline.md` 并逐条核对(尤其"正向已覆盖时不应再加反向断言")。
|
|
@@ -24,12 +24,15 @@
|
|
|
24
24
|
"Conclusion and Recommendations",
|
|
25
25
|
"State Check",
|
|
26
26
|
"Evidence",
|
|
27
|
-
"Self-Doubt"
|
|
27
|
+
"Self-Doubt",
|
|
28
|
+
"Review Disagreement Ledger Writeback"
|
|
28
29
|
],
|
|
29
30
|
"required_patterns": [
|
|
30
31
|
"^### Approval Decision$",
|
|
31
32
|
"^\\$ ",
|
|
32
|
-
"^- \\*\\*Overall Verdict\\*\\*[::]\\s*(?:通过|需要修改|拒绝|Approved|Changes Requested|Rejected)\\s*$"
|
|
33
|
+
"^- \\*\\*Overall Verdict\\*\\*[::]\\s*(?:通过|需要修改|拒绝|Approved|Changes Requested|Rejected)\\s*$",
|
|
34
|
+
"^- \\*\\*Review Baseline Commit\\*\\*[::]\\s*\\S",
|
|
35
|
+
"^- \\*\\*Reviewed Diff Fingerprint\\*\\*[::]\\s*sha256:[0-9a-f]{64}\\s*$"
|
|
33
36
|
],
|
|
34
37
|
"freshness_minutes": 30
|
|
35
38
|
},
|
|
@@ -24,12 +24,15 @@
|
|
|
24
24
|
"结论与建议",
|
|
25
25
|
"状态核对",
|
|
26
26
|
"证据原文",
|
|
27
|
-
"自我质疑"
|
|
27
|
+
"自我质疑",
|
|
28
|
+
"审查分歧账本回写"
|
|
28
29
|
],
|
|
29
30
|
"required_patterns": [
|
|
30
31
|
"^### 审查决定$",
|
|
31
32
|
"^\\$ ",
|
|
32
|
-
"^- \\*\\*总体结论\\*\\*[::]\\s*(?:通过|需要修改|拒绝|Approved|Changes Requested|Rejected)\\s*$"
|
|
33
|
+
"^- \\*\\*总体结论\\*\\*[::]\\s*(?:通过|需要修改|拒绝|Approved|Changes Requested|Rejected)\\s*$",
|
|
34
|
+
"^- \\*\\*审查基线提交\\*\\*[::]\\s*\\S",
|
|
35
|
+
"^- \\*\\*审查差异指纹\\*\\*[::]\\s*sha256:[0-9a-f]{64}\\s*$"
|
|
33
36
|
],
|
|
34
37
|
"freshness_minutes": 30
|
|
35
38
|
},
|
|
@@ -18,12 +18,13 @@ Prohibitions:
|
|
|
18
18
|
- if `Blocker > 0`, never output an approval template
|
|
19
19
|
- never count env-blocked findings as blockers / major issues / minor issues, and never use them to trigger Branch B/C/D
|
|
20
20
|
- always include every TUI command format in the selected branch
|
|
21
|
+
- the count line always shows 5 numbers: the first three (Blockers / Major / Minor) must be 0 to proceed; the last two are "pending human" items and need not be zero — `Manual-verify` (`{e}`) = this round's env-blocked count, `Human-decision` (`{h}`) = the number of rows in task.md `## 审查分歧账本` with `stage=code` and `status=needs-human-decision`; neither participates in branch selection
|
|
21
22
|
|
|
22
23
|
### Branch A: Approved with No Findings
|
|
23
24
|
|
|
24
25
|
```text
|
|
25
26
|
Task {task-id} review completed. Verdict: approved.
|
|
26
|
-
- Blockers: 0 | Major: 0 | Minor: 0
|
|
27
|
+
- Blockers: 0 | Major: 0 | Minor: 0 | Manual-verify: {e} | Human-decision: {h}
|
|
27
28
|
[- Review report: .agents/workspace/active/{task-id}/{review-artifact}]
|
|
28
29
|
|
|
29
30
|
Next step - commit the code:
|
|
@@ -39,7 +40,7 @@ Reminder: env-blocked findings must be carried in the PR description as a "manua
|
|
|
39
40
|
|
|
40
41
|
```text
|
|
41
42
|
Task {task-id} review completed. Verdict: approved.
|
|
42
|
-
- Blockers: 0 | Major: {n} | Minor: {n}
|
|
43
|
+
- Blockers: 0 | Major: {n} | Minor: {n} | Manual-verify: {e} | Human-decision: {h}
|
|
43
44
|
- Review report: .agents/workspace/active/{task-id}/{review-artifact}
|
|
44
45
|
|
|
45
46
|
Next step - fix before commit (recommended):
|
|
@@ -60,7 +61,7 @@ Reminder: env-blocked findings must be carried in the PR description as a "manua
|
|
|
60
61
|
|
|
61
62
|
```text
|
|
62
63
|
Task {task-id} review completed. Verdict: changes requested.
|
|
63
|
-
- Blockers: {n} | Major: {n} | Minor: {n}
|
|
64
|
+
- Blockers: {n} | Major: {n} | Minor: {n} | Manual-verify: {e} | Human-decision: {h}
|
|
64
65
|
- Review report: .agents/workspace/active/{task-id}/{review-artifact}
|
|
65
66
|
|
|
66
67
|
Next step - fix the findings:
|
|
@@ -76,7 +77,7 @@ Reminder: env-blocked findings must be carried in the PR description as a "manua
|
|
|
76
77
|
|
|
77
78
|
```text
|
|
78
79
|
Task {task-id} review completed. Verdict: rejected, re-design the technical plan.
|
|
79
|
-
- Blockers: {n} | Major: {n} | Minor: {n}
|
|
80
|
+
- Blockers: {n} | Major: {n} | Minor: {n} | Manual-verify: {e} | Human-decision: {h}
|
|
80
81
|
- Review report: .agents/workspace/active/{task-id}/{review-artifact}
|
|
81
82
|
|
|
82
83
|
Next step - re-design the technical plan:
|
|
@@ -18,12 +18,13 @@
|
|
|
18
18
|
- 只要 `Blocker > 0`,就绝对不能输出通过模板
|
|
19
19
|
- env-blocked 项绝对不能被计入 blocker / major / minor 计数,也不能用作触发场景 B/C/D 的依据
|
|
20
20
|
- 所选场景中必须包含所有 TUI 命令格式
|
|
21
|
+
- 计数行固定显示 5 个数字:前三项(阻塞 / 主要 / 次要)必须为 0 才进下一步;后两项是「待人处理」项、不要求归零——`人工校验点`(`{e}`)= 本轮 env-blocked 计数,`人工裁决`(`{h}`)= task.md `## 审查分歧账本` 中 `stage=code` 且 `status=needs-human-decision` 的行数;二者均不参与场景判断
|
|
21
22
|
|
|
22
23
|
### 场景 A:通过且无问题
|
|
23
24
|
|
|
24
25
|
```text
|
|
25
26
|
任务 {task-id} 代码审查完成。结论:通过。
|
|
26
|
-
- 阻塞项:0 | 主要问题:0 | 次要问题:0
|
|
27
|
+
- 阻塞项:0 | 主要问题:0 | 次要问题:0 | 人工校验点:{e} | 人工裁决:{h}
|
|
27
28
|
[- 审查报告:.agents/workspace/active/{task-id}/{review-artifact}]
|
|
28
29
|
|
|
29
30
|
下一步 - 提交代码:
|
|
@@ -39,7 +40,7 @@
|
|
|
39
40
|
|
|
40
41
|
```text
|
|
41
42
|
任务 {task-id} 代码审查完成。结论:通过。
|
|
42
|
-
- 阻塞项:0 | 主要问题:{n} | 次要问题:{n}
|
|
43
|
+
- 阻塞项:0 | 主要问题:{n} | 次要问题:{n} | 人工校验点:{e} | 人工裁决:{h}
|
|
43
44
|
- 审查报告:.agents/workspace/active/{task-id}/{review-artifact}
|
|
44
45
|
|
|
45
46
|
下一步 - 修复问题后提交(推荐):
|
|
@@ -60,7 +61,7 @@
|
|
|
60
61
|
|
|
61
62
|
```text
|
|
62
63
|
任务 {task-id} 代码审查完成。结论:需要修改。
|
|
63
|
-
- 阻塞项:{n} | 主要问题:{n} | 次要问题:{n}
|
|
64
|
+
- 阻塞项:{n} | 主要问题:{n} | 次要问题:{n} | 人工校验点:{e} | 人工裁决:{h}
|
|
64
65
|
- 审查报告:.agents/workspace/active/{task-id}/{review-artifact}
|
|
65
66
|
|
|
66
67
|
下一步 - 修复问题:
|
|
@@ -76,7 +77,7 @@
|
|
|
76
77
|
|
|
77
78
|
```text
|
|
78
79
|
任务 {task-id} 代码审查完成。结论:拒绝,需要重新设计方案。
|
|
79
|
-
- 阻塞项:{n} | 主要问题:{n} | 次要问题:{n}
|
|
80
|
+
- 阻塞项:{n} | 主要问题:{n} | 次要问题:{n} | 人工校验点:{e} | 人工裁决:{h}
|
|
80
81
|
- 审查报告:.agents/workspace/active/{task-id}/{review-artifact}
|
|
81
82
|
|
|
82
83
|
下一步 - 重新设计技术方案:
|
|
@@ -21,6 +21,8 @@ Use this template when writing `review-code.md` or `review-code-r{N}.md`.
|
|
|
21
21
|
- **Reviewer**: {reviewer-name}
|
|
22
22
|
- **Review Time**: {timestamp}
|
|
23
23
|
- **Scope**: {file-count and major modules}
|
|
24
|
+
- **Review Baseline Commit**: {raw git rev-parse HEAD} (baseline for the complete-task post-review commit gate; see `.agents/rules/review-handshake.md`)
|
|
25
|
+
- **Reviewed Diff Fingerprint**: {raw node .agents/scripts/review-diff-fingerprint.js worktree HEAD}
|
|
24
26
|
- **Overall Verdict**: {Approved / Changes Requested / Rejected} (pick exactly one; combined phrases will fail the verify gate)
|
|
25
27
|
- **Findings (AI-actionable)**: 0 blockers, 0 majors, 0 minors / **env-blocked**: 0
|
|
26
28
|
|
|
@@ -59,6 +61,10 @@ Use this template when writing `review-code.md` or `review-code-r{N}.md`.
|
|
|
59
61
|
> If this round has no env-blocked findings, keep the section heading and write "None".
|
|
60
62
|
|
|
61
63
|
|
|
64
|
+
## Review Disagreement Ledger Writeback
|
|
65
|
+
|
|
66
|
+
> Upsert each finding this round into the task.md disagreement ledger: append an `open` row for new findings (id prefix `CD-`, stage=code); per the hand-back duty set the executor's prior-round responses to `confirmed` / back to `open` / `needs-human-decision`. State machine and evidence rules: `.agents/rules/review-handshake.md`.
|
|
67
|
+
|
|
62
68
|
## Evidence
|
|
63
69
|
|
|
64
70
|
> Pair each "I verified X" claim with the corresponding raw tool output; the gate only checks that this section exists and at least one `$ ` line is present. Every Blocker must be backed by a reproducible command (rg/grep/sed/nl) and its raw output; a judgment that cannot be reproduced must be downgraded or moved to Self-Doubt.
|