Iteration 6: --resume + persistent input history + migration scaffold

Closes out track 2's ADR-0015 backlog.

* `--resume` CLI flag (L1a, ADR-0015 §7) opens the most-
  recently-used project, tracked in <data-root>/last_project.
  Mutually exclusive with a positional <project-path>; errors
  cleanly to stderr (above the shell prompt) on missing file
  or stale recorded path. last_project is rewritten on every
  successful project open (startup, load, new, save as,
  import).
* Persistent input history (I2-persist, ADR-0015 §12). On
  project open, the in-memory navigable history is hydrated
  from the tail of history.log (capped at the in-memory cap).
  ProjectSwitched gains a `history_entries` payload field;
  App::seed_history is the entry point. Pipes inside source
  text round-trip via splitn(3); unknown escape sequences are
  passed through literally.
* Migration framework scaffold (F3, ADR-0015 §9). New
  persistence::migrations module with MigratorRegistry +
  migrate_to_latest + ensure_project_yaml_migrated. Empty
  in v1 (production registry has no migrators); the loader
  runs through it on every project open and is exercised by
  tests with a fake v1→v2 migrator. Writes
  project.yaml.v<N>.bak before any migrator runs; verifies
  each step bumps the version field.

Refreshes docs/requirements.md (A1 / I2 / F3 / E1 / L1a /
test baseline) and adds docs/handoff/20260508-handoff-3.md
covering both Iter 5 and Iter 6.

Total tests: 408 passing, 0 failing, 0 skipped (up from 345
at handoff-2). Clippy clean.
This commit is contained in:
claude@clouddev1
2026-05-08 08:27:50 +00:00
parent c6cf3df6dc
commit 67d68db5f8
12 changed files with 1544 additions and 34 deletions
+41 -25
View File
@@ -26,10 +26,10 @@ repo is pushed).
## Test baseline
No test suite exists yet — the repo currently contains only
docs. The baseline is therefore "0 passing, 0 failing, 0
skipped." Subsequent phases establish the suite and measure
against it.
After Iterations 5 + 6 (export/import + --resume + persistent
input history + migration scaffold): **408 passing, 0 failing,
0 skipped** (`cargo test`). Clippy clean with the nursery
lint group enabled.
---
@@ -72,13 +72,12 @@ against it.
keys (and for ergonomics in command-driven workflows). Likely
followed by Ctrl-W (delete previous word), Ctrl-K (delete to
end), Ctrl-U (delete to start). Pending.
- [ ] **I2** Persistent navigable input history (project-scoped,
with a global rolling history also available).
*(Progress: in-memory navigable history is implemented; the
on-disk record is `history.log` (Iteration 2). What's still
missing for I2 is hydrating the navigable history from
`history.log` on project open — Iteration 6. Global rolling
history deferred per OOS-6 / N4.)*
- [x] **I2** Persistent navigable input history (project-scoped).
*(Implemented across Iterations 2 + 6: per-command append to
`history.log` (Iter 2); on project open, the in-memory
navigable history is hydrated from the tail of
`history.log` up to the same in-memory cap (Iter 6). Global
rolling history is out of scope per OOS-6 / N4.)*
- [ ] **I3** Tab completion for app commands, DSL keywords, table
names, column names, and SQL keywords.
- [ ] **I4** Syntax highlighting for both the DSL and SQL.
@@ -104,10 +103,10 @@ against it.
`rebuild`, `export`, `import`, `seed`, `replay`, `undo`,
`redo`, `mode`, `help`, `hint`, `quit`.
*(Progress: `quit`/`q`, `mode simple|advanced`, `help` (basic
listing), `save`, `save as`, `load`, `new`, `rebuild` all
implemented (Iteration 4). `export` / `import` land in track
2's Iteration 5; `seed` in the seeding iteration; `replay` /
`undo` / `redo` in the U-series; `hint` with H2.)*
listing), `save`, `save as`, `load`, `new`, `rebuild`,
`export`, `import` all implemented (Iterations 4 + 5). `seed`
in the seeding iteration; `replay` / `undo` / `redo` in the
U-series; `hint` with H2.)*
## DSL data commands
@@ -277,8 +276,16 @@ against it.
in each new project (Iteration 1). Per ADR-0007 amendment
1, `history.log` is NOT in the template — user decides
whether to commit it.
- [ ] **F3** Migration framework — pending Iteration 6.
Scaffold (no migrators yet) is the v1 deliverable.
- [x] **F3** Migration framework scaffold (Iteration 6).
`MigratorRegistry` + `migrate_to_latest` +
`ensure_project_yaml_migrated` are wired into every project
open; no migrators registered in v1 (the production
registry is empty). The framework is exercised by tests
that inject a fake v1→v2 migrator: registry plumbing,
`.v<N>.bak` backup, version-bump sanity check, and
newer-than-supported / malformed-version errors are all
covered. The first real migrator (when v2 ships) is a
one-file change.
## Undo and replay (per ADR-0006)
@@ -295,9 +302,15 @@ against it.
## Sharing and export (per ADR-0007)
- [ ] **E1** `export` produces a zip excluding `playground.db`;
default filename `YYYYMMDD-<projectname>-export-NN.zip` with a
non-clobbering two-digit sequence.
- [x] **E1** `export` produces a zip excluding `playground.db`
AND `history.log` (per ADR-0007 amendment 1); default
filename `YYYYMMDD-<projectname>-export-NN.zip` with a
non-clobbering two-digit sequence under the active data root
(Iteration 5). The zip preserves the project's directory
name as a single top-level folder. `import <zip> [as <t>]`
is the inverse: derive target name from the zip's top
folder, auto-suffix `-NN` on collision (ADR-0015 §11
amendment), rebuild from text on open.
- [ ] **E2** User documentation includes sharing recipes for
git, email, and direct file transfer.
@@ -347,11 +360,14 @@ against it.
- [x] **L1** Load a project via a positional CLI argument
(Iteration 1). Plus `--data-dir` to override the data root
and `--help` / `-h` for the usage banner.
- [ ] **L1a** `--resume` CLI flag opens the most recently used
project (path tracked in `<data-root>/last_project`). Errors
cleanly if no previous project exists or the recorded path is
gone; mutually exclusive with a positional path argument
(ADR-0015 §7). Pending Iteration 6.
- [x] **L1a** `--resume` CLI flag opens the most recently used
project (path tracked in `<data-root>/last_project`).
Iteration 6: errors cleanly with a stderr banner above the
shell prompt if no previous project is recorded or the
recorded path is gone — no silent fallback; mutually
exclusive with a positional path argument (ADR-0015 §7).
`last_project` is rewritten on every successful project
open (startup, load, new, save as, import).
- [~] **L2** Submit a command alongside project load — deferred,
not v1.