feat: ADR-0006 §8 steps 1-2 — --no-undo flag + snapshot ring module
Step 1 (Cargo + CLI): - add the `backup` feature to rusqlite (online backup API) - `--no-undo` flag (test-first) + help-banner entry Step 2 (snapshot store, src/undo.rs): - SnapshotStore: a persisted undo ring + redo stack under <project>/.snapshots/ (index.yaml + per-snapshot payload dirs) - hybrid whole-project snapshot: db via backup API + project.yaml / data/*.csv copied as files; restore is text-first, db-last (ADR-0015 §6 commit-db-last) - stage/finalize/discard, undo/redo (each snapshots current to keep the inverse possible), N=50 eviction, redo-cleared-on-new-work, orphan/staging cleanup, monotonic ids - 12 Tier-1 tests; adds a crate-visible persistence::utc_iso8601_now No worker wiring yet (step 3). 1674 passed / 0 failed / 1 ignored; clippy clean.
This commit is contained in:
@@ -207,7 +207,7 @@ amendment records:
|
||||
data/<table>.csv
|
||||
playground.db
|
||||
.snapshots/
|
||||
index.json # ordered ring + redo stack: ids, timestamps,
|
||||
index.yaml # ordered ring + redo stack: ids, timestamps,
|
||||
# command text, status; the source of truth
|
||||
# for ordering/eviction
|
||||
0001/
|
||||
@@ -221,7 +221,7 @@ amendment records:
|
||||
- **`.snapshots/` is git-ignored, export-excluded, and on the
|
||||
temp-cleanup allowlist** (R13).
|
||||
- The **ring** (undo) and the **redo stack** are both recorded in
|
||||
`index.json`; snapshot payload dirs are shared storage referenced by
|
||||
`index.yaml`; snapshot payload dirs are shared storage referenced by
|
||||
id. Eviction beyond 50 deletes the oldest payload dir.
|
||||
- Ids are monotonic; never reused, to avoid stale references.
|
||||
|
||||
@@ -253,7 +253,7 @@ A snapshot brackets the existing 4-step persistence sequence:
|
||||
3. atomic-rename text into place (step 3)
|
||||
4. commit db (step 4)
|
||||
5. FINALIZE snapshot (NEW) — atomic-rename .staging/ → .snapshots/<id>/,
|
||||
append to index.json ring, evict oldest if
|
||||
append to index.yaml ring, evict oldest if
|
||||
>50, clear redo stack.
|
||||
On any failure in 1–4 → txn rolls back; DISCARD .staging/.
|
||||
```
|
||||
@@ -296,7 +296,7 @@ Mirrors the existing two-phase `rebuild` modal flow, with the
|
||||
|
||||
1. `undo` parses to `Command::App(AppCommand::Undo)` →
|
||||
`dispatch_app_command` returns `Action::PrepareUndo`.
|
||||
2. Runtime handles `PrepareUndo`: reads `.snapshots/index.json` top
|
||||
2. Runtime handles `PrepareUndo`: reads `.snapshots/index.yaml` top
|
||||
entry (command text + timestamp) — a cheap file read, like
|
||||
`summarize_project` does for rebuild — and posts
|
||||
`AppEvent::UndoPrepared { command, when }` (or
|
||||
@@ -356,7 +356,7 @@ primitive collapses a batch to a single ring entry:
|
||||
| `src/app.rs` | `Modal::UndoConfirm` (+ redo) struct; event arms; `handle_undo_confirm_key`; dispatch arms |
|
||||
| `src/ui.rs` | `render_undo_confirm` (mirror `render_rebuild_confirm`) |
|
||||
| `src/db.rs` | `is_mutating`; `stage/finalize/discard_snapshot`; `Request::Undo`/`Redo`/`BeginBatch`/`EndBatch`; dispatcher wrap; `undo_enabled` + `in_batch` worker fields |
|
||||
| `src/persistence/` (or new `src/snapshots/`) | ring + redo store, `index.json`, eviction, restore |
|
||||
| `src/undo.rs` (new) | snapshot ring + redo store, `index.yaml`, stage/finalize/discard/undo/redo/cleanup, eviction, restore (named `undo` — `src/snapshots/` is the insta dir) |
|
||||
| `src/runtime.rs` | `is_app_lifecycle_entry_word += undo,redo`; `PrepareUndo/Undo` (+redo) handling; thread `no_undo` to worker; bracket `run_replay` with Begin/EndBatch |
|
||||
| `src/project/mod.rs` | `.snapshots/` in `.gitignore` template |
|
||||
| `src/archive.rs` | exclude `.snapshots/` from export |
|
||||
@@ -423,7 +423,7 @@ explicit future items (hardlink optimisation) for user awareness.
|
||||
|
||||
1. **Cargo + CLI:** add `backup` feature; `--no-undo` flag + parse
|
||||
tests. (R14, R9-partial)
|
||||
2. **Snapshot store module:** `index.json` model, ring + redo, stage/
|
||||
2. **Snapshot store module:** `index.yaml` model, ring + redo, stage/
|
||||
finalize/discard/restore, eviction — Tier-1 tests first against a
|
||||
temp dir + in-memory/temp db. (R2, R3, R4, R6, R7)
|
||||
3. **Worker integration:** `is_mutating` (exhaustive), dispatcher wrap,
|
||||
|
||||
Reference in New Issue
Block a user