f66fb5a19a
CI / lint (push) Failing after 35s
CI / quality (push) Successful in 40s
CI / typecheck (push) Failing after 48s
CI / security (push) Failing after 49s
CI / coverage (push) Has been skipped
CI / build (push) Successful in 20s
CI / helm (push) Successful in 34s
CI / benchmark-regression (push) Has been skipped
CI / unit_tests (push) Failing after 2m12s
CI / docker (push) Has been skipped
CI / e2e_tests (push) Failing after 15m52s
CI / integration_tests (push) Failing after 22m11s
CI / status-check (push) Failing after 1s
CI / benchmark-publish (push) Has been cancelled
Align Unicode box-drawing blocks and related tables in specification.md, ADR-044/045/046, and reference pages for consistent MkDocs rendering. ISSUES CLOSED: #1171
123 lines
4.7 KiB
Markdown
123 lines
4.7 KiB
Markdown
# Decision Domain Model
|
||
|
||
The decision subsystem records every choice point in a plan's lifecycle
|
||
as a **Decision** node in a persistent tree. Decisions are created
|
||
during the Strategize and Execute phases and form the basis for
|
||
targeted correction and replay.
|
||
|
||
## Decision Types
|
||
|
||
| Type | Phase | Description |
|
||
|--------------------------|------------|-------------------------------------------|
|
||
| `prompt_definition` | Strategize | Root decision — the plan prompt |
|
||
| `invariant_enforced` | Strategize | An invariant constraint was applied |
|
||
| `strategy_choice` | Strategize | High-level approach chosen |
|
||
| `implementation_choice` | Execute | How to implement a specific task |
|
||
| `resource_selection` | Execute | Which resources to read / modify |
|
||
| `subplan_spawn` | Strategize | Decision to create a child plan |
|
||
| `subplan_parallel_spawn` | Strategize | Spawn a group of child plans in parallel |
|
||
| `tool_invocation` | Execute | Which skill / tool to use |
|
||
| `error_recovery` | Execute | How to handle a failure |
|
||
| `validation_response` | Execute | Response to a validation failure |
|
||
| `user_intervention` | Any | User-provided guidance / correction |
|
||
|
||
## Decision Fields
|
||
|
||
### Identity
|
||
|
||
- **decision_id** — ULID, auto-generated
|
||
- **plan_id** — ULID of the parent plan (required)
|
||
- **parent_decision_id** — ULID of the parent decision, or `None` for the root
|
||
- **sequence_number** — monotonic order within the plan (0-indexed, never reused)
|
||
|
||
### Classification
|
||
|
||
- **decision_type** — one of the 11 `DecisionType` enum values
|
||
|
||
### Content
|
||
|
||
- **question** — what question was being answered (required, non-empty)
|
||
- **chosen_option** — the option that was selected (required, non-empty)
|
||
- **alternatives_considered** — list of other options evaluated
|
||
- **confidence_score** — float 0.0–1.0, or `None` if not applicable
|
||
|
||
### Context Snapshot
|
||
|
||
Every decision captures a `ContextSnapshot` for replay:
|
||
|
||
- **hot_context_hash** — cryptographic hash of the context window
|
||
- **hot_context_ref** — storage pointer to the full serialised context
|
||
- **relevant_resources** — list of `ResourceRef` entries (resource_id + optional path)
|
||
- **actor_state_ref** — LangGraph actor checkpoint reference
|
||
|
||
### Rationale
|
||
|
||
- **rationale** — human-readable explanation
|
||
- **actor_reasoning** — raw LLM reasoning trace, if available
|
||
|
||
### Downstream Impact
|
||
|
||
- **downstream_decision_ids** — ULIDs of decisions that depend on this one
|
||
- **downstream_plan_ids** — ULIDs of child plans spawned from this decision
|
||
- **artifacts_produced** — list of `ArtifactRef` (artifact_path + artifact_type)
|
||
|
||
### Timestamps
|
||
|
||
- **created_at** — UTC datetime, auto-set on creation
|
||
|
||
### Correction Metadata
|
||
|
||
- **is_correction** — boolean, True if this decision corrects another
|
||
- **corrects_decision_id** — ULID of the original decision
|
||
- **correction_reason** — why the correction was made
|
||
- **superseded_by** — ULID of the decision that replaced this one
|
||
|
||
## Tree Structure
|
||
|
||
Decisions form a tree via `parent_decision_id`:
|
||
|
||
```
|
||
prompt_definition (root, parent=None)
|
||
├── invariant_enforced
|
||
├── strategy_choice
|
||
│ ├── implementation_choice
|
||
│ │ ├── resource_selection
|
||
│ │ └── tool_invocation
|
||
│ └── subplan_spawn
|
||
└── strategy_choice
|
||
```
|
||
|
||
The `prompt_definition` type is always the root and must have
|
||
`parent_decision_id = None`. This is enforced by a model validator.
|
||
|
||
## Correction Lifecycle
|
||
|
||
Corrections never mutate existing decisions. Instead:
|
||
|
||
1. A new `Decision` is created with `is_correction=True` and
|
||
`corrects_decision_id` pointing to the original.
|
||
2. The original decision has its `superseded_by` field set to the
|
||
new decision's ID.
|
||
3. All downstream decisions of the original are also superseded.
|
||
|
||
The **current tree** consists of all decisions where
|
||
`superseded_by IS NULL`.
|
||
|
||
## Validation Rules
|
||
|
||
- `plan_id` must be a valid ULID
|
||
- `parent_decision_id`, `corrects_decision_id`, `superseded_by` must
|
||
be valid ULIDs or None
|
||
- `confidence_score` must be in [0.0, 1.0] or None
|
||
- `prompt_definition` decisions must have `parent_decision_id = None`
|
||
- If `is_correction` is True, `corrects_decision_id` must be set
|
||
- If `corrects_decision_id` is set, `is_correction` must be True
|
||
|
||
## Source
|
||
|
||
- Domain model: `src/cleveragents/domain/models/core/decision.py`
|
||
- Specification: `docs/specification.md` L18390–L18521
|
||
- ADR-007: Decision tree and correction
|
||
- ADR-033: Decision recording protocol
|
||
- ADR-034: Decision tree versioning and history
|