Files
temp/docs/reference/decision_correction.md
T
freemo a0ac30d5de docs: update and extend documentation for v3.8.0 changes
- docs/reference/plan_cli.md: add note about legacy/v3 plan workflow
  mixing being disallowed (introduced in v3.8.0, issue #1577)
- docs/reference/uko_runtime.md: document v3.8.0 provenance tracking
  (sourceResource, validFrom, isCurrent on typed triples) and revision
  chain for temporal queries across indexing runs (issue #891)
- docs/reference/decision_correction.md: add CorrectionAttemptRecord
  section documenting the correction_attempts table, state lifecycle,
  repository API, and usage examples (issue #920)
- docs/modules/uko-provenance.md: new module guide for UKO provenance
  tracking covering purpose, how provenance is attached, revision chain
  mechanics, query patterns, persistence format, BDD coverage, and gotchas
2026-04-05 20:05:48 +00:00

195 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 (110,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.