# Session handoff — 2026-05-19 (24) Twenty-fourth handover. A **design-only** session: it wrote and accepted **ADR-0030 — Advanced mode: the standard-SQL surface**. No code changed. A fresh session implements ADR-0030 from this file + the ADR, starting at Phase 1. ## §1. State at handoff **Branch:** `main`. Working tree clean (after this docs commit). The session's commits since handoff-23 are docs-only — ADR-0030, the ADR index, the `requirements.md` updates, and this handoff. All local; push asynchronously, not blocking. **Tests:** unchanged — **1240 passing, 0 failing, 1 ignored** as of `a049ff9` (ADR-0029 complete). This session touched no code. **Clippy:** clean as of the same commit. ## §2. What was decided — ADR-0030 Read **`docs/adr/0030-advanced-mode-sql-surface.md`** — the spec, complete and accepted. Its shape, and *why* it landed where it did (the design went through two rounds of user input — §3 records the reasoning so it is not relitigated): - **SQL is grammar in the unified tree, not a separate parser (§1).** SQL statements are authored as `CommandNode` / `Node` grammar in the ADR-0024 tree and parsed by the existing walker. `sqlparser-rs` is **not** used — ADR-0001's reservation is superseded. The reason is decisive: a batch SQL parser produces an AST and nothing else; it cannot drive completion, highlighting, or hints. The user requires SQL to have the *same* ambient assistance as the DSL — and that assistance comes only from the unified grammar tree (ADR-0022/0023/0024). So SQL must live in the tree. - **Mode gates the grammar (§2).** One grammar tree; simple mode exposes the DSL subset, advanced mode adds the SQL forms. Shared entry words (`create`, `insert`, …) get a `Choice` of DSL + SQL forms under one `CommandNode` (how `add` already holds four sub-commands); `select` is a new SQL-only entry word. - **Execution split (§4).** DDL → a typed `Command` → the existing executor, so metadata, the playground type vocabulary, and `STRICT` are preserved. DML and `SELECT` → executed as **validated SQL** (they change no schema, so a typed `Command` buys nothing); the worker re-persists the affected table after DML. - **Engine-neutral (§5, §7).** Playground type vocabulary, never engine storage types; no `STRICT` surfaced; engine-neutral errors. Advanced mode is *standard SQL*, not an engine console. - **Assistance for free (§8).** Because SQL is in the tree, the walker gives SQL completion, highlighting, hint prose, the `[ERR]`/`[WRN]` indicator, and parse-error usage — the same as the DSL, no SQL-specific assistance code. - **The DSL→SQL teaching echo (§10).** A DSL command run in advanced mode also prints its equivalent SQL. - **Persistence / replay (§11).** DDL via `Command` keeps `project.yaml` correct; DML re-persists its table; `history.log` stores the literal line; replay re-runs lines through the one walker. ### §3. Decisions the user made (do not relitigate) 1. **Full SQL scope** — DDL + DML + the full `SELECT` query surface (joins, aggregates, `GROUP BY`/`HAVING`, subqueries, `UNION`, CTEs). No pre-emptive cuts; if a slice proves *genuinely* overwhelming, cutting it is an explicit escalation to the user, never a silent trim. 2. **No fallback to engine types** — advanced DDL keeps the playground's rich type vocabulary. The `SQL → Command` path for DDL is what guarantees this. 3. **Advanced mode is standard SQL, engine-independent** — not a SQLite console; no engine-specifics surface. 4. **SQL lives in the unified grammar tree** (not a separate batch parser) — chosen specifically so SQL gets full completion / highlighting / hints. The user understood and accepted that this means authoring a SQL grammar ourselves; `sqlparser-rs` is dropped. 5. **`Command` only where it pays.** DDL → `Command` (buys metadata + types); DML / `SELECT` → validated SQL (a `Command` buys nothing). 6. **The DSL→SQL echo shows in advanced mode only.** 7. The persisted / replayable representation must be app-enterable syntax — `history.log` already stores the literal line, so this holds. ## §4. The phased implementation plan ADR-0030 §Implementation is canonical. Each phase is independently shippable and test-guarded. The two large grammar slices each warrant their **own focused ADR** when taken up (precedent: ADR-0026 for the `WHERE` grammar). 1. **Foundations + first `SELECT`.** Mode-gate the grammar (advanced unlocks the SQL nodes). Author the core SQL **expression grammar** — the ADR-0026 superset (arithmetic, function calls, `CASE`, the predicate set) — *its own ADR*. A single-table `SELECT` (projection, `WHERE`, `ORDER BY`, `LIMIT`) as a SQL `CommandNode` → `Command::Select` → worker `RunSelect` → the existing data-table renderer. Replace the placeholder echo; add the simple-mode "this is SQL" hint. Proves the path end to end *with full walker assistance*. 2. **`SELECT` — full.** `JOIN`s, `GROUP BY`/`HAVING`, aggregates, subqueries, `UNION`, CTEs — *its own ADR*. 3. **DML.** `INSERT`/`UPDATE`/`DELETE` grammar; the execute-as-validated-SQL path; the worker re-persist step; settle multi-row `INSERT` and `shortid` auto-fill on a SQL `INSERT`. 4. **DDL.** `CREATE`/`DROP`/`ALTER TABLE`, `CREATE`/`DROP INDEX` grammar → `Command`; the §5 type-name map; FK clauses → `AddRelationship`; may land table-rename (`C1`). 5. **The DSL→SQL teaching echo** (§10). 6. **Polish** — `help sql`; engine-neutral error sweep; typing-surface / matrix coverage; the `DOC1` SQL-surface reference page. ## §5. Seams for the implementer (from a code survey) Anchors for Phase 1: - **The placeholder to replace:** `App::submit` (`src/app.rs` ~954–1014) — the advanced-mode branch echoes the input with `advanced_mode.not_implemented` (~996–1012) and sends nothing to the worker. The DSL dispatch path (`dispatch_dsl`, ~1089) is what advanced SQL joins. - **The grammar tree:** `src/dsl/grammar/` — `mod.rs` holds `Node`, `CommandNode`, the `REGISTRY`; `ddl.rs` / `data.rs` hold the DSL command grammars; `expr.rs` holds the ADR-0026 expression grammar (the seed for the SQL expression grammar); `shared.rs` shared fragments. The walker is in `src/dsl/walker/`. SQL grammar is authored here; mode-gating is added to the `REGISTRY` / walker. - **Command core:** `Command` in `src/dsl/command.rs` — add a `Select` variant. **Gotcha:** every exhaustive `match Command` breaks (`verb` / `target_table` / `display_subject` in `command.rs`; `execute_command_typed` in `runtime.rs`; `build_translate_context` in `app.rs`; `command_kind_label` in `tests/typing_surface/mod.rs`) — the ADR-0028/0029 pattern. - **Worker:** `Request` enum + `handle_request` + the `Database` method wrappers in `src/db.rs` (~444 on) — add `RunSelect` (returns `DataResult`), and later a "run validated DML + re-persist" request. - **Result rendering:** a `Select` outcome → `CommandOutcome::Query` → `AppEvent::DslDataSucceeded` → `output_render::render_data_table` — all reused from `show data`. - **Mode:** `src/mode.rs` (`Mode::Simple`/`Advanced`); `App::effective_mode` and the `:`-strip in `App::submit` already work — the mode-gated grammar view plugs in there. - **`sqlparser-rs` is not used** — do not add it (an implementer may keep it only as a test oracle, off the execution path). - **Risk:** the `Node` taxonomy / walker may need extension to carry SQL's grammar (deeper recursion for subqueries / CTEs). Expect node-taxonomy work in Phases 1–2; ADR-0030 flags this. ## §6. How to take over 1. **Read this file, then `docs/adr/0030-advanced-mode-sql- surface.md`** (the spec). Then `CLAUDE.md` (working-style rules), `docs/requirements.md` (`Q4` ticked; `Q1`/`Q2` unblocked), and skim `docs/simple-mode-limitations.md` — ADR-0030 §4 commits advanced mode to lifting the expression limits that file records. 2. **Run `cargo test`** — 1240 passing, 0 failing, 1 ignored. 3. **Run `cargo clippy --all-targets -- -D warnings`** — clean. 4. **Start ADR-0030 Phase 1.** First sub-step is the SQL **expression grammar** — write its focused ADR before authoring it (ADR-0026 is the model and the seed). Then the single-table `SELECT` end to end. Land the `Command:: Select` match-arm sweep with the worker request in one commit (the exhaustive-match breakage forces it). 5. Escalate, do not guess, on anything ADR-0030 left per-phase — multi-row `INSERT`, `shortid` on SQL `INSERT`, any `Node`-taxonomy extension that changes the walker's contract. ## §7. What else is open ADR-0030 is the active design. Other open clusters, unchanged from handoff-23 §5 (prioritisation is a **user decision**): snapshot/undo `U`-series (ADR-0006 written, unbuilt); m:n convenience `C4`; modify-relationship `C3a`; the `show` family `V5`; rename-table `C1` (may fall out of ADR-0030 Phase 4); friendly-error sweep `H1`; CI `TT5`; session-log / Markdown export `V4`.