feat(voyage): document recovery/retry iteration caps in trekexecute
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d2f9ccb690
commit
e34082d79a
2 changed files with 64 additions and 0 deletions
|
|
@ -1298,6 +1298,38 @@ Status: partial (recovery_depth=2, escalated to user)
|
|||
|
||||
Do NOT dispatch a third recovery. Report to the user.
|
||||
|
||||
### Iteration caps + global recovery/retry budget
|
||||
|
||||
Every recovery/retry loop in this executor has a documented numeric bound.
|
||||
These are **three distinct axes** — not one nested counter — plus a separate
|
||||
child turn cap:
|
||||
|
||||
- **Per-step retry cap** — `attempts ≤ 3` (initial + **maximum 2 retries**;
|
||||
Hard Rule 5 / Sub-step E). Bounds the retries of a *single* step.
|
||||
- **Per-session recovery cap** — `recovery_depth < 2` (Phase 7.6 hard cap).
|
||||
Bounds how deep recovery *dispatch* nests.
|
||||
- **Global recovery/retry budget** — a new env-overridable constant
|
||||
`TREKEXECUTE_MAX_RECOVERY_ITERATIONS` (default **25**) — the aggregate ceiling
|
||||
on the **total count of recovery + retry iterations across the whole
|
||||
execution**. This is the case the two caps above do NOT bound: many steps each
|
||||
retrying up to 3× can sum unbounded. It primarily backstops the **retry
|
||||
aggregate** (recovery dispatch is already hard-capped at 2). Surfaced and
|
||||
enforced via the `iterations_remaining` counter (Phase 3 schema; decremented
|
||||
on every recovery/retry iteration; reconciled at the Phase 7.5 completion
|
||||
gate).
|
||||
- **Child turn cap** — `--max-turns` (`TREKEXECUTE_MAX_TURNS`, default 50)
|
||||
bounds model turns inside a single `-p` child; a *different* axis from the
|
||||
three above.
|
||||
|
||||
Default **25** is an independent value from the cap research (practitioner range
|
||||
10–50; OWASP Agentic ASI08 financial-DoS), tuned down from the research ~50
|
||||
starting point for a tighter backstop. It is **not** a reconciliation with
|
||||
`--max-turns` (50) — the axes are incomparable. Operators may override:
|
||||
`TREKEXECUTE_MAX_RECOVERY_ITERATIONS=10 /trekexecute --project ...`. The
|
||||
`effort=='low'` single-foreground-loop path and the wave path are both subject to
|
||||
this aggregate ceiling; it is an execution-spec ceiling (enforced via the
|
||||
`iterations_remaining` counter), not a code-loop edit.
|
||||
|
||||
## Phase 8 — Final report
|
||||
|
||||
Always produce a final report.
|
||||
|
|
@ -1698,3 +1730,10 @@ code-path.
|
|||
cleanup proceeds regardless. Rationale: this converts an unrecoverable
|
||||
failure (worktree removed, branch deleted, work lost) into a recoverable
|
||||
one (push succeeded, branch preserved on remote). Source: research/02 R3.
|
||||
|
||||
20. **Three distinct iteration axes.** Per-step `attempts` (≤3), per-session
|
||||
`recovery_depth` (<2), and the global `TREKEXECUTE_MAX_RECOVERY_ITERATIONS`
|
||||
budget (default 25 — aggregate recovery+retry backstop) are independent
|
||||
bounds, not one nested counter; child `--max-turns` (50) is a fourth,
|
||||
separate axis. Every recovery/retry loop is bounded by at least one of them.
|
||||
See "Iteration caps + global recovery/retry budget".
|
||||
|
|
|
|||
|
|
@ -93,3 +93,28 @@ test('trekexecute — completion gate anchors result:completed to Phase 7.5 audi
|
|||
assert.match(section, /DONE/, 'gate must reference the DONE stop-signal token');
|
||||
assert.match(section, /emitted AFTER/, 'gate must require DONE emitted AFTER the audit ran');
|
||||
});
|
||||
|
||||
// --- S38 loop-discipline hardening: caps + global recovery budget (Step 3) ---
|
||||
|
||||
test('trekexecute — global recovery/retry budget TREKEXECUTE_MAX_RECOVERY_ITERATIONS default 25 (SC b)', () => {
|
||||
const text = read();
|
||||
assert.ok(text.includes('TREKEXECUTE_MAX_RECOVERY_ITERATIONS'),
|
||||
'global recovery/retry budget constant must be documented');
|
||||
assert.match(
|
||||
text,
|
||||
/TREKEXECUTE_MAX_RECOVERY_ITERATIONS[^\n]{0,40}\b25\b|default[^\n]{0,20}\b25\b[^\n]{0,40}aggregate/i,
|
||||
'global budget must document numeric default 25 adjacent to the constant',
|
||||
);
|
||||
});
|
||||
|
||||
test('trekexecute — every recovery/retry loop bounded + 3-axis cap hierarchy (SC b)', () => {
|
||||
const text = read();
|
||||
assert.match(text, /maximum 2 retries|Retry cap = 3 attempts/, 'per-step retry cap must be explicit');
|
||||
assert.match(text, /recovery_depth < 2/, 'recovery-dispatch cap must be explicit');
|
||||
const capIdx = text.indexOf('Iteration caps');
|
||||
assert.ok(capIdx >= 0, 'cap-hierarchy section ("Iteration caps") must exist');
|
||||
const section = text.slice(capIdx, capIdx + 1500);
|
||||
assert.match(section, /attempts/, 'hierarchy must name per-step attempts axis');
|
||||
assert.match(section, /recovery_depth/, 'hierarchy must name per-session recovery_depth axis');
|
||||
assert.match(section, /TREKEXECUTE_MAX_RECOVERY_ITERATIONS/, 'hierarchy must name the global budget axis');
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue