# Session handoff — 2026-05-24 (36)

Thirty-sixth handover. This session **implemented ADR-0006
(undo/snapshot) end-to-end** (§8 steps 1–8 + 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 1–8 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 4a–4i**
   (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.
