# Decision Correction Reference ## Overview The correction subsystem allows operators to modify a plan's decision tree after execution by either **reverting** a subtree of decisions or **appending** new decisions as a child plan. ## Correction Modes ### Revert Invalidates the targeted decision and every descendant reachable via BFS traversal. Associated artifacts are archived and affected child plans are rolled back. ```text ┌─── D1 (target) ◄── revert starts here │ │ │ ┌──┴──┐ │ D2 D3 ← all invalidated │ │ │ D4 ← also invalidated ``` ### Append Preserves the original decision and spawns a **new child plan** rooted at the target node. The child plan carries the operator's guidance and produces additional decisions without disturbing the existing tree. ```text D1 (target) │ ┌──┴──────────┐ D2 (original) CP-new ← child plan appended ``` ## Impact Analysis — BFS Algorithm Impact analysis uses breadth-first search over the decision tree's adjacency list (parent → children mapping): ```python from collections import deque def compute_affected_subtree(target_id, tree): affected = [] queue = deque([target_id]) while queue: node = queue.popleft() affected.append(node) queue.extend(tree.get(node, [])) return affected ``` ### Risk Classification | Affected Count | Risk Level | |----------------|------------| | ≤ 3 | low | | 4 – 10 | medium | | > 10 | high | ## Dry-Run Output A dry-run report contains: - **impact** — Full `CorrectionImpact` with affected decisions, files, child plans, estimated cost, and risk level. - **decisions_to_invalidate** — Decision IDs that *would* be marked invalid (revert mode only). - **child_plans_to_rollback** — Child plans that *would* be rolled back. - **estimated_recompute_time_seconds** — Wall-clock estimate. - **warnings** — Human-readable cautions (e.g. high risk). ## Status Lifecycle ```text PENDING → ANALYZING → EXECUTING → APPLIED → FAILED PENDING → CANCELLED ANALYZING → CANCELLED ``` ## Service API | Method | Description | |-----------------------------|-----------------------------------------------| | `request_correction()` | Create a new correction request | | `analyze_impact()` | BFS impact analysis on the decision tree | | `generate_dry_run_report()` | Full report without side effects | | `execute_revert()` | Invalidate subtree + archive artifacts | | `execute_append()` | Spawn child plan preserving original decision | | `execute_correction()` | Dispatch to revert or append based on mode | | `get_correction()` | Retrieve a correction by ID | | `list_corrections()` | List corrections (optional plan_id filter) | | `list_attempts()` | List execution attempts for a correction | | `cancel_correction()` | Cancel a pending/analyzing correction | --- ## Correction Attempts (v3.8.0+) Each execution of a correction is tracked as a `CorrectionAttemptRecord`. Multiple attempts may exist for a single correction (e.g. if a first attempt fails and the operator retries). ### `CorrectionAttemptRecord` **Module:** `cleveragents.domain.models.core.correction_attempt` | Field | Type | Description | |-------|------|-------------| | `id` | `str` | ULID of this attempt | | `correction_id` | `str` | Parent correction ULID | | `plan_id` | `str` | Plan this correction targets | | `original_decision_id` | `str` | Decision being corrected | | `new_decision_id` | `str \| None` | Replacement decision (set on success) | | `mode` | `CorrectionMode` | `revert` or `append` | | `state` | `CorrectionAttemptState` | Current state (see lifecycle below) | | `guidance` | `str` | Operator guidance text (1–10,000 chars) | | `created_at` | `datetime` | UTC creation timestamp | | `completed_at` | `datetime \| None` | UTC completion timestamp (terminal states only) | | `archived_artifacts_path` | `str \| None` | Path to archived artifacts (revert mode) | ### `CorrectionAttemptState` Lifecycle ```text pending → executing → complete → failed ``` Valid transitions: | From | To | Notes | |------|----|-------| | `pending` | `executing` | Attempt begins execution | | `executing` | `complete` | Correction applied successfully | | `executing` | `failed` | Correction failed; `completed_at` auto-set | Terminal states (`complete`, `failed`) cannot transition further. Self-transitions are rejected. ### `CorrectionAttemptRepository` **Module:** `cleveragents.infrastructure.repositories.correction_attempt` | Method | Description | |--------|-------------| | `create(record)` | Persist a new attempt; raises `DatabaseError` on FK violation | | `get(attempt_id)` | Retrieve by ULID; raises `ResourceNotFoundError` if absent | | `list_by_plan(plan_id)` | List all attempts for a plan (ordered by `created_at`) | | `update_state(attempt_id, new_state, *, new_decision_id, completed_at, archived_artifacts_path)` | Transition state; auto-sets `completed_at` for terminal states | | `delete(attempt_id)` | Hard-delete an attempt record | ### Usage Example ```python from cleveragents.domain.models.core.correction_attempt import ( CorrectionAttemptRecord, CorrectionAttemptState, ) from cleveragents.domain.models.core.correction import CorrectionMode attempt = CorrectionAttemptRecord( id="01HXYZ...", correction_id="01HABC...", plan_id="01HDEF...", original_decision_id="01HGHI...", mode=CorrectionMode.REVERT, state=CorrectionAttemptState.PENDING, guidance="Revert the database migration decision and retry with a safer approach.", ) # Transition to executing repo.update_state(attempt.id, CorrectionAttemptState.EXECUTING) # Complete the attempt repo.update_state( attempt.id, CorrectionAttemptState.COMPLETE, new_decision_id="01HJKL...", archived_artifacts_path="/var/cleveragents/archives/01HXYZ", ) ``` ### Database Schema The `correction_attempts` table uses `RESTRICT` foreign keys for both `original_decision_id` and `new_decision_id`, preserving the correction audit trail when decisions are cleaned up. The ORM-level `cascade="all, delete-orphan"` on `LifecyclePlanModel` ensures that deleting a plan cascades to its correction attempts.