# Decision Service Reference ## Overview `DecisionService` provides the application-layer interface for recording decisions during plan execution, retrieving decision histories, and managing context snapshots. It lives in `src/cleveragents/application/services/decision_service.py`. ## Dual-Mode Persistence | Mode | UnitOfWork | Storage | |------------|------------|------------------------------------------------| | In-memory | `None` | Internal dicts (`_decisions`, `_plan_decisions`) | | Persisted | provided | DB via `DecisionRepository` + in-memory cache | When a `UnitOfWork` is wired, mutations are written to the database first, then the in-memory cache is updated (write-through). ## Constructor ```python DecisionService( settings: Settings | None = None, unit_of_work: UnitOfWork | None = None, ) ``` - **settings** – Application settings (optional for in-memory mode). - **unit_of_work** – When provided, decisions are persisted via `DecisionRepository`. ## Recording ### `record_decision()` ```python svc.record_decision( plan_id="01HV...", decision_type=DecisionType.STRATEGY_CHOICE, # or a string question="Which approach?", chosen_option="Build a REST API", parent_decision_id=None, # optional alternatives_considered=None, # list[str] confidence_score=None, # 0.0-1.0 rationale="", # human-readable actor_reasoning=None, # raw LLM trace context_snapshot=None, # auto-captured if omitted artifacts_produced=None, # list[ArtifactRef] is_correction=False, corrects_decision_id=None, correction_reason=None, ) ``` - Auto-assigns a monotonically increasing **sequence number** per plan. - Auto-generates a **ULID** for `decision_id`. - Auto-captures a **context snapshot** (SHA-256 hash) when no explicit snapshot is provided. - Stores the snapshot in the built-in `SnapshotStore`. **Raises:** - `ValidationError` – required fields missing or empty. - `DuplicateDecisionError` – decision ID already exists. ## Retrieval | Method | Description | |---------------------------------------|--------------------------------------------| | `get_decision(decision_id)` | Single decision by ULID | | `list_decisions(plan_id)` | All decisions for a plan, ordered by seq | | `list_by_type(plan_id, decision_type)`| Filtered by type, ordered by seq | All raise `DecisionNotFoundError` when the target decision does not exist (where applicable). ## Tree Operations | Method | Description | |-------------------------------|------------------------------------------| | `get_tree(plan_id)` | BFS from root(s), level by level | | `get_path_to_root(decision_id)` | Walk from a decision up to the root | ## Superseded Decisions | Method | Description | |-----------------------------------------------|---------------------------------------| | `mark_superseded(decision_id, new_decision_id)` | Mark a decision as superseded | | `get_superseded(plan_id)` | List all superseded decisions | ## Delete ```python svc.delete_decision(decision_id) # -> True ``` Removes from both persistence and the snapshot store. Raises `DecisionNotFoundError` if not found. ## Snapshot Store `SnapshotStore` manages `ContextSnapshot` objects keyed by decision ID with hash-based deduplication. | Method | Description | |---------------------------------|----------------------------------------------| | `get_snapshot(decision_id)` | Retrieve snapshot for a decision | | `get_snapshots_for_plan(plan_id)` | All snapshots for a plan's decisions | | `snapshots.get_by_hash(hash)` | Decision IDs sharing the same context hash | | `snapshots.store(id, snap)` | Store a snapshot (internal) | | `snapshots.remove(id)` | Remove a snapshot | ## Statistics | Method | Description | |-------------------------------|----------------------------------| | `count_decisions(plan_id)` | Number of decisions for a plan | | `get_next_sequence(plan_id)` | Next available sequence number | ## Custom Exceptions | Exception | Base | Description | |--------------------------|--------------------------|-------------------------------------| | `DuplicateDecisionError` | `BusinessRuleViolation` | Decision ID already exists | | `DecisionNotFoundError` | `ResourceNotFoundError` | Decision not found | | `SequenceConflictError` | `BusinessRuleViolation` | Sequence number already used | ## Running Tests ```bash # Behave BDD tests nox -s unit_tests -- features/decision_recording.feature # Robot Framework integration smoke tests nox -s integration_tests # ASV benchmarks nox -s benchmark ``` ## Related - Domain model: `src/cleveragents/domain/models/core/decision.py` - Persistence: `src/cleveragents/infrastructure/database/repositories.py` (`DecisionRepository`) - Database schema: `docs/reference/database_schema.md` - ADR: `docs/adr/ADR-033-decision-recording-protocol.md`