@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.
Files changed (47) hide show
  1. package/dist/packages/cli/src/args.js +8 -43
  2. package/dist/packages/cli/src/bin.js +28 -29
  3. package/dist/packages/cli/src/cli.js +12 -14
  4. package/dist/packages/cli/src/codex-loop-process.js +0 -6
  5. package/dist/packages/cli/src/commands/review.js +5 -10
  6. package/dist/packages/cli/src/commands/run.js +3 -1
  7. package/dist/packages/cli/src/commands/task.js +6 -50
  8. package/dist/packages/cli/src/commands/verify.js +7 -3
  9. package/dist/packages/cli/src/default-base.js +26 -0
  10. package/dist/packages/cli/src/hook-process.js +19 -83
  11. package/dist/packages/cli/src/run-entry.js +66 -21
  12. package/dist/runtime/src/adapters/agy/config.js +2 -3
  13. package/dist/runtime/src/adapters/claude/config.js +2 -2
  14. package/dist/runtime/src/adapters/codex/config.js +2 -5
  15. package/dist/runtime/src/hooks/completion-gate.js +0 -15
  16. package/dist/runtime/src/install/harness.js +3 -3
  17. package/dist/runtime/src/install/plan.js +3 -3
  18. package/dist/runtime/src/install/profiles.js +0 -2
  19. package/dist/runtime/src/office/snapshot.js +4 -1
  20. package/dist/runtime/src/parallel/manage.js +0 -3
  21. package/dist/runtime/src/review/execute.js +68 -4
  22. package/dist/runtime/src/run/verification.js +2 -2
  23. package/dist/runtime/src/schema/validate.js +10 -5
  24. package/dist/runtime/src/task/completion.js +4 -42
  25. package/dist/runtime/src/task/contract.js +11 -0
  26. package/dist/runtime/src/task/service.js +34 -57
  27. package/dist/runtime/src/task/store.js +3 -7
  28. package/dist/runtime/src/verify/acceptance-coverage.js +2 -3
  29. package/dist/runtime/src/verify/acceptance-protocol.js +4 -3
  30. package/dist/runtime/src/verify/acceptance-replay.js +4 -7
  31. package/dist/runtime/src/verify/service.js +6 -23
  32. package/dist/runtime/src/verify/source-fingerprint.js +17 -4
  33. package/docs/en/guides/task-debug.md +39 -133
  34. package/docs/en/spec/acceptance-and-evidence.md +31 -23
  35. package/docs/en/spec/harness-adapters.md +9 -11
  36. package/docs/en/spec/loop-engineering.md +11 -5
  37. package/docs/zh-TW/guides/task-debug.md +27 -73
  38. package/docs/zh-TW/spec/acceptance-and-evidence.md +18 -18
  39. package/docs/zh-TW/spec/harness-adapters.md +7 -8
  40. package/docs/zh-TW/spec/loop-engineering.md +9 -4
  41. package/package.json +1 -1
  42. package/schemas/config.schema.json +1 -21
  43. package/dist/packages/cli/src/debug-intake.js +0 -245
  44. package/dist/runtime/src/task/debug-intake.js +0 -15
  45. package/dist/runtime/src/task/debug-state.js +0 -135
  46. package/dist/runtime/src/task/debug-user-event.js +0 -160
  47. 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
- ...(task.goal === undefined && (task.contractRevision ?? 0) === 0 && task.criteria.every(c => c.acceptance === undefined) ? {} : { taskContractHash: taskContractHash(task) }),
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 remaining = task.debug === undefined ? undefined : await this.#options.taskService.debugService().remaining(task.id);
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-v1",
22
+ domain: "agent-ops-source-v2",
11
23
  mode: scope.noChange === true ? "goal-no-change" : "base",
12
- head,
24
+ tree: await ledgerFreeTree(runner),
13
25
  base: scope.resolvedBase,
14
- paths: [...scope.changedFiles]
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
- Project `init` and `update` add `features.debug` by default:
4
- `{"enabled":true,"budgetMs":3600000,"maxRounds":5}` (sixty minutes). Explicit disabled and custom
5
- settings survive subsequent installs. Old configurations and ordinary tasks
6
- remain readable. DEBUG is an optional task intake field, not a new run mode.
7
-
8
- Claude and Codex native prompt hooks conservatively recognize investigation and
9
- bug-fix requests. They retain the issue verbatim as `goal`, record uncertain
10
- facts/unknowns, and create an existing isolated task. Explain, feature and
11
- refactor requests retain their ordinary behavior. A reliable native session ID
12
- is required; agy does not provide this prompt intake. Its native agent can use
13
- `task create --debug --goal '<original issue>'` with two to five criteria, which
14
- starts the same foreground clock when the native session is available.
15
- An original dirty checkout is refused before any worktree snapshot is created.
16
-
17
- The intake criteria are provisional. The native agent investigates via trusted
18
- configured commands, records hypotheses, replaces the criteria with relevant
19
- behavioral acceptance, fixes the product, and uses existing `verify`, `review`
20
- and worktree finish commands. There is no additional model or background worker.
21
- The default is the full repair loop. A clean HEAD fixes the baseline automatically;
22
- do not request redundant approval or offer diagnosis-only as a fallback. Failure
23
- to reproduce alone does not permit Stop: continue discriminating checks within
24
- the original budget.
25
-
26
- ## Human control
27
-
28
- Native human transcript events control the existing task; CLI actor/text fields,
29
- assistant messages and injected instructions cannot authorize a scope change.
30
- Codex supports current `response_item` human messages and native async answers,
31
- as well as legacy `event_msg` transcripts.
32
-
33
- - `只診斷` / `diagnosis only`: investigate without product repairs. Non-success
34
- Stop requires a confirmed hypothesis supported by a current sealed baseline
35
- assertion FAIL for the original regression, or an existing runtime blocker/limit.
36
- - `暫停` / `pause`: save progress and stop immediately. Native Codex `Interrupt`
37
- also pauses, with a three-second hook timeout; it never blocks or restarts an interrupt.
38
- - `繼續` / `continue`: resume the same task and scope. An exhausted time budget
39
- still needs the existing native time grant; other blockers remain authoritative.
40
- - `繼續修復` / `resume repair`: restore the full repair loop on the existing task.
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 exactly the union of `checkIds` requested by criteria
22
- sharing its runner, baseline and materials; unexpected rows are UNKNOWN. If a
23
- runner always emits its full suite, bind the full emitted set while keeping
24
- `redCheckIds` limited to the actual regression assertions.
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 immutable creation commits, or failed candidates for finding pins.
38
- Revise/replan preserve the original goal, every mapped requirement and previous
39
- contracts/evidence. New contracts require new proof and both fresh reviews.
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`, a run plan, or before a DEBUG task's first repair), revising its surface, or reviewing it.
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 for non-DEBUG tasks), `SURFACE_UNCLASSIFIED`,
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
- Every DEBUG fix MUST declare where its bug came from before review, and a declared escape MUST be linked, labelled and recorded mechanically.
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 hypothesis is confirmed, or a normal task fixes a bug that passed earlier gates.
143
- - Action: Declare `origin` with `task debug --debug-action origin --payload-file <json>`: `{"kind": "escape-of", "commit": "<commit>", "label": "<label>"}` (optional `"receipt"`), or `{"kind": "pre-existing" | "external", "reason": "..."}`. A normal task may opt in with `task create|revise --escape-of <commit> --escape-label <label> [--escape-receipt <id>]`. Commit the `.agent-ops-escapes/<task-id>.json` record with the fix.
144
- - Evidence: `origin` is bound into the task contract hash; finish, `task complete` and the completion gate refuse a DEBUG task created after this rule without it as `ESCAPE_ORIGIN_MISSING`; both reviewers receive the link state, labels, facts and residual risks under the `escape-label` criterion.
145
- - Positive: `Hypothesis confirmed; origin escape-of 864dbbe2 label surface; replay marks the missed page surface-unseen; the record is committed with the fix.`
146
- - Negative: `Finish a DEBUG fix without an origin, or relabel a surface-excluded miss as review because the reviewer "should have noticed".`
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 comes after a confirmed hypothesis (`ESCAPE_ORIGIN_EARLY`
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 MUST become a proven, tracked rule before its fix finishes, and learned rules MUST only tighten the surface gate.
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>` (DEBUG payload `"promote"`). Other labels record a lesson.
188
- - Evidence: Finish, `task complete` and the completion gate re-run the proof and refuse `ESCAPE_RULE_UNPROVEN`, `ESCAPE_RULE_TOO_BROAD` or `SURFACE_BUDGET_EXCEEDED`; the ledger record stores the proving rule, its content hash and its backtest fires, commits and rate.
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: `Finish a surface escape whose rule never fires on the escaped commit, or add a rule field that excludes paths.`
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 ordinary `Stop` failures remain fail-open. Active
122
- DEBUG Stop faults instead retry one targeted reload, then explicitly report
123
- UNKNOWN/incomplete and preserve the original state before non-success Stop.
124
-
125
- Codex DEBUG lifecycle semantics were rechecked on 2026-10-11 against the
126
- [official hooks reference](https://learn.chatgpt.com/docs/hooks#stop): Stop
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, DEBUG budgets and no-progress/stop
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
- With `jobs=1`, child execution MUST wait for confirmed coordinator process death.
76
- The coordinator retains its task and native session identity, and resumes under a
77
- new generation after child deliveries. Native registration, recovery and start
78
- MUST enforce at most one active agent; changing task slot accounting alone is insufficient.
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
- `init` / `update` 預設加入 `features.debug`:啟用、60 分鐘、5 輪。
4
- 之後保留明確關閉與自訂設定;舊設定和一般 task 保持相容。
3
+ DEBUG task 就是一般 task,只是驗收條件要證明原始回歸:一條 behavioral criterion,
4
+ 其 `redCheckIds` 在 baseline commit 以 assertion 失敗、在 candidate 通過。除此之外沒有任何特殊流程。
5
5
 
6
- Claude / Codex prompt hook 會保守辨識調查與修復問題,保留原始 `goal`,
7
- 建立既有隔離 task。說明、功能與重構請求照原流程。
8
- 缺少可靠 session ID,或 agy 沒有 prompt 事件時,使用原生 Agent 執行
9
- `task create --debug --goal '<原始問題>'`;只要有 native session,CLI intake
10
- 會啟動同一個前景時鐘。原始 dirty checkout 不會被自動複製。
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
- 調查用可信任的既有 command;假設用 `task debug --debug-action hypothesis
13
- --payload-file <json>`。JSON 必須含 id、statement、method、expected、checkId、
14
- expectedStatus;附 reference 才能由真實封存的 assertion 決定 confirmed/rejected。
15
- `--action investigate` 只能執行已宣告且尚未解決的 behavioral red check;
16
- `--action observe` 只能把目前相符的 runtime `UNKNOWN` receipt 記為 inconclusive。
17
- 兩者都不能由 Agent 自填 status。重開 rejected 假設需要新證據與 reason。
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
- 將暫定 criteria 改為原始問題的 behavioral 回歸,執行 verify、兩輪獨立 review,
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
- 只有原生 transcript 的人類事件能改變原 task 的範圍;CLI actor/text、assistant
28
- 訊息及注入指令都不能授權。Codex 支援目前 `response_item` 的 `user.text` 與
29
- 原生非同步回答,也保留舊 `event_msg` 格式。
27
+ ## 0.11.0 移除項目
30
28
 
31
- - `只診斷` / `diagnosis only`:繼續調查但不修產品。原始回歸的當前封存 baseline
32
- assertion FAIL 必須支持 confirmed 假設,或已有 runtime blocker/預算上限,才允許非成功停止。
33
- - `暫停` / `pause`:保存進度後立即停止。Codex 原生 `Interrupt` 也表示暫停;
34
- hook timeout 為三秒,不能阻擋或重新啟動使用者的中斷。
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
- 修復 task 標為完成;模糊文字不推測為授權,請使用上述明確指令。
34
+ 舊狀態仍可讀取:task 保留 `debug` 標記,已存的預算與假設狀態會被忽略,
35
+ `originRequired` 不再阻擋 finish,config 的 `features.debug` 仍被接受並在下次 `update` 時移除。
40
36
 
41
- 預算與輪數屬於整個原始 root,revision、child、session 不重設。新 session 重送同一個 active issue 文字時,會接回原本的 root(或 resume 持有它的 worktree),不會另開新預算。已確認或已否決的假設不能換 id、用相同陳述與方法重開;請帶新的鑑別證據重開原假設。
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)。