Implements AgentSkillDiscovery class to support discovering Agent Skills from multiple configured directories across three scopes (global, project, local). Handles name collisions with precedence: local > project > global. Adds comprehensive BDD test coverage for multi-scope discovery scenarios including: - Global-only, project-only, and local-only discovery - Combined discovery from all scopes - Name collision resolution with proper precedence - Non-existent and empty scope directory handling - Multiple skills in same scope discovery ISSUES CLOSED: #9369
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.