@open-agent-toolkit/cli 0.2.27 → 0.2.28

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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-phase-implementer
3
- version: 1.0.10
3
+ version: 1.0.11
4
4
  description: Implements one plan phase end-to-end, commits each task separately, self-checks between tasks, and handles bounded review fixes when resumed by oat-project-implement.
5
5
  tools: Read, Write, Edit, Bash, Grep, Glob, Task
6
6
  color: cyan
@@ -26,7 +26,7 @@ The root supplies:
26
26
 
27
27
  - `project`: active OAT project path;
28
28
  - `phase`: one phase ID;
29
- - `mode`: `implement` or `fix`;
29
+ - `mode`: `implement`, `fix`, or `recover`;
30
30
  - `artifact_paths`: available plan, design, spec, discovery, implementation,
31
31
  and imported-plan paths;
32
32
  - `workflow_mode`: `spec-driven`, `quick`, or `import`;
@@ -35,6 +35,8 @@ The root supplies:
35
35
  - `worktree`: assigned phase worktree or orchestration checkout;
36
36
  - launcher-owned dispatch policy, target, arguments, axes, selection reason,
37
37
  candidates, and formal dispatch stamp;
38
+ - `phase_recovery_limit`, `phase_recovery_attempts_used`,
39
+ `original_request_id`, and the root-resolved recovery authorization source;
38
40
  - optional `parallel_group`, `expected_base_sha`, and smoke run metadata.
39
41
 
40
42
  Fix mode also supplies:
@@ -45,8 +47,21 @@ Fix mode also supplies:
45
47
  - `original_request_id`: original phase dispatch request;
46
48
  - `continuation_event`: resume linkage for this fix attempt.
47
49
 
50
+ Recover mode also supplies:
51
+
52
+ - `original_request_id` and `continuation_event`;
53
+ - `recovery_base_head`, `original_task_id`, and immutable `original_commit`;
54
+ - `defect_class`, `discovered_by`, `bounded_correction_scope`, and
55
+ `bounded_files`;
56
+ - `phase_recovery_limit`, `phase_recovery_attempts_used`, and the authoritative
57
+ `pending_attempt` ledger entry;
58
+ - `focused_verification` and `phase_verification`; and
59
+ - the exact original `dispatch_target` plus launcher-owned axes and stamp.
60
+
48
61
  Reject a missing/unknown phase, an unrecognized mode, a base mismatch, or a
49
- fix request without bounded findings.
62
+ fix request without bounded findings. Reject recover mode when any recover input
63
+ is absent, the continuation does not link to the original request, or the
64
+ pending attempt cannot be reconciled.
50
65
 
51
66
  ## Shared Dispatch Contract
52
67
 
@@ -101,6 +116,195 @@ After formatting, run the repository's applicable gate set over the produced
101
116
  diff, explicitly including artifact writes. This supplements rather than
102
117
  replaces every task and phase verification command below.
103
118
 
119
+ ## Prevention and Post-Commit Recovery
120
+
121
+ Prevention is the first recovery control. Before every planned task commit:
122
+
123
+ 1. format every changed file;
124
+ 2. run the declared task verification;
125
+ 3. run every repository-discovered cheap check applicable to the changed
126
+ surface when it is discoverable and proportionate; and
127
+ 4. when a task changes emitted output, build/test configuration, packaging, or
128
+ equivalent behavior, run the discoverable scoped build or test before
129
+ commit when its cost is proportionate.
130
+
131
+ Run those checks in that order before commit. Broad repository tests or builds
132
+ may remain phase-level when running them per task is disproportionate.
133
+ Corrections completed before the planned task commit are prevention and do not
134
+ consume a phase recovery attempt.
135
+
136
+ When a task-transition or phase check discovers a post-commit failure, classify
137
+ it before editing. Automatic recovery is allowed only when all conditions hold:
138
+
139
+ - the failure is an obvious in-scope lint, type, test, build, or composition
140
+ defect discovered by declared task, transition, or phase verification;
141
+ - the correction is mechanically bounded and unambiguous, remains within phase
142
+ intent and public requirements, and any file-boundary expansion is
143
+ mechanically derived and in-phase;
144
+ - architecture, security, product scope, requirements, and public behavior do
145
+ not change;
146
+ - the work is non-destructive, reversible, and does not cross credential,
147
+ protected-branch, or other consequential boundaries;
148
+ - the exact target remains unchanged and bindable regardless of handle state
149
+ and stays equal to the launcher-owned dispatch target;
150
+ - handle continuity follows one of the authorized alternatives below;
151
+ - attempt accounting follows one of the authorized alternatives below; and
152
+ - focused plus relevant phase verification can establish correctness.
153
+
154
+ Handle and exact-target continuity use these mutually compatible branches:
155
+
156
+ 1. When the accepted handle is available or resumable, use same-handle
157
+ continuation.
158
+ 2. When the accepted handle is unavailable or unresumable, an unchanged,
159
+ bindable exact target plus a lifecycle-authorized recover scope, a reconciled
160
+ pending attempt, and continuation linkage authorizes fresh `mode: recover`.
161
+ 3. A lost or unbindable exact target requires a direction-required stop with no
162
+ fallback.
163
+
164
+ Handle unavailability alone does not make automatic recovery ineligible or
165
+ stop it. It selects the second branch only when all its conditions hold.
166
+
167
+ Attempt accounting uses exactly one of these alternatives:
168
+
169
+ 1. **Pending completion:** a matching `pending_attempt` may continue only after
170
+ complete reconciliation of the authoritative ledger, original request,
171
+ immutable original commit at the same history position, bounded worktree
172
+ diff, and unchanged exact target. Continue and finish that same reserved
173
+ attempt without incrementing `used_attempts` or creating another
174
+ reservation, even when the existing count equals the limit.
175
+ 2. **New reservation:** when no `pending_attempt` exists,
176
+ `phase_recovery_attempts_used < phase_recovery_limit` is mandatory. Atomically
177
+ increment usage and write the new reservation before editing.
178
+
179
+ For the final-attempt boundary, `limit=1`, `used=1`, and a fully reconciled
180
+ matching `pending_attempt` continue and finish the same reserved attempt
181
+ without incrementing usage. With `limit=1`, `used=1`, and no `pending_attempt`,
182
+ stop direction-required before edit with no new reservation and no fallback.
183
+
184
+ Record the eligibility evidence before editing. A new reservation consumes one
185
+ attempt before editing; continuation of a reconciled pending attempt does not
186
+ consume another. Apply the bounded correction and run the focused and phase
187
+ checks before creating a candidate commit. If either check fails, restore the
188
+ bounded files to their original committed content without rewriting history,
189
+ atomically mark the reservation `failed`, durably commit only that ledger
190
+ transition, and stop. When both checks pass, atomically mark the reservation
191
+ `completed` and create one append-only candidate recovery commit containing the
192
+ bounded correction plus that transition.
193
+
194
+ Immediately rerun the focused and phase checks against the committed HEAD.
195
+ These post-commit reruns are the authoritative recovery result. On pass, the
196
+ candidate is the successful recovery commit. On failure, atomically replace the
197
+ `completed` marker with `failed`, durably commit that ledger-only transition,
198
+ preserve the candidate commit as immutable, claim no successful recovery
199
+ commit, and stop. Any failed edit, commit, or re-verification leaves the attempt
200
+ consumed. Preserve the accepted task commit at the same history position; never
201
+ amend, reset, rebase, squash, replace its task ID, or conceal it. Mechanically
202
+ related failures from the same verification command may use one atomic attempt
203
+ and successful recovery commit. Independent failures require separate attempts.
204
+ At three recovery events, report an elevated recovery-volume warning but
205
+ continue while the predicate and budget remain valid.
206
+
207
+ A suspected infrastructure or flake failure permits one no-edit rerun without
208
+ attempt consumption. If the repeated unexplained failure remains ambiguous,
209
+ stop without editing. Never turn contradictory evidence into a speculative
210
+ repair.
211
+
212
+ Stop with `DONE_WITH_CONCERNS` or `BLOCKED`, do not edit, and request direction
213
+ for any ambiguous or contradictory case; architecture, security, product, or
214
+ requirements decision; non-mechanical boundary widening; destructive,
215
+ irreversible, credential-bearing, or protected-branch work; retry exhaustion;
216
+ dirty worktree or dirty history; inability to establish correctness; missing
217
+ original-request or missing exact-target provenance; unverifiable commit range;
218
+ malformed recovery event; exact-target loss; or governance cap. No stop
219
+ condition authorizes fallback or another model, provider, route, or worker.
220
+
221
+ Every post-commit disposition returns exactly one canonical recovery event,
222
+ including recovered, direction-required, and failed-attempt outcomes. The event
223
+ must preserve original request, original commit, defect class, discovering
224
+ check, disposition, authorization, attempt/budget, dispatch target, recovery
225
+ commit when one exists, verification outcome, and reason. This allows defect
226
+ count, prompt count, and successful repair count to remain independently
227
+ measurable.
228
+
229
+ A `direction-required` disposition reached before any reservation leaves
230
+ `pending_attempt: null`, does not increment `used_attempts`, and performs no
231
+ edit or recovery commit. Its event carries the stop-boundary evidence so root
232
+ can validate and record the terminal stop without expecting a `completed` or
233
+ `failed` marker.
234
+
235
+ ### Authoritative Attempt Ledger
236
+
237
+ The active project's
238
+ `oat_phase_recovery_policy.phase_attempt_usage.<pNN>` entry in `state.md` is the
239
+ one authoritative durable per-phase attempt ledger. The phase implementer has a
240
+ narrow exception to root-owned bookkeeping: while it owns the worktree, it may
241
+ atomically replace only that ledger entry. It must not alter any other project
242
+ tracking field.
243
+
244
+ Before the first code edit for a new recovery attempt, atomically increment
245
+ `used_attempts` and write `pending_attempt` with the attempt number, event ID,
246
+ original request, original task/commit, discovering check, exact target, and
247
+ reservation HEAD. This reservation happens before editing and survives
248
+ interruption. Never decrement or reset `used_attempts`.
249
+
250
+ On same-handle resume or recover mode, reconcile the supplied nonzero
251
+ `used_attempts` and `pending_attempt` against `state.md`, Git history, and the
252
+ bounded worktree diff. Complete reconciliation includes the ledger identities,
253
+ original request, immutable original commit at the same history position,
254
+ bounded diff, and unchanged exact target. Continue the same attempt without
255
+ consuming another attempt. Reject an unreconciled resume before further
256
+ editing. A new attempt is exhausted when `used_attempts` is equal to or greater
257
+ than `phase_recovery_limit`; an already-pending matching attempt may only finish
258
+ or fail and does not receive another reservation.
259
+
260
+ Run focused and phase checks before a candidate commit. A pre-commit failure
261
+ restores the bounded files and commits only the `failed` transition. A
262
+ pre-commit pass atomically marks the pending entry `completed` and creates the
263
+ candidate recovery commit with the bounded code change plus that transition.
264
+ Immediately rerun both checks against committed HEAD. Those reruns are
265
+ authoritative: a pass leaves the committed `completed` marker for root
266
+ validation, while a failure atomically replaces it with `failed` in a separate
267
+ ledger-only evidence commit and claims no successful recovery commit. If any
268
+ required terminal marker cannot be committed, preserve the working tree and
269
+ report the attempt as unreconciled; root must fail closed without bookkeeping.
270
+
271
+ The final matching committed `completed` or `failed` marker is the committed
272
+ pre-bookkeeping terminal handoff for an attempted recovery. A report of
273
+ `recovered` or `failed-attempt` returns with that marker still present. A
274
+ pre-attempt `direction-required` report instead returns with
275
+ `pending_attempt: null`, unchanged usage, and evidence of no reservation, edit,
276
+ or recovery commit. An active, mismatched, prematurely cleared, unreconciled,
277
+ or contradictory attempted-recovery marker must fail closed before root
278
+ bookkeeping. Root clears an attempted-recovery marker only after validating the
279
+ report, immutable original history, exact target and axes, canonical event,
280
+ attempt count, recovery commit when successful, and authoritative focused plus
281
+ phase verification. Root records a valid pre-attempt `direction-required`
282
+ event without clearing a marker. Clearing always retains monotonic
283
+ `used_attempts`; failed attempts also preserve their terminal-stop disposition.
284
+ Only the post-bookkeeping null state is settled for an attempted recovery.
285
+
286
+ ### Canonical Recovery Event
287
+
288
+ Emit this exact heading, label order, and enum vocabulary for every post-commit
289
+ disposition:
290
+
291
+ ```markdown
292
+ ### Recovery Event {event-id}
293
+
294
+ - Phase/task: {phase and originating task when known}
295
+ - Original request: {original_request_id}
296
+ - Original commit: {immutable task commit}
297
+ - Defect class: lint | type | test | build | composition | other
298
+ - Discovered by: {exact verification command or transition check}
299
+ - Disposition: recovered | direction-required | failed-attempt
300
+ - Authorization: phase-standing | operator-extension | operator-scope
301
+ - Attempt: {used}/{phase_recovery_limit}
302
+ - Dispatch target: {exact launcher-owned implementation target}
303
+ - Recovery commit: {sha or -}
304
+ - Verification: {focused and relevant phase result}
305
+ - Reason: {eligibility or stop-boundary evidence}
306
+ ```
307
+
104
308
  ## Mode: Implement
105
309
 
106
310
  ### 1. Verify Phase Base
@@ -125,7 +329,12 @@ For every task:
125
329
  3. Follow RED/GREEN/refactor ordering when specified.
126
330
  4. Implement only that task. Optional nested help does not transfer task
127
331
  ownership or commit authority.
128
- 5. Run every task verification command.
332
+ 5. Apply the Prevention and Post-Commit Recovery ordering: format, run every
333
+ declared task verification, run applicable discoverable proportionate cheap
334
+ checks, and, for emitted output or build/test configuration changes, run a
335
+ scoped build/test before commit. Broad repository tests and builds may stay at
336
+ the phase boundary when per-task execution is disproportionate. This
337
+ prevention does not consume a recovery attempt.
129
338
  6. Self-review requirements, behavioral tests, scope, and accidental changes.
130
339
  7. Fix any issue before committing.
131
340
  8. Create exactly one task commit using `commit_convention`.
@@ -139,8 +348,9 @@ For every task:
139
348
  - every task verification passed; and
140
349
  - the worktree is clean.
141
350
  10. Perform a brief between-task transition check before starting the next
142
- task. If the committed task is defective, stop with `DONE_WITH_CONCERNS` or
143
- `BLOCKED`; do not amend, add an unplanned task commit, or conceal it.
351
+ task. If the committed task is defective, apply the post-commit eligibility,
352
+ accounting, append-only recovery, event, and stop contract above. Never
353
+ amend or conceal the task commit.
144
354
 
145
355
  Do not skip, reorder, combine, or split planned task commits.
146
356
 
@@ -149,6 +359,8 @@ Do not skip, reorder, combine, or split planned task commits.
149
359
  After all task commits:
150
360
 
151
361
  - run phase-wide verification;
362
+ - apply the same post-commit recovery contract to an eligible phase-level
363
+ composition failure;
152
364
  - verify task outputs compose correctly;
153
365
  - compare the phase result with design/spec/discovery;
154
366
  - confirm no task boundary or dependency was missed; and
@@ -166,10 +378,12 @@ report.
166
378
  **Phase:** {phase-id}
167
379
  **Tasks executed:** {N} of {N}
168
380
  **Phase base:** {sha}
381
+ **Final head:** {sha}
169
382
  **Commits:** {first sha}..{last sha}
383
+ **Recovery attempts:** {used}/{phase_recovery_limit}
170
384
  **Phase verification:** pass | fail
171
385
  **Confidence:** high | medium | low
172
- **Request ID:** {request_id}
386
+ **Request ID:** {original_request_id}
173
387
  **Dispatch target:** {launcher-owned target}
174
388
  **Dispatch stamp:** {formal Dispatch: line}
175
389
 
@@ -179,6 +393,10 @@ report.
179
393
  | ------- | ------ | ------ | ------------ | --------------- |
180
394
  | pNN-tNN | done | {sha} | pass | {bounded files} |
181
395
 
396
+ ### Recovery Events
397
+
398
+ - {None, or exactly one canonical event per recovered, direction-required, or failed-attempt disposition}
399
+
182
400
  ### Optional Nested Dispatches
183
401
 
184
402
  - {None, or request ID / bounded purpose / exact target / terminal outcome}
@@ -192,6 +410,93 @@ report.
192
410
  - {None or concise reason/evidence}
193
411
  ```
194
412
 
413
+ ## Mode: Recover
414
+
415
+ Recover mode is a continuation of a post-commit recovery attempt already
416
+ authorized when the original accepted handle cannot resume. It is not phase
417
+ implementation, review-fix mode, fallback, or replay.
418
+
419
+ Require this self-contained Recover Scope:
420
+
421
+ ```yaml
422
+ mode: recover
423
+ original_request_id: { original phase request }
424
+ continuation_event: { generic continuation_events identifier }
425
+ recovery_base_head: { current immutable Git HEAD }
426
+ original_task_id: { originating planned task }
427
+ original_commit: { immutable task commit }
428
+ defect_class: { lint|type|test|build|composition|other }
429
+ discovered_by: { exact command or transition check }
430
+ bounded_correction_scope: { mechanical correction only }
431
+ bounded_files: { declared or mechanically derived in-phase files }
432
+ phase_recovery_limit: { resolved total limit }
433
+ phase_recovery_attempts_used: { authoritative nonzero used count }
434
+ pending_attempt: { matching authoritative ledger entry }
435
+ focused_verification: { exact failing check }
436
+ phase_verification: { relevant phase command }
437
+ dispatch_target: { exact original launcher-owned target }
438
+ dispatch_axes: { unchanged original launcher-owned axes }
439
+ dispatch_stamp: { original formal Dispatch line }
440
+ ```
441
+
442
+ 1. Validate every recover input. Confirm the exact launcher-owned target equals
443
+ the original target and the generic `continuation_events` record links
444
+ `continuation_event` to `original_request_id`.
445
+ 2. Confirm HEAD exactly equals `recovery_base_head`; the `original_commit`
446
+ remains immutable at the same history position; and the worktree contains
447
+ only the reconciled pending ledger reservation plus an optional mechanically
448
+ bounded diff inside `bounded_files`. Any other dirt or history change
449
+ blocks.
450
+ 3. Reconcile the authoritative `pending_attempt` and nonzero
451
+ `phase_recovery_attempts_used` with `state.md`. Recover mode continues that
452
+ same consumed attempt and must not increment usage again. Missing,
453
+ contradictory, or unreconciled state blocks before editing.
454
+ 4. Apply or complete only `bounded_correction_scope`. Recover mode must not
455
+ replay planned tasks and must not require, fabricate, or consume a review
456
+ artifact.
457
+ 5. Apply the bounded correction, then run `focused_verification` and
458
+ `phase_verification` before creating a candidate commit. If either check
459
+ fails, restore `bounded_files` to their original committed content,
460
+ atomically mark the pending entry `failed`, durably commit only that
461
+ ledger transition, emit one `failed-attempt` event, and stop.
462
+ 6. When both pre-commit checks pass, atomically mark the pending entry
463
+ `completed` and create one append-only candidate recovery commit containing
464
+ only `bounded_files` plus that ledger transition.
465
+ 7. Immediately rerun `focused_verification` and `phase_verification` against the
466
+ committed HEAD; these reruns are authoritative. On pass, emit one `recovered`
467
+ event and report the candidate as the successful recovery commit. On
468
+ failure, atomically replace `completed` with `failed`, durably commit that
469
+ ledger-only transition, emit one `failed-attempt` event, preserve the
470
+ consumed attempt and immutable candidate, and claim no successful recovery
471
+ commit. If terminal evidence cannot be committed, report an unreconciled
472
+ block that root must reject before bookkeeping. Never amend history or
473
+ launch fallback.
474
+ 8. Return the report below. `DONE` is accepted success;
475
+ `DONE_WITH_CONCERNS` and `BLOCKED` may be accepted terminal stops and must
476
+ still report provenance, accounting, immutable history, and the event.
477
+
478
+ ```markdown
479
+ ## Phase Recovery Continuation Report
480
+
481
+ **Status:** DONE | DONE_WITH_CONCERNS | BLOCKED
482
+ **Phase:** {phase-id}
483
+ **Original request ID:** {original_request_id}
484
+ **Continuation event:** {continuation_event}
485
+ **Recovery base:** {recovery_base_head}
486
+ **Original task/commit:** {original_task_id} / {original_commit}
487
+ **Attempt:** {phase_recovery_attempts_used}/{phase_recovery_limit}
488
+ **Dispatch target:** {same exact launcher-owned target}
489
+ **Dispatch stamp:** {original formal Dispatch line}
490
+ **Pending handoff:** {completed|failed}
491
+ **Recovery commit:** {sha or -}
492
+ **Verification:** {focused result}; {phase result}
493
+ **Recovery event:** {event-id}
494
+
495
+ ### Concerns or Block
496
+
497
+ - {None or bounded terminal-stop evidence}
498
+ ```
499
+
195
500
  ## Mode: Fix
196
501
 
197
502
  Fix mode is a continuation of a successfully completed phase, not a replay.
@@ -16,6 +16,10 @@ and updates project state.
16
16
  in dependency order.
17
17
  - **Task boundary:** each task still produces exactly one bounded, verified
18
18
  commit.
19
+ - **Prevention boundary:** formatting, declared task verification, and
20
+ applicable cheap checks run before the task commit.
21
+ - **Recovery boundary:** an eligible post-commit defect may produce a separate
22
+ same-target recovery commit under the phase's bounded recovery authority.
19
23
  - **Review boundary:** the root dispatches one independent reviewer after the
20
24
  phase report.
21
25
  - **Fix boundary:** blocking findings return to the original phase handle when
@@ -78,7 +82,138 @@ once, and directly executes each task in plan order. For every task it:
78
82
  6. verifies the commit, file boundary, tests, and clean worktree.
79
83
 
80
84
  After all tasks, it runs phase-wide verification and returns a compact report.
81
- It does not dispatch the phase reviewer or mutate project bookkeeping.
85
+ It does not dispatch the phase reviewer or mutate general project bookkeeping.
86
+ While it owns the worktree, it may atomically update only the active phase's
87
+ authoritative `oat_phase_recovery_policy.phase_attempt_usage.<pNN>` entry. The
88
+ phase returns with a matching committed `completed` or `failed` terminal marker
89
+ still present. The root validates that marker against the report, recovery
90
+ event, immutable history, attempt accounting, exact target, and verification
91
+ before clearing it. Only the post-validation null marker is the settled ledger
92
+ state; a premature clear or contradictory marker fails closed.
93
+
94
+ ## Prevent Defects Before Commit
95
+
96
+ Prevention is the first recovery control. Before each planned task commit, the
97
+ phase implementer runs checks in this order:
98
+
99
+ 1. format every changed file;
100
+ 2. run the task's declared verification;
101
+ 3. run every repository-discovered cheap check that applies to the changed
102
+ surface and is proportionate to the task; and
103
+ 4. run a discoverable scoped build or test when the task changes emitted
104
+ output, build or test configuration, packaging, or equivalent behavior.
105
+
106
+ Broad repository tests and builds may remain phase-level when running them for
107
+ every task would be disproportionate. These broader checks verify that the
108
+ phase's task outputs compose correctly. A correction made before the planned
109
+ task commit is prevention and does not consume a recovery attempt.
110
+
111
+ ## Recover After Commit
112
+
113
+ When declared task, transition, or phase verification finds a post-commit
114
+ defect, OAT classifies it before editing. Automatic recovery proceeds only when
115
+ the correction is mechanically bounded, unambiguous, in phase, non-destructive,
116
+ and verifiable, and when the exact launcher-owned implementation target and
117
+ original-request provenance remain intact. Architecture, security, product,
118
+ requirements, public-behavior, credential, protected-branch, destructive, or
119
+ non-mechanical scope changes require operator direction.
120
+
121
+ The accepted task commit remains immutable. For an eligible defect, the phase
122
+ implementer reserves an attempt in the authoritative phase ledger, applies the
123
+ bounded correction, and runs focused and phase checks before a candidate commit.
124
+ After those checks pass, the implementer commits the correction with a
125
+ `completed` pre-bookkeeping marker and immediately reruns both checks against
126
+ the committed HEAD. Those post-commit reruns are authoritative. A pass makes
127
+ the candidate the successful recovery commit; a failure durably transitions the
128
+ marker to `failed` in ledger-only terminal evidence and stops without claiming
129
+ a successful recovery. Mechanically related failures from one verification
130
+ command may share one atomic attempt and successful commit; independent defects
131
+ require separate attempts.
132
+
133
+ Append-only history protects accepted work by requiring a new, auditable commit;
134
+ it does not require repeated approval for a mechanical repair already covered
135
+ by the phase's standing authority. The important distinctions are:
136
+
137
+ - a **defect** is a post-commit failure discovered by declared verification;
138
+ - an **authorization prompt** is required only at a direction-required
139
+ boundary, not for every eligible defect;
140
+ - a **continuation** preserves the original request and exact target, either in
141
+ the accepted handle or through an explicitly linked fresh same-target
142
+ recovery launch; and
143
+ - a **successful repair** produces one immutable append-only recovery commit.
144
+
145
+ This recovery is not accepted-launch fallback. After a launch is accepted,
146
+ completion, failure, timeout, interruption, `BLOCKED`, or contract refusal never
147
+ makes another model, provider, route, or worker eligible. A fresh launch is
148
+ permitted only when the caller-specific lifecycle contract already authorized
149
+ bounded recovery, the accepted handle cannot resume, the exact original target
150
+ remains bindable, a pending attempt is reconciled, and the existing
151
+ `continuation_events` record links it to the original request.
152
+
153
+ ### Recovery Budget
154
+
155
+ `oat_phase_recovery_policy` is dedicated to implementation recovery and is
156
+ independent of `oat_orchestration_retry_limit`, which continues to govern
157
+ review-fix and gate loops. The project default is `10` attempts per phase.
158
+ Project defaults and phase-specific overrides accept integers from `0` through
159
+ `20`; `0` disables automatic post-commit repair for that scope.
160
+
161
+ Attempt usage is monotonic and durable per phase. A new attempt is consumed
162
+ before the bounded edit begins, so a failed edit, commit, or re-verification
163
+ cannot retry for free. An already-reconciled pending attempt may finish without
164
+ another reservation, even when usage equals the limit. Evidence of an
165
+ infrastructure or flaky failure permits one no-edit rerun without consuming an
166
+ attempt; a repeated unexplained failure is ambiguous and stops without editing.
167
+ A direction-required boundary reached before reservation leaves the pending
168
+ marker null and usage unchanged, emits its required event, and records no edit
169
+ or recovery commit.
170
+
171
+ At three recovery events, the phase report warns about elevated recovery volume
172
+ but may continue while every eligibility condition and the budget remain valid.
173
+ At exhaustion, OAT stops for one explicit operator outcome:
174
+
175
+ 1. **Add N attempts:** set that phase's total limit to `used_attempts + N`,
176
+ capped at `20`, without resetting prior usage.
177
+ 2. **Authorize changed scope:** record a separate consequential or
178
+ scope-expanding action outside automatic recovery.
179
+ 3. **Stop:** preserve the worktree, immutable history, and evidence.
180
+
181
+ ### Recovery Event
182
+
183
+ Every recovered, direction-required, or failed-attempt disposition emits
184
+ exactly one event with this heading, label order, and vocabulary:
185
+
186
+ ```markdown
187
+ ### Recovery Event {event-id}
188
+
189
+ - Phase/task: {phase and originating task when known}
190
+ - Original request: {original_request_id}
191
+ - Original commit: {immutable task commit}
192
+ - Defect class: lint | type | test | build | composition | other
193
+ - Discovered by: {exact verification command or transition check}
194
+ - Disposition: recovered | direction-required | failed-attempt
195
+ - Authorization: phase-standing | operator-extension | operator-scope
196
+ - Attempt: {used}/{phase_recovery_limit}
197
+ - Dispatch target: {exact launcher-owned implementation target}
198
+ - Recovery commit: {sha or -}
199
+ - Verification: {focused and relevant phase result}
200
+ - Reason: {eligibility or stop-boundary evidence}
201
+ ```
202
+
203
+ The event ledger keeps defect volume, authorization-prompt volume, continuation
204
+ volume, and successful repair commits measurable as separate facts. A failed
205
+ attempt still produces one event even when it produces no recovery commit.
206
+
207
+ ### Pre-Change Baseline
208
+
209
+ The recorded pre-change baseline is nine recovery events plus two
210
+ operator-recovery continuations. Known failures included lint, composition, and
211
+ test-fixture defects; exact per-class counts are unavailable. The repeated
212
+ prompts exposed a latent policy under integration-heavy verification rather
213
+ than a recent regression. In particular, PR #176 changed phase-base anchoring
214
+ and is explicitly excluded from causation: the root still captures a fresh
215
+ phase base immediately before each launch, so earlier recovery commits are
216
+ already part of the next phase's base.
82
217
 
83
218
  ### Phase reviewer
84
219
 
@@ -155,6 +290,21 @@ Only an allowed and fresh gate disposition can enter the pre-approval sequence,
155
290
  cross final HiLL, run the post-approval sequence, mark implementation complete,
156
291
  or emit success.
157
292
 
293
+ ## Update Installed Recovery Contracts
294
+
295
+ Bounded phase recovery ships in OAT `0.2.28`. After upgrading to that release or
296
+ later, update the installed OAT tools and then regenerate provider views from
297
+ the canonical contracts:
298
+
299
+ ```bash
300
+ oat tools update
301
+ oat sync --scope all
302
+ ```
303
+
304
+ Run the commands in that order before expecting global Claude, Codex, or Cursor
305
+ phase agents to use the new contract. Provider assets are generated views, not
306
+ independently maintained policy forks.
307
+
158
308
  ## Phase Scope
159
309
 
160
310
  The root supplies one scope for the whole phase:
@@ -1,6 +1,6 @@
1
1
  {
2
- "cli": "0.2.27",
3
- "docs-config": "0.2.27",
4
- "docs-theme": "0.2.27",
5
- "docs-transforms": "0.2.27"
2
+ "cli": "0.2.28",
3
+ "docs-config": "0.2.28",
4
+ "docs-theme": "0.2.28",
5
+ "docs-transforms": "0.2.28"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-dispatch-subagents
3
- version: 1.2.1
3
+ version: 1.2.2
4
4
  description: Use when an OAT skill or workflow needs provider-neutral selection, launch, recovery, or evidence for bounded subagent work without project lifecycle policy.
5
5
  disable-model-invocation: true
6
6
  user-invocable: false
@@ -385,18 +385,31 @@ a declared class floor.
385
385
  - An accepted launch is terminal for automatic replacement eligibility.
386
386
  - Completion, failure, timeout, interruption, `BLOCKED`, and contract refusal
387
387
  are post-acceptance outcomes; none makes another route eligible.
388
+ - Automatic route, model, provider, or worker replacement after acceptance is
389
+ forbidden fallback. No post-acceptance outcome makes another route eligible.
388
390
  - A wrapper failure or payload rejection before child start is a pre-start
389
391
  rejection. A new recorded selection is allowed only within caller retry
390
392
  policy.
391
393
  - Continuing the same accepted child through its valid handle is allowed.
392
394
  Record continuation separately and preserve selectors and route.
395
+ - Same-target bounded recovery is a continuation rather than fallback only when
396
+ a caller-specific lifecycle contract explicitly authorizes it. That contract
397
+ must supply the bounded scope, exact target, numeric budget, canonical
398
+ recording, and stop conditions before launch. It may allow either
399
+ continuation through the accepted handle or an explicitly linked fresh
400
+ same-target launch when the original handle cannot be resumed.
401
+ - Standing recovery authority is default-deny. `oat-project-implement` may
402
+ establish it through its complete caller-specific lifecycle contract; wave
403
+ execution, autonomous projects, cloud-project orchestration, reviewers, and
404
+ every other consumer remain outside that grant unless their own future
405
+ contract independently defines the complete boundary.
406
+ - Scope-expanding or consequential recovery requires new operator direction.
407
+ The same applies to ambiguous, destructive, or retry-exhausted work.
393
408
  - A caller may cancel accepted handles only after it proves that the enclosing
394
409
  run itself is invalid under caller-owned containment or integrity policy.
395
410
  Record `invalid-run-abort` and the invalidating evidence. Cancellation never
396
411
  makes another route eligible and never authorizes replacement, fallback, or
397
412
  a successful child outcome.
398
- - Operator-authorized recovery is a new explicit action, never automatic
399
- fallback.
400
413
  - Runtime identity is optional corroboration. Missing runtime identity does not
401
414
  invalidate launcher-owned configured invocation evidence.
402
415