Files
temp/docs/reference/error_recovery.md
CoreRasurae 007af498b8 refactor(autonomy): rename automation profile task flags to spec names
Renamed all 11 task-type confidence threshold fields in AutomationProfile
from phase-transition semantics to spec-defined task-type semantics.
Updated all 8 built-in profiles, CLI formatting, YAML schema, services,
and all Behave/Robot tests referencing the old field names.

Post-review fixes:
- Fixed 24 stale old field names in M6 fixture files
  (automation_profiles.json, autonomy_guardrails.json)
- Added model_validator(mode='before') to detect legacy field names
  and raise actionable ValueError with rename mapping
- Added semantic bridge comments in PlanLifecycleService mapping
  task-type thresholds to phase-transition gates
- Added threshold_field to structured log messages for observability
- Restored categorised CLI automation-profile show output to match
  spec (Phase Transitions / Decision Automation / Self-Repair /
  Execution Controls) instead of flat list
- Added missing access_network field to spec show output examples
  (Rich, Plain, JSON, YAML variants)
- Aligned ADR-017 profile fields table to all 11 fields with
  descriptions matching spec Automatable Tasks table
- Aligned automation_profiles.md threshold descriptions with spec
- Added spec section references in phase_reversion.md, error_recovery.md,
  and plan_execute.md for field naming context
- Extended repository roundtrip test to assert all 11 threshold fields
- Fixed benchmark _make_profile() passing safety fields as top-level
  kwargs instead of via SafetyProfile sub-model (incompatible with
  extra="forbid")
- Aligned CLI JSON/YAML output structure for automation-profile show
  with the specification grouped format (phase_transitions,
  decision_automation, self_repair, execution_controls)
- Moved safety boolean fields into the Execution Controls section
  of Rich output per spec examples
- Reverted auto profile description to "Fully automatic except apply"
  per specification (line 16703, line 28406)
- Improved bridge comments in test steps with semantic context for
  threshold-to-gate mappings

ISSUES CLOSED: #902
2026-03-30 13:18:07 +01:00

284 lines
9.0 KiB
Markdown

# Error Recovery Reference
This document describes the error recovery patterns, error classification,
recovery hint system, and retry policy logic added in D1b.recovery.
## Error Categories
Errors are classified into categories that determine recovery behaviour:
| Category | Retriable | Description |
|----------|-----------|-------------|
| `transient` | Yes | Temporary failures (network, timeout, rate-limit) |
| `validation` | Yes | Validation failures during Execute or Apply |
| `configuration` | No | Bad config, missing required fields |
| `resource` | No | Missing or conflicting resources |
| `merge_conflict` | Yes | Sandbox merge failures |
| `authentication` | No | Auth/authz failures |
| `provider` | Yes | LLM provider errors (model unavailable, token limit) |
| `internal` | No | Unexpected internal errors (bugs) |
| `unknown` | No | Unclassified errors |
## Recovery Actions
Each error category maps to one or more recovery actions with CLI commands:
| Action | CLI Command | When Used |
|--------|-------------|-----------|
| `retry` | `agents plan prompt <plan_id>` | Transient / provider errors |
| `correct` | `agents plan correct <plan_id>` | Validation failures |
| `revert_strategize` | `agents plan revert <plan_id> --to-phase strategize` | Resource / merge conflicts |
| `prompt` | `agents plan prompt <plan_id>` | Resume with guidance |
| `cancel` | `agents plan cancel <plan_id>` | Non-recoverable errors |
| `manual` | — | Internal errors (check logs) |
## Retry Policy
The retry policy is controlled by the automation profile's
`modify_config` threshold (named per spec § Automatable Tasks):
- **0.0** (auto): Automatic retry for retriable errors
- **1.0** (human): Always escalate to human
```
Error occurs → classify_error(message, exception_type)
|
+→ retriable category? → retry_count < max_retries? → threshold < 1.0?
| | | |
| No → escalate No → exhausted, escalate No → escalate
| |
| Yes → auto retry
|
+→ non-retriable → escalate immediately
```
### Retry Limits
Default `max_retries = 3`. Configured via `SubplanConfig.max_retries`
for subplans (max: 5).
### Retry Exhaustion
When all retry attempts are used, the error is escalated with:
- Clear message indicating retries exhausted
- Recovery hints for manual intervention
- Error history preserved for debugging
## Structured Error Metadata
When an error is recorded, the following metadata is stored in the
plan's `error_details` field:
| Key | Type | Description |
|-----|------|-------------|
| `error_category` | string | Classification category |
| `error_phase` | string | Phase when error occurred |
| `retry_count` | string | Number of retries attempted |
| `max_retries` | string | Maximum retries allowed |
| `is_retriable` | string | Whether error can be retried |
| `error_actor` | string | Actor involved (if any) |
| `error_tool_call` | string | Tool call that failed (if any) |
| `stack_summary` | string | Abbreviated stack trace (last 3 frames) |
| `recovery_action` | string | Suggested recovery action |
| `recovery_hint` | string | Human-readable recovery message |
| `recovery_command` | string | CLI command for recovery |
## Execute Phase Integration
The `PlanExecutor` accepts an optional `ErrorRecoveryService` and uses
it during the Execute phase to record errors and drive automatic
retries:
```
PlanExecutor
├── StrategizeStubActor (records errors via ErrorRecoveryService)
├── ExecuteStubActor (retry loop driven by ErrorRecoveryService)
├── PlanLifecycleService (phase transitions, persistence)
└── ErrorRecoveryService (optional — error recording + retry policy)
```
### Retry Loop
When `error_recovery_service` is provided, `run_execute()` wraps the
execute actor in a retry loop:
1. The actor runs.
2. On failure the error is recorded via `ErrorRecoveryService.record_error()`.
3. `should_retry()` is checked — if the error is retriable and retries
remain, the actor runs again.
4. If retries are exhausted or the error is non-retriable, the plan
transitions to `ERRORED` via `fail_execute()`.
Strategize failures are also recorded through the service (but not
retried — the strategize phase is read-only and failures are
deterministic).
```python
from cleveragents.application.services.plan_executor import PlanExecutor
from cleveragents.application.services.error_recovery_service import (
ErrorRecoveryService,
)
er_service = ErrorRecoveryService(
lifecycle_service=lifecycle,
auto_retry_threshold=0.0,
max_retries=3,
)
executor = PlanExecutor(
lifecycle_service=lifecycle,
tool_runner=runner,
error_recovery_service=er_service,
)
# Execute with automatic retry on transient errors
result = executor.run_execute(plan_id)
```
## CLI Commands
### `agents plan errors <plan_id>`
Shows error decisions with recovery hints and retry history for a plan.
```bash
# Rich (default) output
agents plan errors 01HXYZ...
# JSON output
agents plan errors 01HXYZ... --format json
# Plain text
agents plan errors 01HXYZ... --format plain
```
Example rich output:
```
╭─ Plan Errors ──────────────────────────────────────────╮
│ Plan: 01HXYZ... │
│ Phase: execute │
│ State: errored │
│ Error: RuntimeError: Connection timed out │
│ │
│ Error Category: transient │
│ Error Phase: execute │
│ Retry Count: 3/3 │
│ Retriable: false │
│ │
│ Recovery Suggestions: │
│ → Retry the operation — the failure was transient. │
│ $ agents plan prompt 01HXYZ... │
╰────────────────────────────────────────────────────────╯
```
When no errors have been recorded the command shows a green
confirmation message instead.
## CLI Output
Recovery hints are included in CLI error output:
```
Error [transient]: Connection timed out after 30s
Phase: execute
Retry: 0/3
Recovery suggestions:
→ Retry the operation — the failure was transient.
$ agents plan prompt 01HXYZ...
✓ Automatic retry available.
```
### Error History
The error history tracks all errors for a plan, including:
- Total error count
- Retry count per error
- Category breakdown
- Chronological error records with recovery hints
> **Note:** Error history is held in-memory within the
> `ErrorRecoveryService` instance. If the service is restarted or a
> new instance is created, in-memory history is lost. The latest
> error metadata is also persisted to the plan's `error_details`
> field for durability across restarts.
## Service API
### `ErrorRecoveryService`
```python
from cleveragents.application.services.error_recovery_service import (
ErrorRecoveryService,
)
service = ErrorRecoveryService(
lifecycle_service=lifecycle,
auto_retry_threshold=0.0, # from automation profile
max_retries=3,
)
# Record an error
record = service.record_error(
plan_id="01HXYZ...",
phase="execute",
message="Connection timed out",
exception=exc, # optional, for stack trace
)
# Check retry decision
if service.should_retry(plan_id):
# auto-retry
...
elif service.should_escalate(plan_id):
# show recovery hints to user
hints = service.format_recovery_hints_for_cli(plan_id)
print(hints)
# Get full error history
history = service.get_error_history(plan_id)
print(f"Total errors: {history.total_errors}")
# Format for CLI
output = service.format_error_output(plan_id, fmt="json")
```
### `PlanLifecycleService.update_error_details`
External services use `update_error_details()` to merge structured
error metadata into a plan's `error_details` field without accessing
internal persistence methods:
```python
lifecycle.update_error_details(plan_id, {
"error_category": "transient",
"retry_count": "2",
})
```
### Domain Models
```python
from cleveragents.domain.models.core.error_recovery import (
ErrorCategory,
ErrorRecord,
ErrorHistory,
ErrorRecoveryPolicy,
RecoveryAction,
RecoveryHint,
classify_error,
get_recovery_hints,
)
# Classify an error
category = classify_error("Connection timed out", "NetworkError")
# Get recovery hints
hints = get_recovery_hints(ErrorCategory.TRANSIENT, "01HXYZ...")
# Create a policy
policy = ErrorRecoveryPolicy(auto_retry_threshold=0.0, max_retries=3)
if policy.should_retry(record):
...
```