docs: session handoff 36 — ADR-0006 (undo/snapshot) shipped; ADR-0035 (SQL DDL) drafted, 4a next

This commit is contained in:
claude@clouddev1
2026-05-24 22:16:10 +00:00
parent a079200b17
commit f74226fe8c
+211
View File
@@ -0,0 +1,211 @@
# Session handoff — 2026-05-24 (36)
Thirty-sixth handover. This session **implemented ADR-0006
(undo/snapshot) end-to-end** (§8 steps 18 + a `/runda` data-loss
fix) and then **drafted ADR-0035 — advanced-mode SQL DDL** (Phase 4
of the ADR-0030 roadmap, status **Proposed**). The next session
**begins implementing ADR-0035, starting at sub-phase 4a**. See §4.
## §1. State at handoff
**Branch:** `main`. **Tests: 1698 passing, 0 failing, 0 skipped,
1 ignored** (the unchanged `friendly/mod.rs` doctest). **Clippy:**
clean (`cargo clippy --all-targets -- -D warnings`).
**Latest commit (local-only):**
```
a079200 docs: ADR-0035 — advanced-mode SQL DDL (Phase 4)
```
`origin/main` is at `df6aa69`; **1 commit is local-only** (a079200).
The undo/snapshot work (through `df6aa69`) is already pushed.
Unpushed commits are a normal working state; pushing is the user's
step — do not prompt about it.
## §2. What shipped this session
- **ADR-0006 (undo/snapshot) fully implemented** — the U1/U2 half;
the replay/journal half (U3/U4) had shipped via ADR-0034. Built
across §8 steps 18 of the plan
(`docs/plans/20260524-adr-0006-undo-snapshots.md`):
- `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 the online
backup API + `project.yaml`/`data/*.csv` copied; restore is
text-first, db-last (ADR-0015 §6).
- `src/db.rs``snapshot_then` brackets all **19 mutating dispatch
arms** (stage→run→finalise/discard), gated on a **user command
`source`** (internal ops like open-time rebuild are *not*
snapshotted); `BeginBatch`/`EndBatch` (a `replay`/batch = one undo
step); `Undo`/`Redo`/`PeekUndo`/`PeekRedo` handled in
`worker_loop` with `&mut conn`.
- `undo`/`redo` app commands + `Modal::UndoConfirm` confirm flow;
`--no-undo` CLI flag; `.snapshots/` git-ignored + export-excluded
+ temp-cleanup-allowlisted.
- **`/runda` found + fixed a silent data-loss bug**: a committed
mutation whose snapshot couldn't be *staged* left the redo stack
stale (redo-clear was a side effect of `finalize`), so a later
`redo` discarded the new work. Now `clear_redo` runs on that path
(`snapshot_then`/`end_batch`); commit `df6aa69`, regression-tested.
- ADR-0006 marked implemented (Amendment 1 + Implementation note);
`requirements.md` U1/U2 → `[x]`; `CLAUDE.md` updated.
- **ADR-0035 drafted** (`docs/adr/0035-advanced-mode-sql-ddl.md`,
commit `a079200`, **Proposed**) — the next job (§3/§4).
## §3. ADR-0035 design — settled with the user (do not re-litigate)
All user-confirmed through discussion this session.
1. **Own per-statement `Sql*` DDL commands**`SqlCreateTable`,
`SqlAlterTable`, `SqlDropTable`, `SqlCreateIndex`, `SqlDropIndex`
(granularity mirrors the DML `Sql*` set). **Clarifies ADR-0030 §4**:
DDL gets its own advanced commands, but **unlike DML they execute
*structurally*, not verbatim** — raw execution would lose the
playground's types, named relationships, and `STRICT`. ("Verbatim"
for DML was a convenience, not a rule.) **Simple mode is untouched**
(additive). Handlers **reuse the low-level schema/metadata helpers**
where the op matches simple mode, **stand alone where the SQL
surface is richer** (multi-FK `CREATE TABLE`) — clarity over forced
refactoring.
2. **Dispatch:** `create`/`drop` reuse ADR-0033 Amendment 1's
category-grouped, mode-aware dispatch (SQL-first in advanced, simple
fallback); **`alter` is a new advanced-only entry word.**
3. **Type vocabulary** (ADR-0030 §5): playground keywords + standard-SQL
aliases mapped (`integer``int`, `varchar``text`, `timestamp`
`datetime`, …); length args accepted-and-ignored; no engine type
names in/out.
4. **FK → named relationships:** inline `REFERENCES` + table-level
`FOREIGN KEY` create the table **and** its relationship metadata in
one command (= **one undo step**); `ON DELETE`/`ON UPDATE`
ADR-0013 actions; constraint name → relationship name.
5. **Column-type conversion — unified** (ADR-0017 engine, mode policy):
clean auto-converts both modes; incompatible + own-type-static cases
refuse both modes; **lossy refuses-by-default in simple mode
(`--force-conversion`), but advanced mode performs it with a post-op
loss note and relies on `undo` as the net** (no force flag, no
dropping to simple mode).
6. **Table rename (`C1`)** — advanced-only `ALTER TABLE … RENAME TO`;
**new low-level op** (rename table + its CSV file + the relationship
metadata rows). No simple-mode form.
7. **Surface** = full, no pre-emptive cuts; **9 sub-phases 4a4i**
(ADR §13), each with exit + DA gates.
8. **Integration is structural, not free of authoring** (ADR §11):
the walker *mechanisms* (highlighting, `[ERR]`/`[WRN]`, usage
skeleton, completion engine) come free; each node still **authors**
the right `IdentSource` on schema-name slots, its hint/usage catalog
keys, and DDL-specific walker diagnostics (the DDL peers of the DML
ones ADR-0033 added).
9. **Replay:** `create`/`drop`/`alter` are schema-write entry words,
**not** in ADR-0034's app-lifecycle skip set, so SQL DDL **replays
as a write — no replay-filter change** (unlike `undo`/`redo`).
## §4. ADR-0035 implementation — the NEXT job
**Begin Phase 4 at sub-phase 4a**, test-first, following the ADR-0033
sub-phase model. **Recommended first action:** read ADR-0035 in full,
then write a short plan doc
(`docs/plans/<date>-adr-0035-sql-ddl.md`) and confirm any open
micro-calls with the user before coding — exactly how ADR-0033/0034/
0006 were run.
**Sub-phases (ADR-0035 §13):**
- **4a** — dispatch + `CREATE TABLE` core (columns + the §3 type map +
column constraints + single/compound `PRIMARY KEY`); no FK yet.
- **4b** — FK in `CREATE TABLE` (inline + table-level) → relationships.
- **4c** — `DROP TABLE`.
- **4d** — `CREATE [UNIQUE] INDEX` / `DROP INDEX`.
- **4e** — `ALTER TABLE` add/drop/rename column.
- **4f** — `ALTER TABLE … ALTER COLUMN TYPE` (the §7 conversion model).
- **4g** — `ALTER TABLE` add/drop constraint, add FK.
- **4h** — `ALTER TABLE … RENAME TO` (the §6 new low-level op).
- **4i** — verification sweep (typing-surface/matrix, engine-neutral
errors, undo parity, `help`/usage).
**Concrete must-not-forget for the implementer:**
- **Undo wiring for the new commands.** Each `Sql*` DDL command becomes
a **new `Request` variant in `src/db.rs`** and **must be wrapped with
`snapshot_then`** like the existing 19 mutating arms (so it's one undo
step). `handle_request`'s exhaustive match will force you to handle
each new variant — wrap it, don't `reply.send` it raw. `create`/
`drop`/`alter` need **no** `is_app_lifecycle_entry_word` change
(they're writes, §3.9).
- **Grammar lives in `src/dsl/grammar/`** (`CommandNode` + the
`REGISTRY` in `mod.rs`, tagged `CommandCategory`); mirror the
ADR-0033 DML nodes (`src/dsl/grammar/sql_*`). `CHECK`/`DEFAULT`
expressions reuse the ADR-0031 `sql_expr` fragment.
- **`ALTER`/column ops build on the ADR-0013 rebuild-table primitive**
(already used by drop/rename/change-column).
- **Catalog + keys lockstep** (`src/friendly/strings/en-US.yaml` +
`src/friendly/keys.rs`, validated by `keys_validate_against_catalog`):
every new `help_id`/`usage_id`/diagnostic key needs both a catalog
body and a keys.rs entry; engine-neutral wording (the vocab audit
enforces it).
- **Tests:** four tiers (ADR-0008). Per-sub-phase Tier-3 like
`tests/sql_insert.rs`/`sql_update.rs`/`sql_delete.rs`, plus an
end-to-end `tests/sql_ddl_e2e.rs` (mirror `sql_dml_e2e.rs`), plus
typing-surface/matrix coverage. **Add a DDL undo test** (each
statement = one undo step; `CREATE TABLE` with FK = one step).
**Open micro-calls to escalate when reached** (not yet decided):
- `CREATE UNIQUE INDEX` — ADR-0025's index model may need a `unique`
flag (ADR §4/§13 4d flags this).
- Exact `ALTER COLUMN … TYPE` spelling, and whether `IF [NOT] EXISTS`
is admitted or an ordinary parse error (ADR §12 leans OOS).
- Status flip: ADR-0035 is **Proposed**; flip to **Accepted** once 4a
validates the path end-to-end (the ADR-0033 lifecycle).
## §5. Other tracked deferred items (nothing lost)
- **(A)** App-lifecycle-command *runtime*-failure journalling (small
ADR-0034 follow-up; recorded in ADR-0034's Implementation note).
- **M4** — execution-time mode side-channel (deferred by ADR-0033
Amendment 3; needs its own ADR).
- **`blob` value literal** (`src/dsl/value.rs`) — pre-existing gap.
- **Undo residual edge** (ADR-0006 Implementation note): if the entire
`.snapshots/` dir is unwritable, `clear_redo` can also fail and a
stale redo could survive — accepted (whole undo subsystem is broken
then).
- **CI / TT5**, **DSL→SQL teaching echo** (ADR-0030 Phase 5), **DDL as
the last SQL phase before §6 polish**.
## §6. Process pins (unchanged, still binding)
- **Confirm every commit.** Propose the message; wait for the go-ahead.
(Every commit this session was user-approved.)
- **Push is the user's step.** Never push; never prompt about it.
- **No AI attribution** in commits (global rule).
- **Probe, don't reason.** The `/runda` round this session found a real
silent-data-loss bug by *running a throwaway probe*, not by
reasoning. Reproduce/print before concluding; delete probes before
committing.
- **Escalate ADR-vs-implementation mismatches and scope calls.** The
whole ADR-0035 design was settled by escalating (the
reuse-vs-own-command question, the conversion model) rather than
guessing — and corrected twice when the user pushed back.
- **Keep docs in lockstep.** ADR status flips update
`docs/adr/README.md` in the same edit; behaviour changes update
`requirements.md`.
- **Terminology:** the **DSL is the one unified command grammar**;
the real axis is **mode-availability** (simple / advanced / both),
not "DSL vs SQL". Avoid calling simple-mode commands "the DSL".
## §7. How to take over
1. **Read, in order:** this file → `docs/adr/0035-advanced-mode-sql-ddl.md`
(**the next job**) → `docs/adr/0030-advanced-mode-sql-surface.md`
(§4/§5 architecture) + `docs/adr/0033-sql-dml-grammar.md` (the
dispatch + sub-phase precedent to mirror) → `CLAUDE.md`
`docs/requirements.md` (`Q4`/`C1`).
2. **Baseline:**
```
cargo test # expect 1698 passing / 0 failing / 0 skipped / 1 ignored
cargo clippy --all-targets -- -D warnings # clean
```
3. **Start ADR-0035** per §4: read the ADR, draft a short plan, confirm
the open micro-calls with the user, then implement 4a test-first.
4. **Escalate** anything not settled in ADR-0035; the user wants
mismatches and scope calls surfaced, not silently decided.