164 lines
5.0 KiB
Markdown
164 lines
5.0 KiB
Markdown
# ChangeSet Model Reference
|
|
|
|
The ChangeSet domain model captures all file changes made by tools during the
|
|
Execute phase. It is the foundation for plan diff, review, and apply workflows.
|
|
|
|
## Overview
|
|
|
|
| Model | Purpose |
|
|
|---|---|
|
|
| `ChangeOperation` | Enum of operation types (CREATE, MODIFY, DELETE, RENAME) |
|
|
| `ChangeEntry` | Single recorded mutation with content hashes and metadata |
|
|
| `SpecChangeSet` | Collection of entries for a plan, with computed summaries |
|
|
| `ChangeSetStore` | Protocol for persisting and querying changesets |
|
|
| `InMemoryChangeSetStore` | In-memory implementation for M1 milestone |
|
|
|
|
## ChangeOperation
|
|
|
|
```python
|
|
from cleveragents.domain.models.core.change import ChangeOperation
|
|
|
|
ChangeOperation.CREATE # "create" — new file
|
|
ChangeOperation.MODIFY # "modify" — content changed
|
|
ChangeOperation.DELETE # "delete" — file removed
|
|
ChangeOperation.RENAME # "rename" — file moved/renamed
|
|
```
|
|
|
|
## ChangeEntry
|
|
|
|
Each `ChangeEntry` represents a single tool-caused mutation.
|
|
|
|
### Fields
|
|
|
|
| Field | Type | Description |
|
|
|---|---|---|
|
|
| `entry_id` | `str` | Auto-generated ULID uniquely identifying this entry |
|
|
| `plan_id` | `str` | ULID of the plan that owns this change |
|
|
| `resource_id` | `str` | ULID of the resource affected |
|
|
| `tool_name` | `str` | Namespaced tool name (e.g. `builtin/file-write`) |
|
|
| `operation` | `ChangeOperation` | Type of change |
|
|
| `path` | `str` | Repo-relative file path |
|
|
| `before_hash` | `str \| None` | SHA-256 of file before change (`None` for create) |
|
|
| `after_hash` | `str \| None` | SHA-256 of file after change (`None` for delete) |
|
|
| `before_mode` | `int \| None` | File mode before change |
|
|
| `after_mode` | `int \| None` | File mode after change |
|
|
| `timestamp` | `datetime` | UTC timestamp of the change |
|
|
|
|
### ULID Fields
|
|
|
|
The `entry_id` and `plan_id` fields use [ULIDs](https://github.com/ulid/spec)
|
|
(Universally Unique Lexicographically Sortable Identifiers). ULIDs are 128-bit
|
|
identifiers that encode a timestamp and random component, making them sortable
|
|
by creation time while remaining globally unique.
|
|
|
|
```
|
|
01ARZ3NDEKTSV4RRFFQ69G5FAV
|
|
└─────────┘└────────────┘
|
|
timestamp randomness
|
|
(48 bit) (80 bit)
|
|
```
|
|
|
|
### Example
|
|
|
|
```python
|
|
from cleveragents.domain.models.core.change import (
|
|
ChangeEntry, ChangeOperation,
|
|
)
|
|
|
|
entry = ChangeEntry(
|
|
plan_id="01HXYZ123456789ABCDEF",
|
|
resource_id="01HXYZ000000000000001",
|
|
tool_name="builtin/file-write",
|
|
operation=ChangeOperation.CREATE,
|
|
path="src/models/user.py",
|
|
after_hash="e3b0c44298fc1c149afbf4c8996fb924...",
|
|
)
|
|
```
|
|
|
|
## SpecChangeSet
|
|
|
|
A `SpecChangeSet` groups all `ChangeEntry` records for a single plan execution.
|
|
|
|
### Fields
|
|
|
|
| Field | Type | Description |
|
|
|---|---|---|
|
|
| `changeset_id` | `str` | Auto-generated ULID for the changeset |
|
|
| `plan_id` | `str` | ULID of the plan |
|
|
| `entries` | `list[ChangeEntry]` | Ordered list of change entries |
|
|
| `created_at` | `datetime` | UTC timestamp when created |
|
|
|
|
### Computed Properties
|
|
|
|
| Property | Type | Description |
|
|
|---|---|---|
|
|
| `creates` | `int` | Count of CREATE entries |
|
|
| `modifies` | `int` | Count of MODIFY entries |
|
|
| `deletes` | `int` | Count of DELETE entries |
|
|
| `renames` | `int` | Count of RENAME entries |
|
|
| `paths_changed` | `set[str]` | Unique file paths affected |
|
|
| `resources_involved` | `set[str]` | Unique resource IDs |
|
|
|
|
### Example
|
|
|
|
```python
|
|
from cleveragents.domain.models.core.change import (
|
|
ChangeEntry, ChangeOperation, SpecChangeSet,
|
|
)
|
|
|
|
cs = SpecChangeSet(
|
|
plan_id="01HXYZ123456789ABCDEF",
|
|
entries=[
|
|
ChangeEntry(
|
|
plan_id="01HXYZ123456789ABCDEF",
|
|
resource_id="01HXYZ000000000000001",
|
|
tool_name="builtin/file-write",
|
|
operation=ChangeOperation.CREATE,
|
|
path="src/new.py",
|
|
),
|
|
],
|
|
)
|
|
|
|
print(cs.creates) # 1
|
|
print(cs.paths_changed) # {'src/new.py'}
|
|
print(cs.summary()) # {'total': 1, 'creates': 1, ...}
|
|
```
|
|
|
|
## ChangeSetStore
|
|
|
|
The `ChangeSetStore` protocol defines the interface for changeset persistence:
|
|
|
|
```python
|
|
class ChangeSetStore(Protocol):
|
|
def start(self, plan_id: str) -> str: ...
|
|
def record(self, changeset_id: str, entry: ChangeEntry) -> None: ...
|
|
def get(self, changeset_id: str) -> SpecChangeSet | None: ...
|
|
def get_for_plan(self, plan_id: str) -> list[SpecChangeSet]: ...
|
|
def summarize(self, changeset_id: str) -> dict: ...
|
|
```
|
|
|
|
### InMemoryChangeSetStore
|
|
|
|
The `InMemoryChangeSetStore` is the M1 implementation that stores changesets in
|
|
a plain Python dict. It is suitable for single-process tests and the M1 runtime.
|
|
|
|
```python
|
|
from cleveragents.domain.models.core.change import (
|
|
ChangeEntry, ChangeOperation, InMemoryChangeSetStore,
|
|
)
|
|
|
|
store = InMemoryChangeSetStore()
|
|
cs_id = store.start("01HXYZ123456789ABCDEF")
|
|
|
|
store.record(cs_id, ChangeEntry(
|
|
plan_id="01HXYZ123456789ABCDEF",
|
|
resource_id="01HXYZ000000000000001",
|
|
tool_name="builtin/file-write",
|
|
operation=ChangeOperation.CREATE,
|
|
path="src/new.py",
|
|
))
|
|
|
|
cs = store.get(cs_id)
|
|
print(store.summarize(cs_id))
|
|
```
|