Files
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

7.0 KiB
Raw Permalink Blame History

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.explainexplain 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.