docs: ADR-0006 §8 step 8 — mark undo/snapshot implemented

- requirements.md U1/U2: [ ] -> [x] with implementation notes
- CLAUDE.md Safety bullet: implemented; drop U-series from the
  deliberately-deferred list
- ADR-0006 Amendment 1: "not yet implemented" -> implemented, plus an
  Implementation note (index.yaml, source-gated snapshots, non-fatal
  snapshot-failure policy, batch primitive, testing + accepted gaps)
- ADR README index: undo/snapshot half marked implemented
This commit is contained in:
claude@clouddev1
2026-05-24 20:58:31 +00:00
parent cf53023a71
commit 5442cfc0b9
4 changed files with 54 additions and 15 deletions
+38 -2
View File
@@ -96,8 +96,8 @@ implementation, and **supersedes the original Decision's
"snapshots only before destructive operations" model** and its
confirmation rationale. Written with explicit user approval; the
implementation plan is `docs/plans/20260524-adr-0006-undo-snapshots.md`.
**Not yet implemented** at the time of writing — this records the
agreed design.
**Implemented 2026-05-24** (see the Implementation note at the end of
this amendment).
### Snapshot scope — every mutation (single-step undo)
@@ -207,3 +207,39 @@ is turned off. CLI-only for v1 (no in-app toggle).
- The Phase-3 N/A matrix row ("auto-snapshot fires for SQL DML the same
as DSL") becomes non-vacuous: the snapshot hook lives in the worker
dispatch and covers DSL and SQL mutations uniformly.
### Implementation note (2026-05-24)
Shipped across §8 steps 17 of the plan. Details and decisions made
during implementation, user-confirmed where they extended the design:
- **Ring storage** is `src/undo.rs` (`SnapshotStore`): per-snapshot
payload dirs under `<project>/.snapshots/<id>/` plus an
**`index.yaml`** manifest (YAML reuses the existing `serde_yml`
dependency — no `serde_json` added). Monotonic ids, reconciled
against on-disk dirs so a crash can't reuse one; `cleanup()` on
open sweeps `.staging/` and orphan payloads.
- **Worker hook**: `snapshot_then` brackets all 19 mutating dispatch
arms in `src/db.rs` (stage → run → finalise/discard); restore
(undo/redo) runs in `worker_loop` with `&mut Connection`. Snapshots
are **gated on a user command `source`** — internal operations that
pass `source = None` (notably the open-time rebuild when `.db` is
missing) are not recorded, so `rebuild` is undoable as a user
command but opening a project never creates a spurious entry.
- **Snapshot-failure policy** (user-confirmed): staging / finalise /
discard failures are **non-fatal** (logged) — the real persistence
is the durable state and a backup hiccup must not fail the user's
work. Only *restore* failures surface (as `UndoFailed`).
- **Batch** uses `BeginBatch`/`EndBatch` worker requests; `replay`
wraps its loop so a multi-command replay is one undo step,
finalised only if a mutation committed.
- **Testing**: `src/undo.rs` Tier-1 (ring/redo/eviction/restore),
`tests/undo_snapshots.rs` Tier-3 (worker, DSL+SQL, db+csv
consistency, persistence across reopen), plus App-level Tier-1
(dispatch/modal) and parse/replay-filter tests. The thin runtime
glue (`spawn_prepare_undo` / `spawn_undo` + Action arms) is not
loop-tested — the same accepted gap recorded for ADR-0034, with the
App side and worker side each tested. No Tier-2 insta render test
was added for the confirmation modal: the existing modals
(`rebuild` / path / load) are tested at the state level only, and
the undo modal matches that.
+1 -1
View File
@@ -11,7 +11,7 @@ This directory contains the project's ADRs, recorded per
- [ADR-0003 — Input modes and command dispatch](0003-input-modes-and-command-dispatch.md)
- [ADR-0004 — Project file format](0004-project-file-format.md)
- [ADR-0005 — Column type vocabulary](0005-column-type-vocabulary.md)
- [ADR-0006 — Undo snapshots and replay log](0006-undo-snapshots-and-replay-log.md) — **Accepted**. The **replay/journal half** (U3/U4) shipped via ADR-0034; the **undo/snapshot half** (U1/U2) is settled by **Amendment 1 (2026-05-24)** but **not yet implemented** (plan: `docs/plans/20260524-adr-0006-undo-snapshots.md`). Amendment 1 **supersedes the original "snapshots only before destructive operations" model**: a snapshot is taken before **every** data/schema mutation (DSL + SQL) for familiar single-step (Ctrl-Z) undo — so the confirmation collapses to *naming the one command being undone* (no db-diff). Snapshot is a **hybrid whole-project copy** — database via the online backup API **plus** `project.yaml`/`data/*.csv` as files — reconciling this ADR with ADR-0015's "text is authoritative, db is derived"; undo restores all three directly. Staged before the mutation's transaction, finalised after the db commit (preserves ADR-0015 §6 commit-db-last); rolled-back ops leave no snapshot. **Persisted** ring under `.snapshots/`, **N = 50** (raised from 10), git-ignored + export-excluded + temp-cleanup-aware. `redo` supported, **redo stack discarded on new work**. **Batch ops record one undo step** (`replay` + future batch via a Begin/EndBatch worker primitive); **`import` is outside undo** (it switches projects per ADR-0015 §11, leaving the current project untouched). A **`--no-undo` CLI flag** disables snapshotting (hardware escape hatch). Adds the `backup` feature to `rusqlite`
- [ADR-0006 — Undo snapshots and replay log](0006-undo-snapshots-and-replay-log.md) — **Accepted**. The **replay/journal half** (U3/U4) shipped via ADR-0034; the **undo/snapshot half** (U1/U2) is settled by **Amendment 1 (2026-05-24)** and **implemented 2026-05-24** (plan: `docs/plans/20260524-adr-0006-undo-snapshots.md`; ring in `src/undo.rs`, worker hook in `src/db.rs`). Amendment 1 **supersedes the original "snapshots only before destructive operations" model**: a snapshot is taken before **every** data/schema mutation (DSL + SQL) for familiar single-step (Ctrl-Z) undo — so the confirmation collapses to *naming the one command being undone* (no db-diff). Snapshot is a **hybrid whole-project copy** — database via the online backup API **plus** `project.yaml`/`data/*.csv` as files — reconciling this ADR with ADR-0015's "text is authoritative, db is derived"; undo restores all three directly. Staged before the mutation's transaction, finalised after the db commit (preserves ADR-0015 §6 commit-db-last); rolled-back ops leave no snapshot. **Persisted** ring under `.snapshots/`, **N = 50** (raised from 10), git-ignored + export-excluded + temp-cleanup-aware. `redo` supported, **redo stack discarded on new work**. **Batch ops record one undo step** (`replay` + future batch via a Begin/EndBatch worker primitive); **`import` is outside undo** (it switches projects per ADR-0015 §11, leaving the current project untouched). A **`--no-undo` CLI flag** disables snapshotting (hardware escape hatch). Adds the `backup` feature to `rusqlite`
- [ADR-0007 — Sharing and export](0007-sharing-and-export.md)
- [ADR-0008 — Testing approach](0008-testing-approach.md)
- [ADR-0009 — DSL command syntax conventions](0009-dsl-command-syntax-conventions.md)