Files
cleveragents-core/docs/reference/diff_review.md
T
2026-02-25 10:02:38 +00:00

88 lines
2.9 KiB
Markdown

# Diff Review
The diff review module builds reviewable diff artifacts from `SpecChangeSet`
records, grouping changes by resource and producing unified diff text for
CLI display.
## Overview
When a plan accumulates changes through tool executions, the diff review
system transforms the raw `ChangeEntry` records into a structured
`ReviewArtifact` suitable for human review before applying changes.
## Domain Models
### DiffEntry
A single diff entry for CLI review. Contains:
| Field | Type | Description |
|---|---|---|
| `resource_id` | `str` | Resource ULID |
| `resource_name` | `str` | Human-readable resource name |
| `path` | `str` | File path |
| `change_type` | `str` | Operation type (create/modify/delete/rename) |
| `before_content` | `str \| None` | Content before the change |
| `after_content` | `str \| None` | Content after the change |
| `before_hash` | `str \| None` | SHA-256 before |
| `after_hash` | `str \| None` | SHA-256 after |
| `file_mode` | `int \| None` | File permission mode |
| `is_binary` | `bool` | Whether the file is binary |
| `is_rename` | `bool` | Whether this is a rename/move |
| `rename_from` | `str \| None` | Original path for renames |
| `rename_to` | `str \| None` | Destination path for renames |
| `diff_text` | `str` | Unified diff text |
| `truncated` | `bool` | Whether the diff text was truncated |
### ResourceDiffGroup
Groups diff entries for a single resource. Provides summary counts
via properties: `added`, `modified`, `deleted`, `renamed`.
### ReviewArtifact
Complete diff review artifact for a plan. Contains grouped diff entries,
total change count, and truncation status.
## DiffBuilder
`DiffBuilder` takes a `SpecChangeSet` and optional content maps to produce
a `ReviewArtifact`.
```python
from cleveragents.domain.models.core.diff_review import DiffBuilder
builder = DiffBuilder(max_diff_size=50_000, context_lines=3)
artifact = builder.build(
changeset,
before_contents={"src/main.py": "old content"},
after_contents={"src/main.py": "new content"},
resource_names={"RES001": "my-resource"},
)
```
### Features
- **Unified diff generation** using `difflib.unified_diff`
- **Binary detection** via null byte checking
- **Rename detection** using `SequenceMatcher` path similarity (>0.6)
combined with matching content hashes
- **Truncation** when total diff text exceeds `max_diff_size` (applies
uniformly to all entry types including renames)
- **Stable ordering** by resource ID, then path within each group
## DiffSerializer
Renders a `ReviewArtifact` to various output formats:
- `to_plain(artifact)` — plain text for terminal output
- `to_json(artifact)` — structured JSON for programmatic use
- `to_rich(artifact)` — rich markup with `[bold]`, `[green]`, `[red]` tags
## Constants
| Name | Default | Description |
|---|---|---|
| `DEFAULT_MAX_DIFF_SIZE` | 50,000 | Maximum total diff text characters |
| `RENAME_SIMILARITY_THRESHOLD` | 0.6 | Minimum path similarity for rename detection |