Files
rdbms-playground/docs/handoff/20260524-handoff-36.md
T

212 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.