Files
kandev/docs/specs/office/requirements/runtime.md
T

5.2 KiB

status, system, created, owners
status system created owners
draft office 2026-05-04
cfl

Office Agent Runtime — Error Handling Contract Requirements

Overview

When an agent run fails mid-turn (invalid model, auth failure, malformed response, transient upstream), the failed wakeup is terminal — except a classified-transient failure on the legacy (non-routing) post-start path, which is retried a bounded number of times before it counts as a terminal failure (AC-OFFICE-RUNTIME-001.11). The workflow engine can still evaluate a configured on_agent_error action and queue a separate coordinator run for escalation.

Requirements

REQ-OFFICE-RUNTIME-001: Office Agent Runtime — Error Handling Contract

Intent: When an agent run fails mid-turn (invalid model, auth failure, malformed response, transient upstream), the failed agent run is terminal, except the bounded classified-transient retry carved out by AC-OFFICE-RUNTIME-001.11. A workflow can use on_agent_error to queue a separate coordinator run for escalation.

Acceptance criteria

  • AC-OFFICE-RUNTIME-001.1: No automatic retry of the failed agent run, except the bounded classified-transient retry in AC-OFFICE-RUNTIME-001.11. Every other adapter error is terminal for the wakeup that produced it.
  • AC-OFFICE-RUNTIME-001.2: The wakeup row is stamped with status = failed and error_message. The failure path does not queue another wakeup for the same failed agent. A configured on_agent_error action can queue a separate coordinator run.
  • AC-OFFICE-RUNTIME-001.3: Re-runs of the failed agent happen only via explicit user action — Resume session in chat, Mark fixed on an inbox entry, or task reassignment to a different agent — except the automatic bounded retry in AC-OFFICE-RUNTIME-001.11. A coordinator run from on_agent_error is escalation, not a retry.
  • AC-OFFICE-RUNTIME-001.4: agent_run_failed - one entry per failed (task, agent) wakeup while the agent is below threshold. Title: " failed on ". Action: Mark fixed -> dismiss + retry.
  • AC-OFFICE-RUNTIME-001.5: agent_paused_after_failures - one entry per auto-paused agent. Title: " auto-paused after failures (tasks A, B, C)". Action: Mark fixed -> unpause + retry the affected tasks.
  • AC-OFFICE-RUNTIME-001.6: Changing assignee_agent_instance_id on a task fires the existing reactivity pipeline, which queues a fresh task_assigned wakeup for the new agent.
  • AC-OFFICE-RUNTIME-001.7: The existing staleness check (recovery-reliability spec) cancels the prior wakeup for the (task, old agent) since the assignee has changed.
  • AC-OFFICE-RUNTIME-001.8: Any per-task agent_run_failed inbox entry tied to the old (task, agent) auto-dismisses - the failure is no longer actionable on this task.
  • AC-OFFICE-RUNTIME-001.9: If a second auto-pause replaces the agent's pause_reason after Mark fixed on agent_paused_after_failures has read it but before its clear commits, the clear is refused and the call aborts instead of adopting the newer reason: consecutive_failures is not reset and no wakeup is re-queued.
  • AC-OFFICE-RUNTIME-001.10: A Mark fixed call aborted under AC-OFFICE-RUNTIME-001.9 does not dismiss the inbox entry - it stays actionable for the still-paused agent, and is dismissed only once a clear against the then-current pause_reason succeeds.
  • AC-OFFICE-RUNTIME-001.11: A post-start failure on the legacy (HandleAgentFailure) path that classifies transient (the shared routing classifier's ClassTransient && AutoRetryable && FallbackAllowed predicate) is retried up to 2 times, at 5s then 10s, before it counts toward consecutive_failures or auto-pause — observed by consecutive_failures staying unchanged on the first classified-transient failure. This shares its attempt counter with the pre-launch retry tier (no separate column) and is abandoned under the same 24h staleness rule, so a run that already exhausted pre-launch retries gets no additional post-start retry. The retry is additionally refused — falling through to terminal accounting instead of being scheduled — when the run's scheduled arrival (time.Since(run.requested_at) plus the 5s/10s delay this attempt is about to schedule) already exceeds the 2h staleRunThreshold the claim path uses to cancel stale runs: the run cannot be claimed before that delay elapses, so testing only its current age would let it age into the cancellation window during its own backoff, silently losing the failure instead of counting it. A narrower tick-width residual remains — the claim path only re-evaluates a run at the scheduler's next poll after scheduled_retry_at, not exactly at it — and is deliberately not closed. The retry is scheduled only when the lifecycle event carries the exact run identity plus current-invocation evidence with no observed output or effect; unknown, stale, output-producing, effectful, or diagnostically mismatched failures fall through to terminal accounting. See runtime-01.md § Legacy post-start transient retry.

System design

The migrated technical source is split into part 1, part 2.