Files
cleveragents-core/docs/reference/decision_service.md
T

149 lines
5.4 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 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`