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:
claude@clouddev1
2026-05-24 20:17:03 +00:00
parent 6cf5705022
commit 64eee3ed6d
7 changed files with 824 additions and 7 deletions
+8
View File
@@ -32,6 +32,14 @@ mod yaml;
pub(crate) use csv_io::{decode_cell, parse_csv};
pub(crate) use yaml::parse_schema;
/// Current UTC time as an ISO-8601 `Z` string — the same shape
/// `history.log` records (ADR-0015 §5). Exposed crate-wide so the
/// undo snapshot ring (ADR-0006) timestamps entries identically.
#[must_use]
pub(crate) fn utc_iso8601_now() -> String {
history::utc_iso8601_now()
}
/// Owns persistence to a single project on disk. Cheap to
/// move; the db worker holds one instance for its lifetime.
#[derive(Debug, Clone)]