@kylecheng3146/agent-ops 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -14
- package/dist/packages/cli/src/args.js +34 -11
- package/dist/packages/cli/src/bin.js +21 -9
- package/dist/packages/cli/src/cli.js +15 -13
- package/dist/packages/cli/src/commands/review.js +123 -32
- package/dist/runtime/src/adapters/claude/output.js +11 -1
- package/dist/runtime/src/hooks/completion-gate.js +40 -4
- package/dist/runtime/src/hooks/shell.js +290 -42
- package/dist/runtime/src/install/doctor.js +17 -7
- package/dist/runtime/src/install/harness.js +1 -1
- package/dist/runtime/src/review/attestation.js +180 -5
- package/dist/runtime/src/review/execute.js +183 -113
- package/dist/runtime/src/review/host-sandbox.js +3 -2
- package/dist/runtime/src/review/probe.js +3 -0
- package/dist/runtime/src/review/render.js +21 -6
- package/dist/runtime/src/review/roles.js +29 -20
- package/dist/runtime/src/review/runner.js +46 -31
- package/dist/runtime/src/task/completion.js +1 -1
- package/dist/runtime/src/task/service.js +8 -2
- package/dist/runtime/src/task/store.js +16 -7
- package/docs/en/guides/configuration.md +29 -27
- package/docs/en/spec/review.md +55 -28
- package/docs/zh-TW/guides/configuration.md +26 -24
- package/docs/zh-TW/spec/review.md +50 -22
- package/package.json +1 -1
|
@@ -40,7 +40,7 @@ export async function checkTaskCompletionEvidence(stored, options) {
|
|
|
40
40
|
}
|
|
41
41
|
const attestation = await findReviewAttestation(root, sourceFingerprint);
|
|
42
42
|
if (attestation === null || attestation.taskId !== stored.task.id) {
|
|
43
|
-
return { status: "FAIL", code: "REVIEW_REQUIRED", remedy:
|
|
43
|
+
return { status: "FAIL", code: "REVIEW_REQUIRED", remedy: `Run agent-ops review --task ${stored.task.id} --yes for the whole task and current source.` };
|
|
44
44
|
}
|
|
45
45
|
return null;
|
|
46
46
|
}
|
|
@@ -124,7 +124,8 @@ export class TaskService {
|
|
|
124
124
|
completedAt: null,
|
|
125
125
|
archivedAt: null,
|
|
126
126
|
failureFingerprint: null,
|
|
127
|
-
policyConfigHash: input.policyConfigHash ?? null
|
|
127
|
+
policyConfigHash: input.policyConfigHash ?? null,
|
|
128
|
+
completionBase: null
|
|
128
129
|
};
|
|
129
130
|
state.tasks.push(record);
|
|
130
131
|
if (input.sessionId !== undefined) {
|
|
@@ -235,10 +236,14 @@ export class TaskService {
|
|
|
235
236
|
}
|
|
236
237
|
}
|
|
237
238
|
}
|
|
239
|
+
let completionBase = null;
|
|
238
240
|
const fingerprint = async () => {
|
|
239
241
|
try {
|
|
240
242
|
const scope = await resolveReviewScope({ root: completion.root, runner: completion.gitRunner,
|
|
241
243
|
...(completion.base === undefined ? {} : { base: completion.base }) });
|
|
244
|
+
// Recorded so the completion gate can recompute this exact range once
|
|
245
|
+
// the work is committed and the worktree has nothing left to measure.
|
|
246
|
+
completionBase = scope.mode === "base" ? scope.resolvedBase : null;
|
|
242
247
|
return await calculateSourceFingerprint(completion.root, scope, completion.gitRunner);
|
|
243
248
|
}
|
|
244
249
|
catch (error) {
|
|
@@ -282,7 +287,8 @@ export class TaskService {
|
|
|
282
287
|
status: "complete",
|
|
283
288
|
evidence,
|
|
284
289
|
updatedAt: now,
|
|
285
|
-
completedAt: now
|
|
290
|
+
completedAt: now,
|
|
291
|
+
completionBase
|
|
286
292
|
};
|
|
287
293
|
replaceTask(state, completed);
|
|
288
294
|
return cloneRecord(completed);
|
|
@@ -64,12 +64,13 @@ function parseTaskRecord(value) {
|
|
|
64
64
|
"task",
|
|
65
65
|
"updatedAt"
|
|
66
66
|
];
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
// Every record written before an optional field existed must still parse, so
|
|
68
|
+
// the accepted shapes are every combination of them.
|
|
69
|
+
const optionalKeys = ["completionBase", "failureFingerprint", "policyConfigHash"];
|
|
70
|
+
const allowedKeys = new Set(Array.from({ length: 1 << optionalKeys.length }, (_unused, mask) => [
|
|
71
|
+
...baseKeys,
|
|
72
|
+
...optionalKeys.filter((_key, position) => (mask & (1 << position)) !== 0)
|
|
73
|
+
].sort().join("\0")));
|
|
73
74
|
if (!isRecord(value) || !allowedKeys.has(Object.keys(value).sort().join("\0"))) {
|
|
74
75
|
return invalidState("Task state contains an invalid task record.");
|
|
75
76
|
}
|
|
@@ -138,6 +139,13 @@ function parseTaskRecord(value) {
|
|
|
138
139
|
(typeof policyConfigHash !== "string" || !/^[a-f0-9]{64}$/u.test(policyConfigHash))) {
|
|
139
140
|
return invalidState("Task state contains an invalid policy config hash.");
|
|
140
141
|
}
|
|
142
|
+
const completionBase = value.completionBase === undefined
|
|
143
|
+
? null
|
|
144
|
+
: value.completionBase;
|
|
145
|
+
if (completionBase !== null &&
|
|
146
|
+
(typeof completionBase !== "string" || !/^[a-f0-9]{40,64}$/u.test(completionBase))) {
|
|
147
|
+
return invalidState("Task state contains an invalid completion base.");
|
|
148
|
+
}
|
|
141
149
|
return {
|
|
142
150
|
task: task.value,
|
|
143
151
|
status,
|
|
@@ -147,7 +155,8 @@ function parseTaskRecord(value) {
|
|
|
147
155
|
completedAt: value.completedAt,
|
|
148
156
|
archivedAt: value.archivedAt,
|
|
149
157
|
failureFingerprint,
|
|
150
|
-
policyConfigHash
|
|
158
|
+
policyConfigHash,
|
|
159
|
+
completionBase
|
|
151
160
|
};
|
|
152
161
|
}
|
|
153
162
|
function parseSession(value) {
|
|
@@ -49,17 +49,19 @@ Enable it during `agent-ops init`, or by hand:
|
|
|
49
49
|
}
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
`targets` is an
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
`targets` is an ordered selection for the complete command
|
|
53
|
+
`agent-ops review --task <id> --yes`. Every task criterion and its original
|
|
54
|
+
description is reviewed against the staged/unstaged/untracked surface (or a
|
|
55
|
+
clean `--base <ref>...HEAD` range). Current PASS evidence for required checks
|
|
56
|
+
is required before a reviewer starts. Bare and partial reviews are not a
|
|
57
|
+
complete task review and do not satisfy completion.
|
|
57
58
|
|
|
58
59
|
`--review-target` belongs to `init` and configures that persistent chain.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
`review` does not accept target, criterion, or evidence overrides. Exactly two
|
|
61
|
+
fresh sessions are planned: three configured targets require
|
|
62
|
+
`AGENT_OPS_HOST=agy|claude|codex`, exclude that host, and prefer `agy` first;
|
|
63
|
+
two targets run in configured order; one target runs twice. Review JSON includes
|
|
64
|
+
`plannedTargets` in that actual order.
|
|
63
65
|
|
|
64
66
|
Every attempt starts from a fresh session and disposable repository clone with
|
|
65
67
|
native read-only mode.
|
|
@@ -74,9 +76,11 @@ repository even if sandboxed plan mode writes to its cwd:
|
|
|
74
76
|
| `agy` | `agy --print <prompt>` | `--sandbox --mode plan` |
|
|
75
77
|
| `claude` | `claude -p` | `--permission-mode plan --safe-mode` |
|
|
76
78
|
|
|
77
|
-
The
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
The first session is the necessary review. A first PASS starts the second
|
|
80
|
+
adversarial session with the first full redacted report as untrusted data. A
|
|
81
|
+
first FAIL or NOT_RUN stops; a second FAIL is final FAIL, and a missing second
|
|
82
|
+
verdict is NOT_RUN. A same-target pair is still independent because both
|
|
83
|
+
sessions and clones are fresh; a development session is never resumed.
|
|
80
84
|
|
|
81
85
|
`opencode` is **not** a review target even though it is a supported harness.
|
|
82
86
|
Its `--agent plan` is rejected as a subagent and silently falls back to a
|
|
@@ -88,11 +92,11 @@ would consume the following flag instead. It deliberately does not pass
|
|
|
88
92
|
`--dangerously-skip-permissions`, which overrides the permission boundary, or
|
|
89
93
|
`--disable-slash-commands`, which disables plan-mode behavior.
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
95
|
+
Host network or loopback restrictions return `REVIEW_NOT_RUN` before any
|
|
96
|
+
reviewer is started. A trusted outer host runner may rerun the exact same
|
|
97
|
+
command once with both capabilities; an in-sandbox retry is not an elevation
|
|
98
|
+
and cannot produce a PASS. Every attempt, preflight result, and diagnostic is
|
|
99
|
+
preserved in human and JSON output.
|
|
96
100
|
|
|
97
101
|
Capability checks and model starts are reported on stderr, including under
|
|
98
102
|
`--json`; stdout remains one final JSON envelope and raw reviewer output is
|
|
@@ -100,16 +104,14 @@ never streamed. SIGINT or SIGTERM terminates the active reviewer process tree,
|
|
|
100
104
|
does not advance the fallback chain, and never writes an attestation. An
|
|
101
105
|
exhausted timeout chain reports `timeout`, not `missing-cli`.
|
|
102
106
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
Compact PASS evidence is appended with a `review:<target>:` prefix; the full
|
|
112
|
-
human-readable report is transient. Completed tasks are never rewritten.
|
|
107
|
+
The task ID is explicit and its criteria are always used; no session fallback
|
|
108
|
+
or criterion filter can replace the original task requirements. Review rechecks
|
|
109
|
+
the source fingerprint before the adversarial session and again before writing
|
|
110
|
+
evidence. After a complete PASS, the full redacted reports are stored privately
|
|
111
|
+
under `.agent-ops/reviews/`; the attestation stores only metadata and report
|
|
112
|
+
digests. Any evidence write failure remains `REVIEW_NOT_RUN`. Compact PASS
|
|
113
|
+
evidence is appended with a `review:<target>:` prefix, and completed tasks are
|
|
114
|
+
never rewritten.
|
|
113
115
|
|
|
114
116
|
`--yes` is still required for every review run: init selection decides which
|
|
115
117
|
targets are permitted, `--yes` decides whether to spend money now.
|
package/docs/en/spec/review.md
CHANGED
|
@@ -22,20 +22,19 @@ A review result MUST preserve PASS, FAIL, or NOT_RUN and MUST NOT convert NOT_RU
|
|
|
22
22
|
|
|
23
23
|
## REVIEW-HARNESS-001
|
|
24
24
|
|
|
25
|
-
A review
|
|
26
|
-
|
|
25
|
+
A complete review MUST use the configured independent-review target selection;
|
|
26
|
+
the review command MUST NOT accept a per-run harness override.
|
|
27
27
|
|
|
28
|
-
- Trigger: Running `review
|
|
29
|
-
- Action:
|
|
30
|
-
- Evidence: Argument parsing rejects
|
|
31
|
-
- Positive: `review --
|
|
32
|
-
- Negative: `
|
|
28
|
+
- Trigger: Running `review`.
|
|
29
|
+
- Action: Resolve the configured targets and plan exactly two fresh sessions.
|
|
30
|
+
- Evidence: Argument parsing rejects `--harness`, while `init --review-target` remains the configuration entry point.
|
|
31
|
+
- Positive: `review --task <id> --yes` reports its configured `plannedTargets`.
|
|
32
|
+
- Negative: `review --task <id> --yes --harness claude` changes the reviewer set.
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
`plannedTargets`.
|
|
34
|
+
With three configured targets, `AGENT_OPS_HOST` MUST identify the current host;
|
|
35
|
+
that target is excluded and `agy` is primary when available. With two targets,
|
|
36
|
+
both run in configured order even if one is the host. With one target, it runs
|
|
37
|
+
twice in fresh sessions.
|
|
39
38
|
|
|
40
39
|
## REVIEW-READONLY-001
|
|
41
40
|
|
|
@@ -49,10 +48,9 @@ without one MUST be skipped rather than run unsandboxed.
|
|
|
49
48
|
- Negative: `Trust the prompt to stop the reviewer from editing files.`
|
|
50
49
|
|
|
51
50
|
Every attempted review MUST run in a fresh session (`sessionIsolation:
|
|
52
|
-
"fresh"`) and in a disposable repository clone.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
self-review`. A resumed development session is never an independent review.
|
|
51
|
+
"fresh"`) and in a disposable repository clone. A same-target pair remains
|
|
52
|
+
independent because the sessions and clones are fresh. A resumed development
|
|
53
|
+
session is never an independent review.
|
|
56
54
|
|
|
57
55
|
Capability and model-start progress goes to stderr even when stdout is JSON.
|
|
58
56
|
Raw reviewer output remains bounded and unstreamed. SIGINT or SIGTERM aborts
|
|
@@ -61,22 +59,22 @@ distinct NOT_RUN reason rather than being flattened to `missing-cli`.
|
|
|
61
59
|
|
|
62
60
|
## REVIEW-CHAIN-001
|
|
63
61
|
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
The two planned sessions MUST be ordered as a necessary review followed by an
|
|
63
|
+
adversarial re-check. The first session MUST stop the run on FAIL or NOT_RUN;
|
|
64
|
+
there is no fallback after that result.
|
|
66
65
|
|
|
67
|
-
- Trigger:
|
|
68
|
-
- Action:
|
|
69
|
-
- Evidence:
|
|
70
|
-
- Positive: `
|
|
71
|
-
- Negative: `
|
|
66
|
+
- Trigger: The first target is missing, unauthenticated, unavailable, or returns a malformed report.
|
|
67
|
+
- Action: Return NOT_RUN with the first attempt and do not start the second session.
|
|
68
|
+
- Evidence: `attempts` contains the first diagnostic and has no second attempt.
|
|
69
|
+
- Positive: `primary NOT_RUN` is final NOT_RUN.
|
|
70
|
+
- Negative: `Run the second target after the necessary review did not run.`
|
|
72
71
|
|
|
73
72
|
## REVIEW-ADVERSARIAL-001
|
|
74
73
|
|
|
75
|
-
A PASS MUST be offered to
|
|
74
|
+
A PASS MUST be offered to the second planned target for refutation, and a
|
|
76
75
|
successful refutation MUST make the run FAIL.
|
|
77
76
|
|
|
78
|
-
- Trigger: The primary target returns PASS
|
|
79
|
-
already been walked past. The host target never serves as the challenger.
|
|
77
|
+
- Trigger: The primary target returns PASS.
|
|
80
78
|
- Action: Send that target the prior report as untrusted data and ask it to
|
|
81
79
|
refute the verdict; report FAIL when it does, and record the challenge as
|
|
82
80
|
`adversarial` either way.
|
|
@@ -84,8 +82,37 @@ successful refutation MUST make the run FAIL.
|
|
|
84
82
|
a challenger that produced no report appears on the attempt list instead.
|
|
85
83
|
- Positive: `codex passed, claude found a blocking defect, the run failed.`
|
|
86
84
|
- Negative: `Manufacture a refutation so the challenge looks effective.`
|
|
87
|
-
- Note: With one
|
|
88
|
-
is already terminal and is never re-checked.
|
|
85
|
+
- Note: With one configured target the same target is invoked again in a fresh
|
|
86
|
+
session. A FAIL is already terminal and is never re-checked.
|
|
87
|
+
|
|
88
|
+
## REVIEW-HOST-001
|
|
89
|
+
|
|
90
|
+
A host that cannot provide network and loopback capability MUST fail closed
|
|
91
|
+
before any reviewer invocation.
|
|
92
|
+
|
|
93
|
+
- Trigger: The host declares disabled network or the loopback probe fails.
|
|
94
|
+
- Action: Return `REVIEW_NOT_RUN / host-required` with the host restriction.
|
|
95
|
+
- Evidence: `attempts` is empty and no target preflight or reviewer process ran.
|
|
96
|
+
- Positive: A trusted outer host runner can retry the exact command once with both capabilities.
|
|
97
|
+
- Negative: Treat a child login error as proof that an authenticated reviewer is unavailable.
|
|
98
|
+
|
|
99
|
+
There is no repository-level permission bypass. An unavailable outer host runner
|
|
100
|
+
MUST leave the result NOT_RUN rather than manufacture PASS.
|
|
101
|
+
|
|
102
|
+
## REVIEW-EVIDENCE-001
|
|
103
|
+
|
|
104
|
+
A complete PASS MUST include the primary report, the adversarial report, two PASS
|
|
105
|
+
attempts with fresh session IDs, a stable source fingerprint, and a private
|
|
106
|
+
bounded report artifact before its attestation is written. Artifact or
|
|
107
|
+
attestation write failure MUST return NOT_RUN.
|
|
108
|
+
|
|
109
|
+
- Trigger: A reviewer chain reaches a PASS verdict.
|
|
110
|
+
- Action: Validate both reports, both fresh attempts, the source fingerprint,
|
|
111
|
+
and the private bounded artifact before writing the attestation.
|
|
112
|
+
- Evidence: The attestation and artifact agree on task, host, targets, session
|
|
113
|
+
IDs, report digests, and source fingerprint.
|
|
114
|
+
- Positive: A complete pair writes the artifact and matching PASS attestation.
|
|
115
|
+
- Negative: A partial PASS or failed evidence write becomes NOT_RUN.
|
|
89
116
|
|
|
90
117
|
## REVIEW-CONTRACT-001
|
|
91
118
|
|
|
@@ -44,15 +44,17 @@ Claude 與 Codex lifecycle support 為 `supported`,OpenCode 從 app initializa
|
|
|
44
44
|
}
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
`targets`
|
|
48
|
-
|
|
49
|
-
`--
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
target
|
|
55
|
-
|
|
47
|
+
`targets` 是完整指令 `agent-ops review --task <id> --yes` 的有序選擇。
|
|
48
|
+
每一條 task criterion 與原始 description 都會針對 staged/unstaged/untracked
|
|
49
|
+
變更(或乾淨的 `--base <ref>...HEAD`)審查;必要驗證的最新 PASS evidence
|
|
50
|
+
必須在 reviewer 啟動前存在。裸跑或 partial review 不算完整 task review,也
|
|
51
|
+
不能滿足 completion。
|
|
52
|
+
|
|
53
|
+
`--review-target` 只屬於 `init`,用來設定持久 reviewer selection。`review` 不接受
|
|
54
|
+
target、criterion 或 evidence override。每次恰好規劃兩個全新 session:設定三個
|
|
55
|
+
target 時必須提供 `AGENT_OPS_HOST=agy|claude|codex`,排除該 host 並優先選 agy;
|
|
56
|
+
設定兩個時依設定順序執行;設定一個時同一 CLI 執行兩次。review JSON 的
|
|
57
|
+
`plannedTargets` 會列出實際順序。
|
|
56
58
|
|
|
57
59
|
每次嘗試都從全新 session、一次性 repository clone 與原生唯讀模式啟動。Claude 使用完整 safe-mode
|
|
58
60
|
隔離;Codex 與 Agy 為了支援既有 OAuth 登入而保留登入環境,因此 context
|
|
@@ -65,9 +67,11 @@ target;它不會臨時啟用未設定的 reviewer。既有 model、effort 與
|
|
|
65
67
|
| `agy` | `agy --print <prompt>` | `--sandbox --mode plan` |
|
|
66
68
|
| `claude` | `claude -p` | `--permission-mode plan --safe-mode` |
|
|
67
69
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
第一個 session 是必要 reviewer。只有第一個 PASS 才會啟動第二個 adversarial
|
|
71
|
+
session,並將第一份完整 redacted report 以不可信資料傳入。第一個 FAIL 或
|
|
72
|
+
NOT_RUN 立即停止;第二個 FAIL 是終局 FAIL,第二個無法取得 verdict 則為
|
|
73
|
+
NOT_RUN。同 target pair 仍因 session 與 clone 全新而具獨立性;不得 resume 開發
|
|
74
|
+
session。
|
|
71
75
|
|
|
72
76
|
`opencode` **不是** review 目標,即使它是支援的 harness。它的 `--agent plan`
|
|
73
77
|
會被判定為 subagent 而遭拒,並靜默退回可寫入的 agent,因此無法滿足唯讀前置
|
|
@@ -77,24 +81,22 @@ Agy 的 prompt 會直接作為 `--print` 的值;裸用 `-p` 會誤吞下一個
|
|
|
77
81
|
agent-ops 刻意不傳會繞過權限邊界的 `--dangerously-skip-permissions`,也不傳會
|
|
78
82
|
使 plan mode 失效的 `--disable-slash-commands`。
|
|
79
83
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
+
Host 缺少 network 或 loopback 權限時,會在啟動任何 reviewer 前回傳
|
|
85
|
+
`REVIEW_NOT_RUN`。可信任的外部 host runner 可以用兩項權限重跑同一個完整
|
|
86
|
+
指令一次;在原 sandbox 內重試不算升權,也不能產生 PASS。文字與 JSON 輸出
|
|
87
|
+
都會保留每次 attempt、preflight 與 diagnostic。
|
|
84
88
|
|
|
85
89
|
Capability check 與模型啟動進度都寫到 stderr,包括 `--json` 模式;stdout
|
|
86
90
|
仍只有最終 JSON envelope,且不會串流 reviewer 原始輸出。SIGINT 或 SIGTERM
|
|
87
91
|
會終止目前 reviewer 的完整 process tree、不進入 fallback,也不寫入
|
|
88
92
|
attestation。整條 chain 逾時時回報 `timeout`,不會誤報 `missing-cli`。
|
|
89
93
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
`
|
|
96
|
-
僅 compact PASS evidence 會以 `review:<target>:` 附加;完整人類可讀 report 是暫存的。
|
|
97
|
-
已完成的 task 絕不改寫。
|
|
94
|
+
task ID 必須明確指定,且永遠使用該 task 的原始 criteria;不能用 session fallback
|
|
95
|
+
或 criterion filter 取代需求。review 會在 adversarial session 前、以及寫入證據前
|
|
96
|
+
重新確認 source fingerprint。完整 PASS 後,兩份完整 redacted report 會私密保存於
|
|
97
|
+
`.agent-ops/reviews/`;attestation 只保存 metadata 與 report digest。任何 evidence
|
|
98
|
+
寫入失敗都維持 `REVIEW_NOT_RUN`。Compact PASS evidence 仍以
|
|
99
|
+
`review:<target>:` 附加,已完成的 task 絕不改寫。
|
|
98
100
|
|
|
99
101
|
每次執行 review 仍需 `--yes`:init 的勾選決定「允許哪些目標」,
|
|
100
102
|
`--yes` 決定「現在是否要花錢」。
|
|
@@ -24,18 +24,18 @@ English source version: 2026-07-23. Revalidate: when the English specification c
|
|
|
24
24
|
|
|
25
25
|
## REVIEW-HARNESS-001
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
完整 review MUST 使用 configured independent-review target selection;review
|
|
28
|
+
指令 MUST NOT 接受單次 harness override。
|
|
28
29
|
|
|
29
|
-
- Trigger:
|
|
30
|
-
- Action:
|
|
31
|
-
- Evidence: argument parsing
|
|
32
|
-
- Positive: `review --
|
|
33
|
-
- Negative:
|
|
30
|
+
- Trigger: 執行 `review`。
|
|
31
|
+
- Action: 解析設定的 targets,規劃恰好兩個全新 session。
|
|
32
|
+
- Evidence: argument parsing 拒絕 `--harness`;`init --review-target` 仍是設定入口。
|
|
33
|
+
- Positive: `review --task <id> --yes` 回報設定的 `plannedTargets`。
|
|
34
|
+
- Negative: `review --task <id> --yes --harness claude` 改變 reviewer 集合。
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
結果都以 `plannedTargets` 保存這個實際順序。
|
|
36
|
+
設定三個 target 時,`AGENT_OPS_HOST` MUST 指出目前 host;該 target 會被排除,
|
|
37
|
+
若可用則 agy 為 primary。設定兩個時依順序執行,即使其中一個是 host;設定一個
|
|
38
|
+
時,在全新 session 執行兩次。
|
|
39
39
|
|
|
40
40
|
## REVIEW-READONLY-001
|
|
41
41
|
|
|
@@ -48,9 +48,8 @@ review target MUST 以其自身的唯讀機制啟動;沒有唯讀機制的 tar
|
|
|
48
48
|
- Negative: `信任 prompt 能阻止審查者修改檔案。`
|
|
49
49
|
|
|
50
50
|
每次 review 都 MUST 使用全新 session(`sessionIsolation: "fresh"`)並在
|
|
51
|
-
disposable repository clone
|
|
52
|
-
|
|
53
|
-
標示 `DEGRADED: isolated self-review`。不得 resume 開發 session 作為獨立審查。
|
|
51
|
+
disposable repository clone 中執行。同 target pair 仍因 session 與 clone 全新而
|
|
52
|
+
具獨立性。不得 resume 開發 session 作為獨立審查。
|
|
54
53
|
|
|
55
54
|
Capability 與模型啟動進度即使在 JSON 模式也寫到 stderr;reviewer 原始輸出仍
|
|
56
55
|
維持 bounded capture,不直接串流。SIGINT 或 SIGTERM 會中止 active process
|
|
@@ -59,24 +58,53 @@ tree,不 fallback、不寫 attestation;timeout 保留獨立 NOT_RUN reason
|
|
|
59
58
|
|
|
60
59
|
## REVIEW-CHAIN-001
|
|
61
60
|
|
|
62
|
-
|
|
61
|
+
兩個規劃的 session MUST 依序為必要 reviewer 與 adversarial 複審。第一個
|
|
62
|
+
session 遇到 FAIL 或 NOT_RUN MUST 立即停止;不會在該結果後 fallback。
|
|
63
63
|
|
|
64
|
-
- Trigger:
|
|
65
|
-
- Action:
|
|
66
|
-
- Evidence:
|
|
67
|
-
- Positive: `
|
|
68
|
-
- Negative:
|
|
64
|
+
- Trigger: 第一個 target 不存在、未登入、不可用或回傳 malformed report。
|
|
65
|
+
- Action: 回傳含第一個 attempt 診斷的 NOT_RUN,不啟動第二個 session。
|
|
66
|
+
- Evidence: `attempts` 有第一個 diagnostic 且沒有第二個 attempt。
|
|
67
|
+
- Positive: `primary NOT_RUN` 是終局 NOT_RUN。
|
|
68
|
+
- Negative: `必要 reviewer 沒跑成後仍啟動第二個 target`。
|
|
69
69
|
|
|
70
70
|
## REVIEW-ADVERSARIAL-001
|
|
71
71
|
|
|
72
|
-
PASS MUST
|
|
72
|
+
PASS MUST 交給第二個規劃的 target 嘗試反駁,且反駁成立時 MUST 使整體判定為 FAIL。
|
|
73
73
|
|
|
74
|
-
- Trigger: primary target 回報 PASS
|
|
74
|
+
- Trigger: primary target 回報 PASS。
|
|
75
75
|
- Action: 將前一份 report 以不可信資料交給該 target 並要求它反駁;反駁成立即回報 FAIL,且無論結果都記錄為 `adversarial`。
|
|
76
76
|
- Evidence: `adversarial` 記載挑戰者與是否反駁成立;未能產出 report 的挑戰者則記錄在 attempt 清單。
|
|
77
77
|
- Positive: `codex 判 PASS,claude 找到 blocking 缺陷,整體判定 FAIL。`
|
|
78
78
|
- Negative: `為了讓複查看起來有效而編造反駁。`
|
|
79
|
-
- Note:
|
|
79
|
+
- Note: 只有一個設定 target 時,會在全新 session 再呼叫同一 target。FAIL 已是終局,不再複查。
|
|
80
|
+
|
|
81
|
+
## REVIEW-HOST-001
|
|
82
|
+
|
|
83
|
+
Host 缺少 network 或 loopback 能力時,MUST 在任何 reviewer invocation 前
|
|
84
|
+
fail closed。
|
|
85
|
+
|
|
86
|
+
- Trigger: host 宣告 network disabled 或 loopback probe 失敗。
|
|
87
|
+
- Action: 回傳 `REVIEW_NOT_RUN / host-required` 與 host restriction。
|
|
88
|
+
- Evidence: `attempts` 為空,沒有 target preflight 或 reviewer process 執行。
|
|
89
|
+
- Positive: 可信任的外部 host runner 可在具兩項能力的主機重跑同一指令一次。
|
|
90
|
+
- Negative: 把 child login error 當作 authenticated reviewer 不可用的證明。
|
|
91
|
+
|
|
92
|
+
repository 不提供 permission bypass。外部 host runner 不可用時,結果 MUST 保持
|
|
93
|
+
NOT_RUN,不得製造 PASS。
|
|
94
|
+
|
|
95
|
+
## REVIEW-EVIDENCE-001
|
|
96
|
+
|
|
97
|
+
完整 PASS MUST 在寫入 attestation 前具備 primary report、adversarial report、
|
|
98
|
+
兩個帶 fresh session ID 的 PASS attempt、穩定 source fingerprint,以及私密且
|
|
99
|
+
有大小上限的 report artifact。artifact 或 attestation 寫入失敗 MUST 回傳 NOT_RUN。
|
|
100
|
+
|
|
101
|
+
- Trigger: reviewer chain 得到 PASS verdict。
|
|
102
|
+
- Action: 寫入 attestation 前驗證兩份 report、兩個 fresh attempt、source
|
|
103
|
+
fingerprint 與私密且有大小上限的 artifact。
|
|
104
|
+
- Evidence: attestation 與 artifact 的 task、host、targets、session IDs、report
|
|
105
|
+
digests 及 source fingerprint 完全一致。
|
|
106
|
+
- Positive: 完整 pair 寫入 artifact 與相符的 PASS attestation。
|
|
107
|
+
- Negative: 不完整 PASS 或 evidence 寫入失敗會降為 NOT_RUN。
|
|
80
108
|
|
|
81
109
|
## REVIEW-CONTRACT-001
|
|
82
110
|
|