docs: session handoff 36 — ADR-0006 (undo/snapshot) shipped; ADR-0035 (SQL DDL) drafted, 4a next
This commit is contained in:
@@ -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 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.
|
||||
Reference in New Issue
Block a user