Files
cleveragents-core/docs/reference/semantic_validation.md
T
eugen.thaci 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
docs(spec): align ASCII UI tables in specification and related pages
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
2026-04-03 04:55:21 +00:00

266 lines
8.7 KiB
Markdown

# Semantic Validation
The **Semantic Validation Service** provides lightweight, AST-based semantic
analysis for Python projects during the strategize/execute phases. It detects
syntax errors, missing imports, broken references, duplicate imports, API
misuse, and missing symbols before code is applied. Non-Python files are
automatically skipped.
## Overview
Semantic checks are exposed as Validation tools attachable per resource via the
Tool Registry. Results integrate into the `ValidationPipeline` as informational
by default, meaning failures are reported but do not block the plan lifecycle
unless configured otherwise.
```
Source Code ──► SemanticValidationService.check_file() ──► [SemanticCheckResult, ...]
├── SyntaxCheckRule
├── MissingImportRule
├── BrokenReferenceRule
├── DuplicateImportRule
├── APIMisuseRule
└── MissingSymbolRule
```
> **Note:** `check_file()` returns `[]` immediately for non-Python files
> (files without `.py` or `.pyi` extension).
## Built-in Rules
| Rule | Description | Default Severity|
|--------------------|---------------------------------------------------------|-----------------|
| `syntax_error` | Parses source via `ast.parse` | `error` |
| `missing_import` | Flags imports not in `sys.stdlib_module_names` | `warn` |
| `broken_reference` | Detects names not defined in any scope (scope-aware) | `warn` |
| `duplicate_import` | Finds duplicate relative imports | `error` |
| `api_misuse` | AST-based detection of dangerous calls (see below) | `warn` |
| `missing_symbol` | Finds undefined names in functions and class methods | `info` |
> **Rename:** The rule was previously registered as `dependency_cycle` and is
> now registered as `duplicate_import` to better reflect its purpose.
> The class alias `DependencyCycleRule` remains available for backward
> compatibility.
### APIMisuseRule Dangerous Calls
The `api_misuse` rule uses AST analysis (not regex) to detect calls to:
- `eval()`, `exec()`, `compile()`
- `__import__()`
- `os.system()`, `os.popen()`
- `subprocess.call()`, `subprocess.run()`, `subprocess.Popen()`
- `pickle.load()`, `pickle.loads()`
- `marshal.loads()`
Because the rule inspects `ast.Call` nodes, it does **not** false-positive on
string literals that happen to contain these function names.
## Severity Mapping
Each rule produces findings with a severity level. The severity determines
how the finding integrates with the `ValidationPipeline`:
| Severity | Pipeline Mode | Behaviour |
|----------|------------------|-------------------------------------|
| `error` | `required` | Failure **blocks** the operation |
| `warn` | `informational` | Failure is reported, does not block |
| `info` | `informational` | Informational only |
The mapping is configurable via `validation.semantic.severity_mapping`.
## Required vs Informational Attachment Modes
Semantic validations attach to the `ValidationPipeline` in one of two modes:
- **Required** (`error` severity): If a required semantic validation fails,
`ValidationSummary.all_required_passed` becomes `False`, blocking the plan
from proceeding to the Apply phase.
- **Informational** (`warn`/`info` severity): If an informational validation
fails, the finding is logged at INFO level for review but does **not**
affect the `all_required_passed` property.
This allows teams to start with informational semantic checks and
progressively promote them to required as confidence grows.
## Configuration
Three configuration keys control semantic validation:
| Key | Type | Default | Description |
|------------------------------------------|--------|---------|----------------------------------------|
| `validation.semantic.enabled` | `bool` | `true` | Global on/off for semantic validation |
| `validation.semantic.python.enabled` | `bool` | `true` | Python-specific checks on/off |
| `validation.semantic.severity_mapping` | `dict` | (below) | Per-rule severity overrides |
Default severity mapping:
```yaml
validation.semantic.severity_mapping:
syntax_error: error
missing_import: warn
broken_reference: warn
duplicate_import: error
api_misuse: warn
missing_symbol: info
```
### Per-project Configuration
Set `validation.semantic.enabled: false` in the project configuration to
disable semantic validation for a specific project:
```yaml
# .cleveragents/config.yaml
validation:
semantic:
enabled: false
```
### Per-plan Configuration
Override in plan metadata to enable/disable per plan execution:
```yaml
validation:
semantic:
enabled: true
python:
enabled: true
```
## Rule Registry
The `SemanticRuleRegistry` manages pluggable validation rules:
```python
from cleveragents.application.services import (
SemanticRuleRegistry,
create_default_registry,
)
# Create with built-in rules
registry = create_default_registry()
# List registered rules
print(registry.list_rules())
# ['api_misuse', 'broken_reference', 'duplicate_import',
# 'missing_import', 'missing_symbol', 'syntax_error']
#
# Note: 'duplicate_import' is provided by DuplicateImportRule
# Look up a rule
rule = registry.get("syntax_error")
# Register a custom rule
registry.register(my_custom_rule)
```
### Custom Rule Protocol
Any object implementing the `SemanticValidationRule` protocol can be
registered:
```python
class MyCustomRule:
@property
def name(self) -> str:
return "my_custom_check"
def check(self, source: str, filename: str) -> SemanticCheckResult:
# ... run analysis ...
return SemanticCheckResult(
passed=True,
message="All good",
)
```
## Caching
The `SemanticValidationCache` avoids re-running checks on unchanged files
by caching results keyed by `(rule_name, file_sha256)`. The cache uses an
**LRU (Least Recently Used)** eviction policy with a configurable
`max_size` (default: 4096 entries). All operations are **thread-safe**.
```python
from cleveragents.application.services import SemanticValidationCache
cache = SemanticValidationCache(max_size=256)
file_hash = cache.compute_hash(source_code)
# Check cache before running expensive rule
cached = cache.get("syntax_error", file_hash)
if cached is None:
result = rule.check(source_code, filename)
cache.put("syntax_error", file_hash, result)
```
The service automatically uses caching when `check_file()` is called.
Calling `check_file()` with the same source content will return cached
results without re-executing rules.
When the cache reaches `max_size`, the least-recently-used entry is
automatically evicted to make room for the new one.
## Output Schema Normalisation
All semantic check results follow a consistent normalised schema:
```json
{
"passed": true,
"message": "No syntax errors in test.py",
"data": null
}
```
The `data` field contains structured finding details when present:
```json
{
"passed": false,
"message": "Syntax error at test.py:3: invalid syntax",
"data": {
"filename": "test.py",
"line": 3,
"detail": "invalid syntax"
}
}
```
The `normalise_output()` method on `SemanticValidationService` produces
this schema from any `SemanticCheckResult`.
## Pipeline Integration
Use `as_pipeline_results()` to get results compatible with the
`ValidationPipeline`:
```python
service = SemanticValidationService()
results = service.as_pipeline_results(source, "module.py")
# Each result dict has:
# - passed: bool
# - message: str
# - data: dict | None
# - severity: str ("info" | "warn" | "error")
# - mode: str ("required" | "informational")
```
## API Reference
### `SemanticValidationService`
| Method | Description |
|-------------------------|---------------------------------------------------|
| `check_file()` | Run all (or selected) rules on source code |
| `as_pipeline_results()` | Same as `check_file` but returns pipeline dicts |
| `normalise_output()` | Normalise a single result to passed/message/data |
| `enabled` | Whether semantic validation is globally enabled |
| `python_enabled` | Whether Python-specific checks are enabled |
| `registry` | The rule registry instance |
| `cache` | The result cache instance |