Files
rdbms-playground/docs/handoff/20260519-handoff-21.md
T
claude@clouddev1 02234e6c45 docs: handoff 21 — ADR-0028 complete
ADR-0028 (query plans / `explain`) is fully implemented; the
handoff-16 design trio (ADR-0026 / 0027 / 0028) is now closed.

- handoff-21: session summary, the two deliberate deviations
  from handoff-20's plan, test coverage, open clusters.
- requirements.md: QA1 / QA2 ticked.
- CLAUDE.md: the `EXPLAIN QUERY PLAN` deferred-items line
  updated to "implemented per ADR-0028".
2026-05-19 12:55:24 +00:00

162 lines
7.0 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-19 (21)
Twenty-first handover. This session **finished ADR-0028**
query plans / `explain`. Steps 25 (planned in full in
handoff-20 §3) are implemented, tested and committed; step 1
landed in the previous session. **ADR-0028 is complete**, and
with it the handoff-16 design trio (ADR-0026 / ADR-0027 /
ADR-0028) is fully implemented.
## State at handoff
**Branch:** `main`. Working tree clean. **3 feature commits**
this session (plus this handoff); all local — push
asynchronously, not blocking.
```
<this file> docs: handoff 21 — ADR-0028 complete
ae99276 explain: typing-surface matrix cells (ADR-0028 step 5)
a7d459f explain: styled plan tree + annotation taxonomy (step 4)
d17addd explain: `explain` command end to end (steps 23)
c1fcf28 docs: handoff 20 — ADR-0028 step 1 done, 2-5 planned
03d8a09 ui: styled-output-line mechanism (ADR-0028 step 1)
```
**Tests:** **1172 passing, 0 failing, 1 ignored** (`cargo
test`). The ignored test is the long-standing `` ```ignore ``
doc-test in `src/friendly/mod.rs`. Typing-surface matrix:
**174 cells** (was 161 — +13 for `explain`).
**Clippy:** clean (`cargo clippy --all-targets -- -D
warnings`, nursery group).
## §1. What ADR-0028 delivered
The `explain` prefix command — `explain show data …`,
`explain update …`, `explain delete from …` — captures a
query's plan via `EXPLAIN QUERY PLAN` and renders it as an
annotated, span-styled tree. `EXPLAIN QUERY PLAN` never
executes the wrapped statement, so explaining a destructive
`update` / `delete` is safe and changes nothing.
- **Grammar** (`src/dsl/grammar/data.rs`): a new `EXPLAIN`
`CommandNode` whose shape is a `Choice` over the three
explainable query shapes, reached through `Subgrammar` — the
inner command is parsed, completed and hinted exactly as it
is standalone. `Command::Explain { query: Box<Self> }`.
- **Worker** (`src/db.rs`): SQL construction split out of
`do_query_data` / `do_update` / `do_delete` into
`build_query_data_sql` / `build_update_sql` /
`build_delete_sql`, so `EXPLAIN QUERY PLAN` runs the exact
same statement. `Request::ExplainPlan` / `do_explain_plan`
capture the plan; `QueryPlan` / `ExplainRow` carry it back.
- **Display SQL**: the executed statement with `?N` params
inlined as standard-SQL literals (`<>` for inequality,
double-quoted idents, the implicit `ORDER BY <pk>` that
`limit` adds).
- **Render** (`src/output_render.rs`): `render_explain_plan`
draws the box-drawing tree; `PLAN_TAXONOMY` classifies each
node's `detail` and only the category-bearing keyword run
carries a semantic colour (efficient / expensive /
automatic-index). An automatic-index node also gets the
`← add an index?` advice tag.
- **Catalog**: `parse.usage.explain` plus `help.data.explain`
— `explain` appears in the in-app `help` listing.
## §2. Decisions / deviations from handoff-20's plan
handoff-20 §3 was followed closely. The three gotchas it
flagged all held — `static` wrappers (`EXPLAIN_SHOW_DATA`
etc.) for the `Subgrammar` `&'static` requirement; the
role-based `build_show_data` extraction; steps 2+3 combined
into one commit because the `Command::Explain` variant breaks
every exhaustive `match Command`. Two deliberate deviations:
1. **Display SQL via param-inlining, not a parallel
`compile_operand`.** handoff-20 suggested a second
literal-rendering variant of the WHERE compiler. Instead,
`inline_params_for_display` (`src/db.rs`) takes the
executed SQL and substitutes each `?N` with its bound
literal in a single quote-aware scan. This is structurally
guaranteed to match the executed statement and avoids a
second expression compiler that could drift from the
first. (`<>`, double-quoted idents and the implicit
`ORDER BY` all come for free — they are already in the
executed SQL.)
2. **`help_id: Some("data.explain")`, not `None`.**
handoff-20 planned no help entry; at the user's request
`explain` now has a `help.data.explain` catalog entry and
appears in `help` like every other command.
Other notes:
- `render_explain_plan` returns `Vec<OutputLine>` (styled).
Commit A built the tree with plain lines; commit B enriched
the *same* function with the taxonomy + styled runs — no
duplicated tree-walking logic.
- `explain` is **not** written to `history.log`
(`do_explain_plan` takes no `source`) — it is a read-only
diagnostic, and `EXPLAIN QUERY PLAN` does not execute.
- The plan tree renders wholly in the neutral foreground
colour (not the `System` green) so connectors / names stay
neutral per ADR-0028 §6; only category keywords are
coloured. Every plan line therefore carries a `styled_runs`
payload, including the display-SQL line.
## §3. Test coverage added
- **Parse** (`src/dsl/grammar/data.rs` `explain_tests`): each
wrapped form parses to `Command::Explain`; `explain` of an
incomplete inner command is the same parse error; `explain
show table` is rejected (`explain` covers `show data` only).
- **Worker** (`src/db.rs`): scan vs. index-search plans;
`explain delete` / `explain update` leave data untouched;
display SQL inlines literals, quotes idents, shows the
implicit `ORDER BY`, writes `<>`; missing-table errors.
- **Render** (`src/output_render.rs`): the taxonomy classes,
the automatic-index tag, neutral fallback, a cyclic-parent
guard.
- **App** (`src/app.rs`): the `DslExplainSucceeded` handler
renders the `[ok]` header, display SQL and tree.
- **Typing-surface matrix**: 13 cells in
`tests/typing_surface/explain.rs`.
## §4. What's next
ADR-0028 closes the handoff-16 design trio. No feature is in
flight. Open clusters, unchanged from handoff-16/17/18/19/20
(prioritisation is a **user decision — ask**):
- Snapshot / undo / replay `U`-series (designed in ADR-0006).
- Constraints `C3`; m:n convenience `C4`; modify-relationship
`C3a`; column drop/rename/type-change grammar `C1` (the
rebuild primitive exists).
- Friendly-error layer `H1` (partial); strong syntax-help in
parse errors `H1a`.
- Session-log / Markdown export `V4` — would be the first
real reuse of the `OutputLine` styled-runs mechanism beyond
the plan renderer.
- `SD1`; CI workflow `TT5`; readline shortcuts `I1b`;
multi-line input `I1`; `TU1`.
## §5. How to take over
1. **Read this file**, then `CLAUDE.md` (working-style
rules), then `docs/requirements.md` (per-item progress —
`QA1` / `QA2` now ticked).
2. **Run `cargo test`** — 1172 passing, 0 failing, 1 ignored.
3. **Run `cargo clippy --all-targets -- -D warnings`** —
clean.
4. Pick the next cluster *with the user* — §4 has no default.
### Note on the typing-surface matrix
`tests/typing_surface/` is **174 cells**. The matrix-snapshot
discipline from handoff-17/18/19/20 stands: a failing cell
with *correct* new behaviour → update its snapshot; with
*wrong* behaviour → the cell earned its keep. `cargo insta`
is not installed on this machine — regenerate snapshots with
`INSTA_UPDATE=always cargo test --test typing_surface_matrix
<filter>` and review the written `.snap` files before
committing.