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".
This commit is contained in:
@@ -184,9 +184,8 @@ not yet implemented:
|
|||||||
rebuild-table primitive (ADR-0013) is in place; the grammar
|
rebuild-table primitive (ADR-0013) is in place; the grammar
|
||||||
and dispatch are pending.
|
and dispatch are pending.
|
||||||
- **Indexes**: `add index` / `drop index` done (ADR-0025).
|
- **Indexes**: `add index` / `drop index` done (ADR-0025).
|
||||||
`EXPLAIN QUERY PLAN` (QA1 / QA2) is designed in ADR-0028 —
|
`EXPLAIN QUERY PLAN` (QA1 / QA2) implemented per ADR-0028 —
|
||||||
the `explain` prefix command + span-styled plan tree —
|
the `explain` prefix command + span-styled plan tree.
|
||||||
but not yet implemented.
|
|
||||||
- **Modify relationship** (C3a): drop+add covers the use case
|
- **Modify relationship** (C3a): drop+add covers the use case
|
||||||
today.
|
today.
|
||||||
- **m:n convenience** (C4): auto-generates a junction table
|
- **m:n convenience** (C4): auto-generates a junction table
|
||||||
|
|||||||
@@ -0,0 +1,161 @@
|
|||||||
|
# Session handoff — 2026-05-19 (21)
|
||||||
|
|
||||||
|
Twenty-first handover. This session **finished ADR-0028** —
|
||||||
|
query plans / `explain`. Steps 2–5 (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 2–3)
|
||||||
|
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.
|
||||||
@@ -371,18 +371,17 @@ handoff-14 cleanup; 449 after B2/C2.)
|
|||||||
|
|
||||||
## Query analysis
|
## Query analysis
|
||||||
|
|
||||||
- [ ] **QA1** `EXPLAIN QUERY PLAN` is run on demand for queries;
|
- [x] **QA1** `EXPLAIN QUERY PLAN` is run on demand for queries;
|
||||||
output is rendered as an annotated tree highlighting full
|
output is rendered as an annotated tree highlighting full
|
||||||
scans, index use, and join order.
|
scans, index use, and join order.
|
||||||
*(Designed in ADR-0028: the `explain` prefix over
|
*(Implemented per ADR-0028: the `explain` prefix over
|
||||||
`show data` / `update` / `delete`, with a span-styled plan
|
`show data` / `update` / `delete`, with a span-styled plan
|
||||||
tree. The pedagogical payoff — a plan that flips between a
|
tree. `EXPLAIN QUERY PLAN` never executes, so explaining a
|
||||||
full scan and an index search — needs a filtered query
|
destructive `update` / `delete` is safe.)*
|
||||||
(`show data … where`, designed in ADR-0026) plus indexes
|
- [x] **QA2** Plan rendering specifics — tree layout, annotation
|
||||||
(ADR-0025, done). Implementation pending.)*
|
taxonomy, colour scheme. Implemented per ADR-0028 (§3–§6):
|
||||||
- [ ] **QA2** Plan rendering specifics — tree layout, annotation
|
a box-drawing tree, the substring-pattern taxonomy, and the
|
||||||
taxonomy, colour scheme. Designed in ADR-0028 (§3–§6);
|
`OutputLine` styled-runs mechanism.
|
||||||
implementation pending.
|
|
||||||
|
|
||||||
## Hints, help, errors
|
## Hints, help, errors
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user