feat(voyage): surface iterations_remaining signal in trekexecute
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e34082d79a
commit
65a51b2667
2 changed files with 51 additions and 0 deletions
|
|
@ -850,12 +850,24 @@ progress file.
|
|||
"steps": {
|
||||
"1": { "status": "pending", "attempts": 0, "error": null, "completed_at": null, "commit": null }
|
||||
},
|
||||
"iterations_remaining": 25,
|
||||
"entry_condition_checked": false,
|
||||
"exit_condition_checked": false,
|
||||
"summary": null
|
||||
}
|
||||
```
|
||||
|
||||
**`iterations_remaining` (v1.7+, additive-optional):** the remaining
|
||||
recovery/retry budget against the global hard cap (unit = **iterations**, per the
|
||||
brief — token/cost budgeting is out of scope). Seeded to
|
||||
`TREKEXECUTE_MAX_RECOVERY_ITERATIONS` (default 25) at start. **Single writer:** the
|
||||
executor decrements it by 1 on **every recovery/retry iteration** — each step
|
||||
attempt beyond the first, and each Phase 7.6 recovery dispatch. **Backfill-on-absent:**
|
||||
when resuming a legacy `progress.json` that lacks the field, seed it to the cap
|
||||
rather than hard-failing (forward/backward-compatible; shape-validated by
|
||||
`progress-validator.mjs` — non-negative integer, never required-top). The field is
|
||||
present in the spec at minimum — there is **no `(if wired)` conditional**.
|
||||
|
||||
### Mode-specific behavior
|
||||
|
||||
**mode = execute (fresh):**
|
||||
|
|
@ -1246,6 +1258,14 @@ Record in progress file:
|
|||
> audit ran** (never before, never in place of it). A transcript that merely
|
||||
> "feels done" is NOT a stop-signal — victory-declaration bias is the exact
|
||||
> failure mode this gate exists to defeat.
|
||||
> 3. **Counter liveness (deterministic, defeats "never decremented")** — the gate
|
||||
> reconciles the budget counter against the ground-truth counters the Phase 7.5
|
||||
> audit already derives:
|
||||
> `iterations_remaining == TREKEXECUTE_MAX_RECOVERY_ITERATIONS − (recovery_depth + Σ steps.*.attempts-beyond-first)`.
|
||||
> A field left un-decremented (or tampered) fails this reconciliation and the
|
||||
> result is OVERRIDDEN `completed → partial`, exactly as the audit-override
|
||||
> already does (`:1221`). So the counter's liveness is auditable at the gate,
|
||||
> not merely asserted in prose.
|
||||
>
|
||||
> Termination authority therefore rests on the deterministic audit + an
|
||||
> objective stop-signal, never on the model's narrative. Native `/goal` (when
|
||||
|
|
@ -1523,6 +1543,7 @@ To resume: /trekexecute --resume {path}
|
|||
"drift_details": [],
|
||||
"recovery_dispatched": false,
|
||||
"recovery_depth": 0,
|
||||
"iterations_remaining": 25,
|
||||
"legacy_plan": false,
|
||||
"progress_file": "{path}"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,3 +118,33 @@ test('trekexecute — every recovery/retry loop bounded + 3-axis cap hierarchy (
|
|||
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');
|
||||
});
|
||||
|
||||
// --- S38 loop-discipline hardening: iterations_remaining budget signal (Step 4) ---
|
||||
|
||||
test('trekexecute — iterations_remaining surfaced in progress schema + summary JSON, no (if wired) (SC c)', () => {
|
||||
const text = read();
|
||||
assert.ok(text.includes('iterations_remaining'), 'iterations_remaining must be present (SC c)');
|
||||
assert.ok(!/iterations_remaining[^\n]*\(if wired\)/.test(text),
|
||||
'no "(if wired)" conditional — field present in the spec at minimum');
|
||||
const schemaIdx = text.indexOf('### Progress file schema');
|
||||
assert.ok(schemaIdx >= 0, 'progress schema section missing');
|
||||
assert.match(text.slice(schemaIdx, schemaIdx + 1400), /iterations_remaining/,
|
||||
'progress schema must include iterations_remaining');
|
||||
const sumIdx = text.indexOf('"trekexecute_summary": {');
|
||||
assert.ok(sumIdx >= 0, 'summary JSON block missing');
|
||||
assert.match(text.slice(sumIdx, sumIdx + 900), /iterations_remaining/,
|
||||
'summary JSON must include iterations_remaining (observable)');
|
||||
});
|
||||
|
||||
test('trekexecute — iterations_remaining decrement + backfill + gate cross-check documented (SC c)', () => {
|
||||
const text = read();
|
||||
assert.match(text, /decrement[^.\n]*iteration|every recovery\/retry iteration/i,
|
||||
'decrement-per-iteration rule must be documented');
|
||||
assert.match(text, /backfill|seed (it )?to (the )?cap/i,
|
||||
'backfill-on-absent (legacy resume) rule must be documented');
|
||||
const gateIdx = text.indexOf('machine-verifiable completion gate');
|
||||
const gate = text.slice(gateIdx, gateIdx + 2200);
|
||||
assert.match(gate, /iterations_remaining/, 'gate must cross-check iterations_remaining');
|
||||
assert.match(gate, /recovery_depth/, 'gate cross-check must reconcile against recovery_depth');
|
||||
assert.match(gate, /attempts/, 'gate cross-check must reconcile against attempts');
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue