Skip to content

Commit e57eed2

Browse files
docs: document pre-run snapshot & recovery mechanism
snapshot.mjs has existed since 3b6251f but was never covered in the docs. Add an ARCHITECTURE.md section explaining createPreRunSnapshot, refreshSnapshot (now refreshing after every cycle, not just implement-*), and restoreFromSnapshot, and link to it from README's Scope Enforcement section with a corrected "every cycle" description.
1 parent 7f3cdcb commit e57eed2

2 files changed

Lines changed: 15 additions & 1 deletion

File tree

ARCHITECTURE.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,18 @@ If the cascade cannot fully revert a file, a `scope-cleanup-<cycleId>` reconcile
194194

195195
---
196196

197+
## Pre-Run Snapshot & Recovery
198+
199+
The revert cascade above is necessary but blunt — `git restore` / `git clean` wipe a file back to `HEAD`, which would also destroy any uncommitted work the user (or a prior run) had in that file before Cortex started. `src/snapshot.mjs` exists to make reverts non-destructive:
200+
201+
1. **`createPreRunSnapshot()`** — runs once, before any cycle starts. Captures every uncommitted file (`git diff --name-only HEAD` + `git ls-files --others --exclude-standard`) as a byte-perfect `Buffer` blob under `.harness/pre-run-snapshot/`, indexed in `snapshot.json`. The snapshot directory itself is excluded from capture so it never snapshots its own blobs on subsequent runs, and blob filenames are prefixed with `blob-` so they stay visually distinct from real files.
202+
2. **`refreshSnapshot(cycle)`** — runs after **every** cycle that completes successfully and has an assigned agent (not just `implement-*` cycles — reconcile, fix, and other cycle types can produce valid in-scope edits too). It reads the cycle's report, filters `filesChanged[]` down to paths inside that agent's configured scope, and re-captures just those files. This means the snapshot always reflects the latest *valid* in-scope state, not just the pre-run state.
203+
3. **`restoreFromSnapshot(filePath)`** — called by the scope-revert cascade (see above) instead of leaving a file at bare `HEAD`. If a blob exists for the file, its content is written back byte-for-byte; otherwise the cascade's normal git-based revert stands.
204+
205+
Net effect: an out-of-scope write is reverted to the most recent *known-good* content for that file — either the user's pre-run uncommitted work, or the latest valid in-scope edit from an earlier cycle in the same run — rather than to whatever `HEAD` happens to contain.
206+
207+
---
208+
197209
## Auto-Scope Update
198210

199211
When an implement cycle completes with `scope: []` (unconstrained), the harness automatically detects the paths created and writes them back to `harness.config.json`, locking them in for all future cycles in the same run.

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,9 @@ This appends the harness runtime entries to `.gitignore` (idempotent — safe to
234234

235235
## Scope Enforcement & Auto-Update
236236

237-
Each agent is bound to its declared scope paths. After every implement cycle, Cortex compares changed files against those paths. Out-of-scope writes are automatically reverted via a 4-step git cascade.
237+
Each agent is bound to its declared scope paths. After every cycle, Cortex compares changed files against those paths. Out-of-scope writes are automatically reverted via a 4-step git cascade.
238+
239+
Reverts are non-destructive: a pre-run snapshot captures uncommitted work before the run starts and is refreshed with each cycle's valid in-scope edits, so a revert restores the latest known-good content for a file rather than wiping it back to bare `HEAD`. See [ARCHITECTURE.md → Pre-Run Snapshot & Recovery](./ARCHITECTURE.md#pre-run-snapshot--recovery) for details.
238240

239241
**New project with no scopes configured?** Set all agent scopes to `[]` and run. Cortex detects the paths your agents create, locks them into `harness.config.json`, and enforces them from the next cycle onward — shared libs (`libs/shared/`) are automatically distributed to all relevant agents.
240242

0 commit comments

Comments
 (0)