---
name: infinibot-orchestrator-iteration-retry
description: Add bounded retry-with-backoff to an InfiniBot autonomy orchestrator iteration loop, with audit trail and manual retry RPC.
---
# InfiniBot Orchestrator Iteration Retry

## When to use
- Adding retry to an iteration-based orchestrator loop in `src/autonomy/` where a step (builder, tester, judge) can fail transiently.
- User asks for "retry failed iteration", "iteration backoff", or "auto-retry on test fail / builder error".
- Exposing a manual retry RPC for a failed/cancelled autonomy task from the UI.

## How to apply
1. **Add policy module** at `src/autonomy/retry.ts`:
   - Export `IterationRetryPolicy` type: `{ maxRetries: number; backoffMs: number[]; retryOn: Array<"error"|"blocked"|"test_fail"> }`.
   - Export `DEFAULT_ITERATION_RETRY_POLICY` (3 retries, `[5000, 15000, 30000]`, all three retryOn reasons).
   - Export `planIterationRetry(attemptsSoFar, reason, policy)` returning `{ shouldRetry: boolean; delayMs: number; nextAttempt: number }`.
   - Export `IterationRetryRecord` type: `{ iterationIndex, attempt, reason, plannedDelayMs, at, manual?: boolean }`.
   - Add `retry.test.ts` covering: budget exhaustion, reason filtering, backoff index clamp, manual entries.
2. **Wire into orchestrator** in `src/autonomy/orchestrator.ts`:
   - After builder error OR tester FAIL, count prior retries for the current iteration index in `task.context.retries[]`.
   - Call `planIterationRetry()`. If `shouldRetry`, append a `IterationRetryRecord` to `task.context.retries`, emit an `iteration_retry` audit event, await the backoff, drop the failed iteration record from history, decrement the loop counter so the same index re-runs.
   - If retries exhausted, fall through to the existing failure path.
3. **Extend task types** in `src/autonomy/types.ts` so `context.retries: IterationRetryRecord[]` is part of the persisted task shape.
4. **Add manual retry RPC** in `src/gateway/server-methods/autonomy.ts`:
   - Method `autonomy:iteration.retry` taking `{ taskId, iterationIndex }`.
   - Append a retry record with `manual: true`, reset `status` from `failed`/`cancelled` back to `pending`, clear `failureReason`, then call `startOrchestratedTask(taskId)` (it must be idempotent).
   - Register the method in `src/gateway/server-methods-list.ts`.
5. **UI hook (optional)** in `ui/src/ui/controllers/autonomy.ts`:
   - Add `retryFailedIteration(taskId, iterationIndex)` calling the new RPC.
   - Surface retry chips in the iteration history block of the task detail modal.

## Rules
- Never retry on `cancelled` user actions or judge-rejected outcomes — only on `error`, `blocked`, or `test_fail` per policy.
- Never amend the previous iteration record in place; always drop-and-rerun so the audit trail reads as sequential attempts.
- Always store retries in `task.context.retries[]` (the persisted task), not in orchestrator-local state — survives restart.
- Always make `startOrchestratedTask` idempotent before exposing a manual retry RPC; double-invocation must not spawn parallel runners.
- Always emit an `iteration_retry` audit event for every retry (auto and manual) so the UI history view stays consistent.
- Never block the orchestrator's event loop with a synchronous sleep — use the existing async wait helper used elsewhere in `orchestrator.ts`.