@kylecheng3146/agent-ops 0.10.2 → 0.11.0
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/dist/packages/cli/src/args.js +8 -43
- package/dist/packages/cli/src/bin.js +28 -29
- package/dist/packages/cli/src/cli.js +12 -14
- package/dist/packages/cli/src/codex-loop-process.js +0 -6
- package/dist/packages/cli/src/commands/review.js +5 -10
- package/dist/packages/cli/src/commands/run.js +3 -1
- package/dist/packages/cli/src/commands/task.js +6 -50
- package/dist/packages/cli/src/commands/verify.js +7 -3
- package/dist/packages/cli/src/default-base.js +26 -0
- package/dist/packages/cli/src/hook-process.js +19 -83
- package/dist/packages/cli/src/run-entry.js +66 -21
- package/dist/runtime/src/adapters/agy/config.js +2 -3
- package/dist/runtime/src/adapters/claude/config.js +2 -2
- package/dist/runtime/src/adapters/codex/config.js +2 -5
- package/dist/runtime/src/hooks/completion-gate.js +0 -15
- package/dist/runtime/src/install/harness.js +3 -3
- package/dist/runtime/src/install/plan.js +3 -3
- package/dist/runtime/src/install/profiles.js +0 -2
- package/dist/runtime/src/office/snapshot.js +4 -1
- package/dist/runtime/src/parallel/manage.js +0 -3
- package/dist/runtime/src/review/execute.js +68 -4
- package/dist/runtime/src/run/verification.js +2 -2
- package/dist/runtime/src/schema/validate.js +10 -5
- package/dist/runtime/src/task/completion.js +4 -42
- package/dist/runtime/src/task/contract.js +11 -0
- package/dist/runtime/src/task/service.js +34 -57
- package/dist/runtime/src/task/store.js +3 -7
- package/dist/runtime/src/verify/acceptance-coverage.js +2 -3
- package/dist/runtime/src/verify/acceptance-protocol.js +4 -3
- package/dist/runtime/src/verify/acceptance-replay.js +4 -7
- package/dist/runtime/src/verify/service.js +6 -23
- package/dist/runtime/src/verify/source-fingerprint.js +17 -4
- package/docs/en/guides/task-debug.md +39 -133
- package/docs/en/spec/acceptance-and-evidence.md +31 -23
- package/docs/en/spec/harness-adapters.md +9 -11
- package/docs/en/spec/loop-engineering.md +11 -5
- package/docs/zh-TW/guides/task-debug.md +27 -73
- package/docs/zh-TW/spec/acceptance-and-evidence.md +18 -18
- package/docs/zh-TW/spec/harness-adapters.md +7 -8
- package/docs/zh-TW/spec/loop-engineering.md +9 -4
- package/package.json +1 -1
- package/schemas/config.schema.json +1 -21
- package/dist/packages/cli/src/debug-intake.js +0 -245
- package/dist/runtime/src/task/debug-intake.js +0 -15
- package/dist/runtime/src/task/debug-state.js +0 -135
- package/dist/runtime/src/task/debug-user-event.js +0 -160
- package/dist/runtime/src/task/debug.js +0 -632
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { taskContractHash } from "../task/contract.js";
|
|
1
|
+
import { executionContractHash, taskContractHash } from "../task/contract.js";
|
|
2
2
|
import { replayAcceptance } from "./acceptance-replay.js";
|
|
3
3
|
import { AgentOpsError, resolveContainedPath } from "../fs/paths.js";
|
|
4
4
|
import { validateTaskAgainstConfig } from "../schema/validate.js";
|
|
@@ -61,7 +61,9 @@ export class VerificationService {
|
|
|
61
61
|
failureClass: result.failureClass,
|
|
62
62
|
sourceFingerprint,
|
|
63
63
|
toolVersions: this.#options.toolVersions ?? {},
|
|
64
|
-
|
|
64
|
+
// Surfaced tasks are always bound, so a later surface-only revision of a goal-less one keeps it; legacy tasks stay unbound.
|
|
65
|
+
...(task.goal === undefined && (task.contractRevision ?? 0) === 0 && task.criteria.every(c => c.acceptance === undefined) &&
|
|
66
|
+
task.surfaceRequired === undefined ? {} : { taskContractHash: executionContractHash(task) }),
|
|
65
67
|
config: this.#options.config
|
|
66
68
|
});
|
|
67
69
|
references.push(await this.#options.evidenceStore.save(evidence));
|
|
@@ -70,10 +72,7 @@ export class VerificationService {
|
|
|
70
72
|
}
|
|
71
73
|
async #runCommand(task, command) {
|
|
72
74
|
const startedAt = (this.#options.now ?? (() => new Date().toISOString()))();
|
|
73
|
-
const
|
|
74
|
-
if (remaining === 0)
|
|
75
|
-
throw verificationError("TASK_DEBUG_BUDGET_EXHAUSTED", "The original issue's active budget is exhausted.");
|
|
76
|
-
const result = await executeConfiguredCommand(remaining === undefined ? command : { ...command, timeoutMs: Math.min(command.timeoutMs ?? 300_000, remaining) }, {
|
|
75
|
+
const result = await executeConfiguredCommand(command, {
|
|
77
76
|
cwd: await this.#commandCwd(command),
|
|
78
77
|
runner: this.#options.processRunner,
|
|
79
78
|
trusted: this.#options.trusted
|
|
@@ -110,11 +109,6 @@ export class VerificationService {
|
|
|
110
109
|
};
|
|
111
110
|
}
|
|
112
111
|
async verify(taskId) {
|
|
113
|
-
const stored = await this.#options.taskService.status({ taskId });
|
|
114
|
-
return stored.task.debug === undefined ? await this.#verify(taskId) :
|
|
115
|
-
await this.#options.taskService.debugService().verification(taskId, () => this.#verify(taskId));
|
|
116
|
-
}
|
|
117
|
-
async #verify(taskId) {
|
|
118
112
|
const stored = await this.#options.taskService.status({ taskId });
|
|
119
113
|
if (stored.status === "archived") {
|
|
120
114
|
throw verificationError("TASK_NOT_ACTIVE", "An archived task cannot be verified.");
|
|
@@ -153,8 +147,7 @@ export class VerificationService {
|
|
|
153
147
|
results.push(await this.#runCommand(validation.value, commandById(this.#options.config, commandId)));
|
|
154
148
|
}
|
|
155
149
|
const acceptance = validation.value.criteria.some(c => c.acceptance !== undefined && c.acceptance.mode !== "review-only")
|
|
156
|
-
? await replayAcceptance({ ...this.#options, task: validation.value, sourceFingerprint
|
|
157
|
-
...(stored.task.debug === undefined ? {} : { remainingMs: () => this.#options.taskService.debugService().remaining(taskId) }) }) : [];
|
|
150
|
+
? await replayAcceptance({ ...this.#options, task: validation.value, sourceFingerprint }) : [];
|
|
158
151
|
let status = aggregateVerificationStatus([...results, ...acceptance.map(a => ({ required: true, status: a.status }))]);
|
|
159
152
|
let sourceChanged = false;
|
|
160
153
|
const postflightScope = await resolveReviewScope({
|
|
@@ -197,16 +190,6 @@ export class VerificationService {
|
|
|
197
190
|
}
|
|
198
191
|
}
|
|
199
192
|
else {
|
|
200
|
-
if (stored.task.debug !== undefined && !sourceChanged) {
|
|
201
|
-
const failures = {};
|
|
202
|
-
for (const result of results) {
|
|
203
|
-
const references = await this.#persistEvidence(validation.value, commandById(this.#options.config, result.commandId), result.startedAt, result.finishedAt, result, sourceFingerprint);
|
|
204
|
-
relevantCriteria(validation.value, result.commandId).forEach((criterion, index) => { const reference = references[index]; if (reference !== undefined)
|
|
205
|
-
failures[criterion.id] = [...(failures[criterion.id] ?? []), reference]; });
|
|
206
|
-
}
|
|
207
|
-
if (Object.keys(failures).length > 0)
|
|
208
|
-
await this.#options.taskService.recordEvidence(taskId, failures);
|
|
209
|
-
}
|
|
210
193
|
const required = [...results.filter((result) => result.required), ...acceptance.map(a => ({ commandId: a.runnerId, required: true,
|
|
211
194
|
status: a.status, failureClass: a.failureClass, exitCode: null, timedOut: false, testCount: null,
|
|
212
195
|
diagnostic: a.criterionId + ":" + a.phase + ":" + a.failureClass, evidenceReferences: [a.reference], startedAt: "", finishedAt: "" }))];
|
|
@@ -3,17 +3,30 @@ import { join } from "node:path";
|
|
|
3
3
|
import { sha256 } from "../fs/hash.js";
|
|
4
4
|
import { AgentOpsError } from "../fs/paths.js";
|
|
5
5
|
import { resolveGitCommit } from "./change-surface.js";
|
|
6
|
+
/**
|
|
7
|
+
* Escape-ledger records are committed after the fix; a commit touching only them leaves the base-mode fingerprint alone.
|
|
8
|
+
* Only top-level task records qualify: rules/ steer the surface gate and stay fingerprinted.
|
|
9
|
+
*/
|
|
10
|
+
const ledgerRecord = (path) => /^\.agent-ops-escapes\/task-[A-Za-z0-9-]+\.json$/u.test(path);
|
|
11
|
+
/** HEAD's tree without the ledger, so a ledger-only commit yields the same digest. */
|
|
12
|
+
async function ledgerFreeTree(runner) {
|
|
13
|
+
const result = await runner.run(["ls-tree", "-r", "--full-tree", "-z", "HEAD"]);
|
|
14
|
+
if (result.exitCode !== 0)
|
|
15
|
+
throw new AgentOpsError("CHANGE_SURFACE_GIT_FAILED", "Git could not list the HEAD tree.");
|
|
16
|
+
const entries = Buffer.from(result.stdout).toString("utf8").split("\0").filter(entry => entry !== "" && !ledgerRecord(entry.split("\t", 2)[1]));
|
|
17
|
+
return sha256(entries.join("\0"));
|
|
18
|
+
}
|
|
6
19
|
export async function calculateSourceFingerprint(root, scope, runner) {
|
|
7
|
-
const head = await resolveGitCommit(runner, "HEAD");
|
|
8
20
|
if (scope.mode === "base") {
|
|
9
21
|
return sha256(JSON.stringify({
|
|
10
|
-
domain: "agent-ops-source-
|
|
22
|
+
domain: "agent-ops-source-v2",
|
|
11
23
|
mode: scope.noChange === true ? "goal-no-change" : "base",
|
|
12
|
-
|
|
24
|
+
tree: await ledgerFreeTree(runner),
|
|
13
25
|
base: scope.resolvedBase,
|
|
14
|
-
paths:
|
|
26
|
+
paths: scope.changedFiles.filter(path => !ledgerRecord(path))
|
|
15
27
|
}));
|
|
16
28
|
}
|
|
29
|
+
const head = await resolveGitCommit(runner, "HEAD");
|
|
17
30
|
const paths = [];
|
|
18
31
|
for (const path of scope.changedFiles) {
|
|
19
32
|
const absolute = join(root, ...path.split("/"));
|
|
@@ -1,135 +1,41 @@
|
|
|
1
1
|
# Task DEBUG investigations
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
The
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
Pauses retain evidence, consumed time and rounds, exclude waiting time, and do not
|
|
43
|
-
reset budgets. Diagnosis and pause cannot complete a repair task. Ambiguous free
|
|
44
|
-
text is not inferred as permission; use an explicit command above.
|
|
45
|
-
|
|
46
|
-
Use `task debug --task <id> --debug-action <action>`:
|
|
47
|
-
|
|
48
|
-
- `status` displays root-wide hypotheses, receipts and remaining state.
|
|
49
|
-
- `investigate --command-id <id>` runs a trusted configured verifier. Actual
|
|
50
|
-
subprocess outcomes/time are recorded; reproduction-only work is not a fix round.
|
|
51
|
-
- `hypothesis --payload-file <json>` records `id`, `statement`, `method`,
|
|
52
|
-
`expected`, `checkId`, `expectedStatus` (`PASS` or `FAIL`). Add `reference` to
|
|
53
|
-
resolve it from actual sealed acceptance evidence. `--action investigate` may
|
|
54
|
-
only run a declared unresolved behavioral red check; `--action observe` may
|
|
55
|
-
only classify the current matching runtime `UNKNOWN` receipt as inconclusive.
|
|
56
|
-
Neither action lets an agent assign a status. A rejected hypothesis needs a
|
|
57
|
-
new reference and `reason`.
|
|
58
|
-
- `strategy --payload-file <json>` records a different `from`/`to` method,
|
|
59
|
-
substantive `reason` and discriminating `reference`. Only one switch is allowed.
|
|
60
|
-
- `origin --payload-file <json>` declares where the bug came from once a
|
|
61
|
-
hypothesis is confirmed: `{"kind": "escape-of", "commit": "<commit>", "label":
|
|
62
|
-
"<earliest gate>"}` (optional `"receipt"`) or `{"kind": "pre-existing" |
|
|
63
|
-
"external", "reason": "..."}`. It revises the contract, so re-verify and
|
|
64
|
-
re-record the confirmed hypothesis before review; finish refuses
|
|
65
|
-
`ESCAPE_ORIGIN_MISSING` without it. `escape-of` prints the link state and
|
|
66
|
-
`git blame` hints and writes `.agent-ops-escapes/<task-id>.json`, which is
|
|
67
|
-
committed with the fix (see `EVIDENCE-ESCAPE-001`). A surface label also
|
|
68
|
-
needs a tracked `.agent-ops-escapes/rules/<rule-id>.json` rule that replays
|
|
69
|
-
at the escaped commit, and a criteria/verify label needs `"promote":
|
|
70
|
-
"<runnerId:checkId>"`; finish refuses `ESCAPE_RULE_UNPROVEN` otherwise (see
|
|
71
|
-
`EVIDENCE-ESCAPE-002`).
|
|
72
|
-
- `checkpoint --session <id>` saves the current bound source/policy/stop cause.
|
|
73
|
-
- `resume --session <id>` recovers a matching owned worktree checkpoint. Mismatches
|
|
74
|
-
require human confirmation and remain preserved; this command cannot waive them.
|
|
75
|
-
- `extend --session <native-id> --event-id latest` reads the current native human
|
|
76
|
-
continue or resume-repair event. After time exhaustion it grants a full twenty
|
|
77
|
-
minutes from that event, retaining consumed time and overrun in the grant snapshot
|
|
78
|
-
without waiving any other blocker. No actor/text flag can
|
|
79
|
-
authorize a grant. Missing native transcripts fail closed as unsupported.
|
|
80
|
-
|
|
81
|
-
Limits belong to the original root across revisions, children and sessions.
|
|
82
|
-
Repeating an active issue's text from a new session reattaches that root (or
|
|
83
|
-
resumes the worktree holding it) instead of starting a fresh budget. A
|
|
84
|
-
resolved hypothesis cannot return under a new id with the same statement and
|
|
85
|
-
method; reopen the original with new discriminating evidence.
|
|
86
|
-
Controlled investigation, verification and acquired review execution consume
|
|
87
|
-
active time; observable review-slot waiting is excluded. Claude, Codex, and agy
|
|
88
|
-
use their native session lifecycle to account foreground reasoning, tool use,
|
|
89
|
-
and edits. Accepted idle Stop closes the foreground clock. Rejected Codex Stop
|
|
90
|
-
keeps the clock running, including repeated Stop (`stop_hook_active: true`). OpenCode has no supported
|
|
91
|
-
foreground lifecycle and remains unsupported. Time between stopped turns is
|
|
92
|
-
paused. An interrupted unsealed operation remains blocked until its persisted process
|
|
93
|
-
identity proves death; only then is an UNKNOWN environment receipt sealed and
|
|
94
|
-
the elapsed interval retained.
|
|
95
|
-
|
|
96
|
-
Only changed product candidates followed by verification count toward repair
|
|
97
|
-
rounds. Test/fixture edits do not. New paired original-regression outcomes or
|
|
98
|
-
new discriminating hypothesis outcomes count as progress; renaming a task or
|
|
99
|
-
hypothesis does not. Two stagnant rounds require the strategy switch; two more
|
|
100
|
-
stop, subject to the global round/time ceilings.
|
|
101
|
-
The switch may cite this issue's own sealed regression evidence from an earlier
|
|
102
|
-
contract revision, because a scope revision stales current evidence while
|
|
103
|
-
verification stays stopped; hypotheses and delivery still need fresh evidence.
|
|
104
|
-
At the round limit an unchanged candidate may still be reviewed, and re-verified
|
|
105
|
-
when its last verification passed; a failing or changed candidate stays stopped.
|
|
106
|
-
|
|
107
|
-
Success requires baseline assertion red and candidate green for the original
|
|
108
|
-
regression, required related checks, a supported confirmed hypothesis, and two
|
|
109
|
-
fresh independent reviews bound to the current source, contract, config and
|
|
110
|
-
meaningful DEBUG proof. Missing IDs, setup failure, skip, timeout and UNKNOWN
|
|
111
|
-
never prove reproduction. Proof changes invalidate review. Completed tasks and
|
|
112
|
-
worktree finish retain the existing attestation/integration requirements.
|
|
113
|
-
|
|
114
|
-
On Claude, agy and native Codex, Stop checks an active DEBUG issue even without Git net diff,
|
|
115
|
-
with or without the completion gate. Without the gate this check alone runs,
|
|
116
|
-
with one targeted task/config reload on a gate fault. A second failure emits an
|
|
117
|
-
explicit `UNKNOWN` / incomplete diagnostic with `agent-ops doctor` recovery,
|
|
118
|
-
permits non-success Stop and preserves the task, evidence and budgets. It never
|
|
119
|
-
attests completion or retries indefinitely.
|
|
120
|
-
A valid runtime stop checkpoint permits non-success Stop while retaining the
|
|
121
|
-
active task. `allow-stop` cannot waive DEBUG. Gates are never automatically
|
|
122
|
-
enabled for unsupported hosts: the generic Codex completion gate remains
|
|
123
|
-
unsupported, while its DEBUG-specific Stop uses native `decision: "block"`
|
|
124
|
-
with a continuation reason. `continue: false` would stop the harness and is not
|
|
125
|
-
used to continue DEBUG. OpenCode Stop is unsupported. This feature
|
|
126
|
-
persists foreground progress, and does not promise
|
|
127
|
-
execution after the native conversation closes. Native transcripts are trusted
|
|
128
|
-
host evidence, not protection against an attacker with the same filesystem
|
|
129
|
-
authority.
|
|
130
|
-
|
|
131
|
-
An explicit native human `no time limit` / `取消時間限制` instruction removes the
|
|
132
|
-
original issue time cap via the same native-only `extend --event-id latest`
|
|
133
|
-
authority. The grant records `grantedMs: null` and the spent snapshot; original
|
|
134
|
-
budget, consumption, prior grants, iteration limits and evidence gates remain.
|
|
135
|
-
Ordinary command and review stall timeouts remain in force.
|
|
3
|
+
A DEBUG task is an ordinary task whose acceptance proves the original
|
|
4
|
+
regression: a behavioral criterion whose `redCheckIds` fail with an assertion at
|
|
5
|
+
the baseline commit and pass on the candidate. Nothing else is special about it.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
agent-ops task create --debug --title "Fix cart scroll" \
|
|
9
|
+
--goal '<the issue, verbatim>' \
|
|
10
|
+
--surface-file surface.json \
|
|
11
|
+
--criterion-file regression.json --criterion-file related.json
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
- `--debug` needs `--goal` and at least one behavioral criterion with
|
|
15
|
+
`redCheckIds`; otherwise creation fails with `TASK_DEBUG_RED_CHECK_REQUIRED`.
|
|
16
|
+
The surface audit is required as for any task.
|
|
17
|
+
- The baseline is the commit the task was created on; `task revise --baseline
|
|
18
|
+
<ref>` moves it (for example off the wrong branch) and voids earlier evidence.
|
|
19
|
+
- Then fix, commit, `verify`, two-round `review` and `worktree finish` exactly
|
|
20
|
+
as for any task. Setup failure, skip, timeout and UNKNOWN never prove
|
|
21
|
+
reproduction; the red check must fail on an assertion at the baseline.
|
|
22
|
+
|
|
23
|
+
## Escape origin (advisory)
|
|
24
|
+
|
|
25
|
+
If you know where the bug came from, record it like any task:
|
|
26
|
+
`task revise --escape-of <commit> --escape-label <label>`. It writes `.agent-ops-escapes/<task-id>.json` and
|
|
27
|
+
prints the link state, `git blame` hints and any rule proof
|
|
28
|
+
(`ESCAPE_RULE_UNPROVEN` and friends). None of it blocks finish; see
|
|
29
|
+
`EVIDENCE-ESCAPE-001` and `EVIDENCE-ESCAPE-002`.
|
|
30
|
+
|
|
31
|
+
## Removed in 0.11.0
|
|
32
|
+
|
|
33
|
+
`task debug` (hypotheses, strategy switches, investigate, checkpoint, resume,
|
|
34
|
+
extend, origin), the 60-minute budget and five-round limit, native control
|
|
35
|
+
words (只診斷, 暫停, 繼續, 繼續修復, 取消時間限制), automatic DEBUG intake from
|
|
36
|
+
prompt hooks, the DEBUG-specific Stop block and the Codex `Interrupt` hook are
|
|
37
|
+
gone. `task debug` now fails with `TASK_DEBUG_REMOVED`.
|
|
38
|
+
|
|
39
|
+
Older state still loads: tasks keep their `debug` tag, stored budget and
|
|
40
|
+
hypothesis state is ignored, `originRequired` no longer blocks finish, and a
|
|
41
|
+
config's `features.debug` is accepted and dropped by the next `update`.
|
|
@@ -18,10 +18,11 @@ Executable acceptance MUST bind the current contract to immutable replay evidenc
|
|
|
18
18
|
build and test build. Tasks provide stable check IDs and explicit committed
|
|
19
19
|
test/fixture/helper materials. Each checkout installs and builds its own version
|
|
20
20
|
before candidate materials are overlaid. Tasks cannot override runner commands.
|
|
21
|
-
- A generic runner must emit
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
- A generic runner must emit every `checkId` requested by criteria sharing its
|
|
22
|
+
runner, baseline and materials, each exactly once; missing or duplicate rows are
|
|
23
|
+
UNKNOWN. Other rows are ignored, so a binding may list only its red checks. A
|
|
24
|
+
failing unrequested row still disagrees with a PASS aggregate through the
|
|
25
|
+
runner's exit code, which makes the candidate UNKNOWN, never green.
|
|
25
26
|
- Fixture, collection, build, timeout, cancellation, truncated output, missing or
|
|
26
27
|
duplicate IDs, retries and skips MUST NOT establish red or green. Complete raw
|
|
27
28
|
execution artifacts are digest-bound to the contract, materials and commits.
|
|
@@ -34,9 +35,15 @@ Executable acceptance MUST bind the current contract to immutable replay evidenc
|
|
|
34
35
|
counters and cannot supply mechanical proof by itself. Pytest requires one
|
|
35
36
|
ordered setup/call/teardown lifecycle per nodeid; the Rust protocol requires
|
|
36
37
|
explicit attempts. Missing metadata MUST NOT default to a successful attempt.
|
|
37
|
-
- Baselines are
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
- Baselines are creation commits, or failed candidates for finding pins.
|
|
39
|
+
`task revise --baseline <ref>` moves every typed criterion's baseline (and the
|
|
40
|
+
task's creation commit) at once to a commit that is an ancestor of HEAD, for example after a task was opened on the
|
|
41
|
+
wrong branch, and voids its verification. Revise/replan preserve the original
|
|
42
|
+
goal, every mapped requirement and previous contracts/evidence.
|
|
43
|
+
- Verification evidence binds an execution hash of the criteria only. A revise
|
|
44
|
+
that changes the surface or origin keeps it; a criteria or configuration change
|
|
45
|
+
voids it. Evidence from before 0.11 bound the full contract hash and still
|
|
46
|
+
matches an unchanged contract. Every new contract needs both fresh reviews.
|
|
40
47
|
- `task pin-finding` validates saved report digest/index provenance. Recurrence
|
|
41
48
|
explicitly names an existing pin. A sixth criterion returns a replan obligation
|
|
42
49
|
without changing state; the mapped replan must retain the pin and all requirements.
|
|
@@ -76,7 +83,7 @@ Each child worktree MUST record its modification intent before editing.
|
|
|
76
83
|
|
|
77
84
|
Every new task MUST record a surface audit of where else its change lands before writing criteria, and review MUST NOT run while discovery finds an unclassified place.
|
|
78
85
|
|
|
79
|
-
- Trigger: Creating a task (`task create`,
|
|
86
|
+
- Trigger: Creating a task (`task create`, including `--debug`, or a run plan), revising its surface, or reviewing it.
|
|
80
87
|
- Action: Search four axes with recorded fixed-string queries or `n/a: reason`, classify every hit as included, excluded (glob + reason) or UNKNOWN, give every surface row an observable `behavior`, and declare each shared contract compatible or breaking. Pass it with `task create|revise --surface-file <json>`.
|
|
81
88
|
- Evidence: The surface is stored on the task, bound into its contract hash with revision history, replayed by `git grep -F` before review, and handed to both reviewers under the `surface-coverage` criterion.
|
|
82
89
|
- Positive: `A diff token hits three copy-pasted sibling pages; the audit includes them with their behavior before review runs.`
|
|
@@ -118,8 +125,11 @@ Every new task MUST record a surface audit of where else its change lands before
|
|
|
118
125
|
dismissals. Reviewers see each dismissal with its hit count, flagged when it
|
|
119
126
|
hid a file an earlier `SURFACE_UNCLASSIFIED` block named.
|
|
120
127
|
Results are cached by HEAD, base, diff, query set and config hash.
|
|
128
|
+
- `verify` runs the same gate after verification and prints its result as
|
|
129
|
+
advisory lines (`Surface: PASS`, or the code and unclassified paths), so the
|
|
130
|
+
surface is fixed before review; only review enforces it.
|
|
121
131
|
- Review returns NOT_RUN with: `SURFACE_MISSING` (no or unparseable surface;
|
|
122
|
-
also refused at create
|
|
132
|
+
also refused at create), `SURFACE_UNCLASSIFIED`,
|
|
123
133
|
`SURFACE_QUERY_TOO_BROAD` (one recorded query over 200 files),
|
|
124
134
|
`SURFACE_EXCLUSION_TOO_BROAD` (one glob over 10 files, or any file in the
|
|
125
135
|
diff), `SURFACE_DISMISSAL_TOO_BROAD` (over 128 dismissals),
|
|
@@ -137,17 +147,15 @@ Every new task MUST record a surface audit of where else its change lands before
|
|
|
137
147
|
|
|
138
148
|
## EVIDENCE-ESCAPE-001
|
|
139
149
|
|
|
140
|
-
|
|
150
|
+
A bug fix SHOULD declare where its bug came from when known, and a declared escape MUST be linked, labelled and recorded mechanically. The declaration is advisory: it never blocks finish.
|
|
141
151
|
|
|
142
|
-
- Trigger: A DEBUG
|
|
143
|
-
- Action: Declare `origin` with `task
|
|
144
|
-
- Evidence: `origin` is bound into the task contract hash;
|
|
145
|
-
- Positive: `
|
|
146
|
-
- Negative: `
|
|
152
|
+
- Trigger: A DEBUG task (`task create --debug`) or any task fixes a bug that passed earlier gates and its origin is known.
|
|
153
|
+
- Action: Declare `origin` with `task create|revise --escape-of <commit> --escape-label <label> [--escape-receipt <id>]`, the same for DEBUG and normal tasks. `pre-existing` and `external` origins (with a `reason`) recorded by 0.10 `task debug` still load; an undeclared origin is counted as such. Commit the `.agent-ops-escapes/<task-id>.json` record with the fix.
|
|
154
|
+
- Evidence: `origin` is bound into the task contract hash; both reviewers receive the link state, labels, facts and residual risks under the `escape-label` criterion. A task without an origin still finishes; 0.10 tasks marked `originRequired` are no longer refused (`ESCAPE_ORIGIN_MISSING` was removed in 0.11.0).
|
|
155
|
+
- Positive: `Regression red at the baseline, green on the fix; origin escape-of 864dbbe2 label surface; replay marks the missed page surface-unseen; the record is committed with the fix.`
|
|
156
|
+
- Negative: `Relabel a surface-excluded miss as review because the reviewer "should have noticed".`
|
|
147
157
|
|
|
148
|
-
- The declaration
|
|
149
|
-
otherwise), inside the DEBUG budget. It is a contract revision: re-verify,
|
|
150
|
-
re-record the confirmed hypothesis with the new evidence, then review.
|
|
158
|
+
- The declaration is a contract revision: re-verify, then review.
|
|
151
159
|
Re-declaring replaces the record. The output lists `git blame` hint commits
|
|
152
160
|
for lines the fix changed or removed; blame is a hint only, because an
|
|
153
161
|
omission bug lives in lines nobody wrote.
|
|
@@ -181,13 +189,13 @@ Every DEBUG fix MUST declare where its bug came from before review, and a declar
|
|
|
181
189
|
|
|
182
190
|
## EVIDENCE-ESCAPE-002
|
|
183
191
|
|
|
184
|
-
A surface escape
|
|
192
|
+
A surface escape SHOULD become a proven, tracked rule, and learned rules MUST only tighten the surface gate. The proof is advisory: it never blocks finish.
|
|
185
193
|
|
|
186
194
|
- Trigger: A declared escape-of origin (EVIDENCE-ESCAPE-001), or a past escape backfilled with `task create --escape-of <commit> --escape-label <label> --escape-fix <fix-commit>`.
|
|
187
|
-
- Action: For a `surface`, `surface-unseen` or `surface-excluded` label, commit a rule `.agent-ops-escapes/rules/<rule-id>.json` shaped `{"id", "escape", "label", "trigger": {"paths", "tokens"}, "expand": {"paths", "queries"}, "noExclude"}` and re-declare the origin. For `criteria` or `verify`, name the fixing task's red-to-green check with `--escape-promote <runnerId:checkId>` (
|
|
188
|
-
- Evidence:
|
|
195
|
+
- Action: For a `surface`, `surface-unseen` or `surface-excluded` label, commit a rule `.agent-ops-escapes/rules/<rule-id>.json` shaped `{"id", "escape", "label", "trigger": {"paths", "tokens"}, "expand": {"paths", "queries"}, "noExclude"}` and re-declare the origin. For `criteria` or `verify`, name the fixing task's red-to-green check with `--escape-promote <runnerId:checkId>` (origin field `"promote"`). Other labels record a lesson.
|
|
196
|
+
- Evidence: Declaring the origin runs the proof and prints `ESCAPE_RULE_UNPROVEN`, `ESCAPE_RULE_TOO_BROAD` or `SURFACE_BUDGET_EXCEEDED` when it fails; since 0.11.0 finish no longer refuses them. The ledger record stores the proving rule, its content hash and its backtest fires, commits and rate.
|
|
189
197
|
- Positive: `Escape surface-unseen; rule image-size-siblings fires on the escaped commit, its query hits both missed sibling pages there, and fires on 2 of the last 200 commits.`
|
|
190
|
-
- Negative: `
|
|
198
|
+
- Negative: `Report a surface escape as proven when its rule never fires on the escaped commit, or add a rule field that excludes paths.`
|
|
191
199
|
|
|
192
200
|
- Rules are data only and need no trust: triggers and expands become argv
|
|
193
201
|
`git grep -F` queries and path globs, never shell or regex. The strict schema
|
|
@@ -257,7 +265,7 @@ New verification evidence uses schema 3. Schema 2 remains readable and its exit-
|
|
|
257
265
|
|
|
258
266
|
Existing task files remain readable without migration. Legacy tasks without a config baseline, arbitrary evidence references, or unfinished archived children must be recreated and verified/reviewed before completion. Repeating completion also revalidates the evidence; an old completed status alone is insufficient. Runtime callers must supply `TaskServiceOptions.completion`; omitting this repository context fails closed for completion while leaving read-only task operations available.
|
|
259
267
|
|
|
260
|
-
Before committing, use the default worktree scope for verify, review and completion. After committing, use the same `--base <git-ref>` on all three commands to produce fresh proof for that committed range; `TaskServiceOptions.completion.base` selects it for runtime callers. Base mode requires a clean worktree. Without a worktree change surface or an explicit base, completion returns `TASK_COMPLETION_SCOPE_REQUIRED`. The agy Stop gate still checks worktree-scoped proof: complete and stop before committing, or use its user-approved one-time permit after inspecting a completed base-scoped task.
|
|
268
|
+
Before committing, use the default worktree scope for verify, review and completion. After committing, use the same `--base <git-ref>` on all three commands to produce fresh proof for that committed range. When `--base` is absent and the tree is clean, verify and review choose it: a session worktree uses its merge-base with the target branch (which follows a finish rebase), elsewhere the task's creation commit when it is an ancestor of HEAD. Base-mode source fingerprints ignore escape-ledger task records (`.agent-ops-escapes/task-*.json`; rules stay fingerprinted), so committing the ledger keeps verification and review current; fingerprints from 0.10 differ, so re-verify once after upgrading; `TaskServiceOptions.completion.base` selects it for runtime callers. Base mode requires a clean worktree. Without a worktree change surface or an explicit base, completion returns `TASK_COMPLETION_SCOPE_REQUIRED`. The agy Stop gate still checks worktree-scoped proof: complete and stop before committing, or use its user-approved one-time permit after inspecting a completed base-scoped task.
|
|
261
269
|
|
|
262
270
|
This enforces the toolkit's completion command, not a host's natural-language completion claim. It does not prevent a process with the same filesystem authority from editing task/evidence files directly, and it does not lock Git or external source writers.
|
|
263
271
|
|
|
@@ -118,17 +118,12 @@ installed configuration; the managed OpenCode `tool.execute.before` plugin can
|
|
|
118
118
|
throw its documented denial or unavailable-runtime error for its supported Bash
|
|
119
119
|
surface. Codex remains `unknown` and never emits a denial. Fixture tests assert
|
|
120
120
|
these wire and plugin shapes only; they do not prove that a host honors a
|
|
121
|
-
denial. `SessionStart` and
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
`decision: "block"` with `reason` schedules a continuation; `continue: false`
|
|
128
|
-
halts it. `stop_hook_active` identifies a prior continuation and cannot waive
|
|
129
|
-
the DEBUG check. Native `Interrupt` pauses with a three-second timeout and
|
|
130
|
-
never blocks or restarts the human interruption. This DEBUG-specific policy
|
|
131
|
-
does not enable Codex's generic completion gate or optional Stop verifier.
|
|
121
|
+
denial. `SessionStart` and `Stop` failures remain fail-open.
|
|
122
|
+
|
|
123
|
+
Since 0.11.0 no hook is DEBUG-specific: prompts never open DEBUG tasks, Stop
|
|
124
|
+
never holds a session for one, and Codex `Interrupt` is no longer registered
|
|
125
|
+
(a stale registration from an older install is a no-op until `update`). Codex
|
|
126
|
+
still has no generic completion gate or optional Stop verifier.
|
|
132
127
|
Codex separately trusts each exact native hook definition. After managed hook
|
|
133
128
|
updates, review new or changed definitions in `/hooks`; agent-ops repository
|
|
134
129
|
trust alone does not make an unreviewed native hook active.
|
|
@@ -197,6 +192,9 @@ removes only `run` and keeps `loop`.
|
|
|
197
192
|
resumability and concrete remediation. An unchanged cleanup failure retains its
|
|
198
193
|
original cause. Trust, native identity, generation and denial failures remain
|
|
199
194
|
fail-closed; a sealed proof never erases a native or organization denial.
|
|
195
|
+
The JSON `state` of `run status` and `run logs` omits the event history and goal
|
|
196
|
+
text, keeping `eventCount` and `goalHash`, so repeated polling stays small;
|
|
197
|
+
`run logs` returns the events themselves.
|
|
200
198
|
|
|
201
199
|
Manual resume of a receipt-bound integration validates the exact sealed proof,
|
|
202
200
|
receipt digest and transaction, owner/generation, candidate/target ancestry and
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
still measure setup, proof, review and integration. Legacy finite runs upgrade
|
|
19
19
|
only on manual resume, retaining the old limit, intervals, elapsed time, usage
|
|
20
20
|
epochs and blocker history. Reads and installation never upgrade or awaken runs.
|
|
21
|
-
Command/review timeouts, provider quotas
|
|
21
|
+
Command/review timeouts, provider quotas and no-progress/stop
|
|
22
22
|
controls remain independent and effective. Explicit --time-budget is rejected.
|
|
23
23
|
Missing counters remain UNKNOWN; partial usage is not a complete cost estimate.
|
|
24
24
|
- Questions pause work and require an explicit answer. Repair preserves the goal
|
|
@@ -72,10 +72,16 @@
|
|
|
72
72
|
- Convergence compares actual per-check statuses and outstanding finding pins.
|
|
73
73
|
Source fingerprints, timing and diagnostics alone cannot establish progress.
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
For any `jobs` value, the coordinator MUST yield only through an explicit
|
|
76
|
+
`action=wait` request sent after it has planned its children; the supervisor
|
|
77
|
+
never stops a coordinator that is still planning. A wait confirms coordinator
|
|
78
|
+
process death, frees its slot and drops its native thread, so the coordinator does
|
|
79
|
+
not poll `run status` while children work. Recovery leaves a waiting coordinator
|
|
80
|
+
stopped; once every child is delivered, complete or blocked, it restarts under a
|
|
81
|
+
new generation in a fresh native session whose instructions list each child's
|
|
82
|
+
status and delivered commit. With `jobs=1`, child execution MUST wait for that
|
|
83
|
+
confirmed death. Native registration, recovery and start MUST enforce at most
|
|
84
|
+
`jobs` active agents; changing task slot accounting alone is insufficient.
|
|
79
85
|
|
|
80
86
|
This module defines the bounded loop used to plan, implement, verify, and hand off work.
|
|
81
87
|
|
|
@@ -1,83 +1,37 @@
|
|
|
1
1
|
# Task DEBUG 調查
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
DEBUG task 就是一般 task,只是驗收條件要證明原始回歸:一條 behavioral criterion,
|
|
4
|
+
其 `redCheckIds` 在 baseline commit 以 assertion 失敗、在 candidate 通過。除此之外沒有任何特殊流程。
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
```sh
|
|
7
|
+
agent-ops task create --debug --title "修購物車無法捲動" \
|
|
8
|
+
--goal '<原始問題,逐字>' \
|
|
9
|
+
--surface-file surface.json \
|
|
10
|
+
--criterion-file regression.json --criterion-file related.json
|
|
11
|
+
```
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
- `--debug` 需要 `--goal`,且至少一條帶 `redCheckIds` 的 behavioral criterion;
|
|
14
|
+
否則建立失敗並回 `TASK_DEBUG_RED_CHECK_REQUIRED`。surface audit 與一般 task 一樣必填。
|
|
15
|
+
- baseline 是建立 task 時的 commit;`task revise --baseline <ref>` 可移動它
|
|
16
|
+
(例如開錯分支時),並使先前證據失效。
|
|
17
|
+
- 之後修復、commit、`verify`、兩輪 `review`、`worktree finish`,與一般 task 完全相同。
|
|
18
|
+
setup 失敗、skip、timeout 與 UNKNOWN 都不算重現;red check 必須在 baseline 以 assertion 失敗。
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
再透過既有 worktree finish 完成。基線 assertion red、候選 green、相關檢查與
|
|
21
|
-
當前 proof digest 都必須有效;setup / skip / timeout / UNKNOWN 不算重現。
|
|
22
|
-
DEBUG 預設自動走完修復閉環。乾淨 HEAD 自動固定為基線,不要為此再問許可,
|
|
23
|
-
也不要主動降為只診斷。單次未重現不構成停止理由;在原預算內繼續做鑑別檢查。
|
|
20
|
+
## 逃逸來源(建議性質)
|
|
24
21
|
|
|
25
|
-
|
|
22
|
+
若知道 bug 從哪裡來,與一般 task 一樣記錄:
|
|
23
|
+
`task revise --escape-of <commit> --escape-label <label>`。它會寫入 `.agent-ops-escapes/<task-id>.json`,並印出
|
|
24
|
+
連結狀態、`git blame` 提示與規則證明(如 `ESCAPE_RULE_UNPROVEN`)。這些都不會阻擋
|
|
25
|
+
finish;見 `EVIDENCE-ESCAPE-001` 與 `EVIDENCE-ESCAPE-002`。
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
訊息及注入指令都不能授權。Codex 支援目前 `response_item` 的 `user.text` 與
|
|
29
|
-
原生非同步回答,也保留舊 `event_msg` 格式。
|
|
27
|
+
## 0.11.0 移除項目
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
- `繼續` / `continue`:接回同一 task 及原範圍;耗盡時間仍需既有原生時間授權,其他阻礙不解除。
|
|
36
|
-
- `繼續修復` / `resume repair`:在原 task 恢復完整修復閉環。
|
|
29
|
+
`task debug`(假設、策略切換、investigate、checkpoint、resume、extend、origin)、
|
|
30
|
+
60 分鐘預算與 5 輪上限、原生控制詞(只診斷、暫停、繼續、繼續修復、取消時間限制)、
|
|
31
|
+
prompt hook 自動建立 DEBUG、DEBUG 專用 Stop 阻擋,以及 Codex `Interrupt` hook
|
|
32
|
+
都已移除。`task debug` 現在回傳 `TASK_DEBUG_REMOVED`。
|
|
37
33
|
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
舊狀態仍可讀取:task 保留 `debug` 標記,已存的預算與假設狀態會被忽略,
|
|
35
|
+
`originRequired` 不再阻擋 finish,config 的 `features.debug` 仍被接受並在下次 `update` 時移除。
|
|
40
36
|
|
|
41
|
-
|
|
42
|
-
受控調查、驗證與取得 slot 後的 review 計時;review 排隊不計時。
|
|
43
|
-
Claude、Codex 與 agy 都使用可信 native session lifecycle,在 `UserPromptSubmit`
|
|
44
|
-
或原生 session 開始前景時鐘,並在 idle `Stop` 結束。因此該輪的 Agent 推理、
|
|
45
|
-
工具與修改都計入,停止回合之間的使用者等待不計入。Codex 被拒絕的 Stop 仍繼續
|
|
46
|
-
計時,重複 Stop 的 `stop_hook_active: true` 不會繞過 DEBUG gate。opencode 沒有支援
|
|
47
|
-
的前景 lifecycle,不可宣稱完整的 active-time 預算。
|
|
48
|
-
中斷且沒有封存結果的操作,必須等持久化 process identity 證實程序已死亡後,
|
|
49
|
-
才封存 UNKNOWN environment receipt;這段經過時間仍會保留,不會退還不明時間。
|
|
50
|
-
測試材料修改不算修復輪;兩輪停滯需要一次實質策略切換,再兩輪停滯停止。
|
|
51
|
-
範圍改版會讓現有證據失效、而驗證在登記策略切換前仍停止,因此策略切換可引用同一原始任務已封存的歷史回歸證據;假設確認與最終交付仍需新版契約的新證據。
|
|
52
|
-
達到回合上限後,未變更的候選仍可審查;上次驗證通過時也可重新驗證(例如只更新 escape ledger),不計為新回合。驗證失敗或產品內容變更的候選仍維持停止。
|
|
53
|
-
|
|
54
|
-
假設確認後以 `origin --payload-file <json>` 宣告 bug 來源:`{"kind": "escape-of",
|
|
55
|
-
"commit": "<commit>", "label": "<最早關卡>"}`(可選 `"receipt"`),或 `{"kind":
|
|
56
|
-
"pre-existing" | "external", "reason": "..."}`。它會修訂 contract,因此 review 前要重新
|
|
57
|
-
verify 並重新記錄已確認的假設;沒有它時 finish 以 `ESCAPE_ORIGIN_MISSING` 拒絕。
|
|
58
|
-
`escape-of` 會印出連結狀態與 `git blame` 提示,並寫入 `.agent-ops-escapes/<task-id>.json`,
|
|
59
|
-
與修復一起 commit(見 `EVIDENCE-ESCAPE-001`)。surface 標記還需要一條在被逃逸 commit
|
|
60
|
-
重放成立、受追蹤的 `.agent-ops-escapes/rules/<rule-id>.json` 規則;criteria/verify 標記需要
|
|
61
|
-
`"promote": "<runnerId:checkId>"`;否則 finish 以 `ESCAPE_RULE_UNPROVEN` 拒絕(見
|
|
62
|
-
`EVIDENCE-ESCAPE-002`)。
|
|
63
|
-
|
|
64
|
-
checkpoint 保存 task/session/source/contract/config/cause;resume 只接受同一
|
|
65
|
-
擁有者 worktree 的匹配 checkpoint,保留 dirty 內容及預算。失配需要人類確認。
|
|
66
|
-
時間耗盡後明確「繼續」或「繼續修復」可透過 `extend --event-id latest` 讀取原生人類事件,
|
|
67
|
-
從該事件取得完整 20 分鐘,並以 grant 快照保留既有消耗與超時;沒有可信事件來源則回報 unsupported,其他阻礙不被解除。
|
|
68
|
-
|
|
69
|
-
Claude / agy / 原生 Codex 的 Stop 都會檢查無 Git 差異的 active DEBUG task,不論是否安裝 completion gate。
|
|
70
|
-
DEBUG gate 故障先針對 task/config 重新載入一次;仍失敗則明確回報 `UNKNOWN/未完成`
|
|
71
|
-
與 `agent-ops doctor` 恢復方法,允許非成功停止並保留 task、證據及預算,不無限重試。
|
|
72
|
-
有效停止 checkpoint 只允許非成功停止,task 仍 active;allow-stop 不能繞過。
|
|
73
|
-
Codex 的一般 completion gate 仍 unsupported;DEBUG 專用 Stop 以原生
|
|
74
|
-
`decision: "block"` 與 reason 續跑,不能使用會停止 harness 的 `continue: false`。
|
|
75
|
-
已接受的 Stop 結束前景時鐘;opencode Stop unsupported。
|
|
76
|
-
只承諾前景對話與持久化進度,不承諾對話關閉後繼續,也不宣稱抵擋同檔案權限攻擊。
|
|
77
|
-
|
|
78
|
-
完整命令及細節見英文 [Task DEBUG](../../en/guides/task-debug.md)。
|
|
79
|
-
|
|
80
|
-
原生人類明確要求「取消時間限制」或 `no time limit` 時,可透過同一個
|
|
81
|
-
`extend --event-id latest` 原生授權入口取消原任務總時限。grant 記錄
|
|
82
|
-
`grantedMs: null` 與已用時間快照;原預算、消耗、舊 grant、回合限制及
|
|
83
|
-
驗證與 review 關卡均保留。個別命令與 review 的防卡死逾時仍有效。
|
|
37
|
+
完整說明見英文 [Task DEBUG](../../en/guides/task-debug.md)。
|