forked from cleveragents/cleveragents-core
135 lines
4.3 KiB
Markdown
135 lines
4.3 KiB
Markdown
# Invariants
|
|
|
|
Invariants are natural-language constraints on plan execution. They flow into the
|
|
decision tree during Strategize and are reconciled by the Invariant Reconciliation
|
|
Actor before any strategy work begins.
|
|
|
|
## Scope Hierarchy
|
|
|
|
| Scope | Description |
|
|
|-----------|----------------------------------------------------------|
|
|
| `GLOBAL` | Applies to every plan in the system |
|
|
| `PROJECT` | Applies to plans targeting a specific project |
|
|
| `ACTION` | Defined in an action template; promoted on `plan use` |
|
|
| `PLAN` | Attached directly to a specific plan |
|
|
|
|
## Merge Precedence
|
|
|
|
When computing the effective set of invariants for a plan, the precedence chain is:
|
|
|
|
```
|
|
plan > project > global
|
|
```
|
|
|
|
- **Plan-level** invariants take highest precedence.
|
|
- **Project-level** invariants apply next.
|
|
- **Global-level** invariants are lowest precedence.
|
|
- **Action-level** invariants are promoted to plan scope when `plan use` is called.
|
|
|
|
### De-duplication
|
|
|
|
Invariants are de-duplicated by text (case-insensitive). When the same constraint
|
|
text appears at multiple scopes, only the highest-precedence copy is kept.
|
|
|
|
### Merge Example
|
|
|
|
Given:
|
|
|
|
- Global: `"Never delete production data"`, `"Log all changes"`
|
|
- Project (`myapp`): `"All API changes need tests"`, `"Log all changes"`
|
|
- Plan: `"Use Python 3.13 only"`
|
|
|
|
The effective set for a plan targeting `myapp` would be:
|
|
|
|
1. `"Use Python 3.13 only"` (plan)
|
|
2. `"All API changes need tests"` (project)
|
|
3. `"Log all changes"` (project — shadows the global duplicate)
|
|
4. `"Never delete production data"` (global)
|
|
|
|
## Enforcement
|
|
|
|
At the start of the Strategize phase, the Invariant Reconciliation Actor:
|
|
|
|
1. Collects the effective invariant set for the plan.
|
|
2. Evaluates each invariant against the current plan context.
|
|
3. Creates an `InvariantEnforcementRecord` for each invariant.
|
|
4. Records an `invariant_enforced` decision in the decision tree.
|
|
|
|
### Enforcement Record
|
|
|
|
Each record contains:
|
|
|
|
| Field | Description |
|
|
|------------------|--------------------------------------------------|
|
|
| `invariant_id` | ULID of the invariant |
|
|
| `enforced` | Whether the invariant was successfully enforced |
|
|
| `actor_response` | Response text from the reconciliation actor |
|
|
| `decision_id` | ULID of the associated decision node |
|
|
|
|
## Violation Model
|
|
|
|
When an invariant is violated during execution, an `InvariantViolation` is created:
|
|
|
|
| Field | Description |
|
|
|-----------------|---------------------------------------------------|
|
|
| `invariant_id` | ULID of the violated invariant |
|
|
| `violated_text` | The invariant text that was violated |
|
|
| `severity` | `error`, `warning`, or `info` |
|
|
| `details` | Additional violation context |
|
|
|
|
## CLI Usage
|
|
|
|
### Add an invariant
|
|
|
|
```bash
|
|
# Global invariant
|
|
agents invariant add --global "Never delete production data"
|
|
|
|
# Project-scoped invariant
|
|
agents invariant add --project myapp "All API changes need tests"
|
|
|
|
# Plan-specific invariant
|
|
agents invariant add --plan 01HXYZ... "Use Python 3.13 only"
|
|
|
|
# Action-scoped invariant
|
|
agents invariant add --action local/code-coverage "Minimum 80% coverage"
|
|
```
|
|
|
|
### List invariants
|
|
|
|
```bash
|
|
# List all active invariants
|
|
agents invariant list
|
|
|
|
# Filter by scope
|
|
agents invariant list --global
|
|
agents invariant list --project myapp
|
|
|
|
# Show merged effective set for a project
|
|
agents invariant list --effective --project myapp
|
|
|
|
# Filter by regex
|
|
agents invariant list "data.*safe"
|
|
|
|
# JSON output
|
|
agents invariant list --format json
|
|
```
|
|
|
|
### Remove an invariant
|
|
|
|
```bash
|
|
# With confirmation prompt
|
|
agents invariant remove 01HXYZ...
|
|
|
|
# Skip confirmation
|
|
agents invariant remove --yes 01HXYZ...
|
|
```
|
|
|
|
## Relationship with PlanInvariant
|
|
|
|
The existing `PlanInvariant` model in `plan.py` represents invariants already
|
|
attached to a plan with an `InvariantSource` provenance tag. The new `Invariant`
|
|
model in `invariant.py` is the standalone storage model used by `InvariantService`
|
|
for cross-scope management. When a plan is created via `plan use`, action
|
|
invariants are converted to `PlanInvariant` entries on the plan itself.
|