- 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
6.6 KiB
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.
┌─── 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.
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):
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
CorrectionImpactwith 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
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
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
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.