# Session handoff — 2026-05-28 (49)

Forty-ninth handover. **ADR-0038 is done** — and twice DA-audited.
Every catalogue row of the DSL → SQL teaching echo is implemented,
every echo round-trips per line per the §1 copy-paste contract,
every §6 category-3 line surfaces, the §4 de-emphasised styled-runs
rendering polish landed in `2aab457`, and a closing /runda Devil's-
Advocate pass over the polish (`6840b92`) pinned three minor wiring
gaps. Docs in sync. If you continue, pick a fresh feature; if you're
triaging, ADR-0038 won't surprise you.

## §1. State at handoff

**Branch:** `main`. **HEAD `6840b92`.** **Tests: 2020 passing, 0
failing, 0 skipped, 1 ignored.** **Clippy: clean**
(`--all-targets -D warnings`, nursery).

Commits since handoff-48's `df5c4e2`:

```
6840b92 test: /runda round 2 — pin TeachingEcho kind + cat-3 prose wiring
63b2927 docs: session handoff 49 — ADR-0038 done, M4 + ADR statuses in sync
2aab457 feat: DSL→SQL teaching echo — §4 styled-runs polish (ADR-0038)
```

The first version of this handoff went out with `63b2927` at HEAD;
this amendment (committed after `6840b92`) records the closing
/runda round 2 below.

## §2. ADR-0038 — done

The feature shipped across **five** commits, the last of which is the
§4 polish:

| Commit | Phase | What |
|---|---|---|
| handoff-46 `04c8e42` | 1 (start) | channel + create-table slice |
| `90479cb` | 1 (rest) | Bucket A renderer — every single-statement DDL row + `show data` + `--all-rows` fall-throughs; create-table contract-gap fix |
| `275c726` | 2 | Bucket B — resolved-name + multi-statement (auto- and user-named `add index`, positional `drop index`, `add`/`drop relationship` in both selector forms, `drop column --cascade`, `add relationship --create-fk`) |
| `e6ad1ae` | 3 | category-3 prose — `change column --dont-convert` *caveat* (the other two cat-3 lines were already in place via `client_side.*` keys) |
| `2aab457` | 4 (polish) | §4 styled-runs rendering — `OutputKind::TeachingEcho` with dimmed prefix + advanced-mode lex of the SQL; `OutputStyleClass::Hint` for every cat-3 prose line |

Plus **two** /runda Devil's-Advocate passes — `5cb105b` after
Phase 3 (doc-drift + Bucket C explicit no-echo tests) and
`6840b92` after the polish (kind assertions on every echo arm +
the broader-scope `client_side` notes pinning, see §3a below).
Neither pass escalated.

ADR-0037 and ADR-0038 both **Accepted** with implementation notes
referencing every shipping commit.

## §2a. /runda round 2 findings (closed by `6840b92`)

A second Devil's-Advocate pass over the polish surfaced three
test-coverage gaps the polish itself had left behind. All three were
closed in `6840b92`; tests-only commit (+98 lines in `src/app.rs`),
no production code touched.

- **`bucket_a_success_events_render_the_teaching_echo_beneath_ok`** and
  **`bucket_b_multi_line_echo_renders_one_line_per_statement_beneath_ok`**
  only checked line *text*. After the polish, every echo line is
  pushed via `push_teaching_echo` and carries
  `OutputKind::TeachingEcho` — and the kind is what fires
  `ui::render_output_line`'s dim-prefix + advanced-lex branch. A
  regression to plain `System` would leave the text intact while
  silently breaking the styling. The `assert_echo_beneath_ok`
  helper now pins `kind == TeachingEcho` on every event arm the
  bucket_a test covers (six arms in one shot); the bucket_b test
  pins it on each of the three multi-statement lines.
- **`add_column_client_side_notes_render_as_category_three_prose`**
  (new) pins the broader-scope polish: `handle_dsl_add_column_success`'s
  illuminating `client_side_notes` (shortid / serial auto-fill, per
  `client_side.auto_fill_*` keys) now route through
  `push_category_three_prose`, producing a System line with a
  whole-text Hint span. The closely-related caveat path was already
  pinned by `polished_echo_carries_teaching_echo_kind_and_caveat_a_hint_span`;
  this completes the cat-3 prose coverage symmetrically.

What the round-2 pass *verified clean* (no action needed) — kept
here as a flight log so the next session doesn't re-walk the same
ground:

- All four `OutputKind` matches in `ui.rs` (tag_len, tag, Echo-
  branch detection, body_style) handle the new variant; no other
  code matches on `OutputKind`.
- `OutputStyleClass::Hint` resolution works on both light + dark
  (`hint_class_resolves_to_muted_foreground`).
- ADR-0028 §7 OOS "no re-styling existing output" is not violated:
  ADR-0038 takes ownership of styling its own cat-3 content; the
  broader-scope was user-confirmed and recorded.
- The hybrid styling (custom path for SQL via `lex_to_runs` +
  `styled_runs` for prose) follows the precedent established by
  `OutputKind::Echo` / ADR-0022 §5; ADR-0028 §5 anticipates this
  ("any output line may now carry rich styling").
- Replay bypass unchanged; no AI attribution anywhere; clippy clean.

Acceptable observations the round-2 pass left *documented but not
fixed* — none warranted escalation:

- The `2aab457` commit message and the `en-US.yaml` comment overstate
  the reason `TEACHING_ECHO_LABEL` became a const ("i18n template
  couldn't provide that"). Reality: simpler + avoids resolving i18n
  per render (a hot path). Historic — not amending; this handoff
  is the more accurate forward-looking reference.
- The two rendering-path tests
  (`teaching_echo_line_renders_dim_prefix_and_lexed_sql`,
  `category_three_prose_line_renders_all_dim`) only use the dark
  theme; the rendering logic is theme-agnostic and the class
  resolution is pinned for both, so this is pedantic-incomplete
  rather than a real gap.
- No full-pipeline integration test driving submit → spawn → render
  (same observation as §4 below, restated for completeness).

## §3. What the polish (Phase 4) does, in shape

Per ADR-0038 §4 + §6, the de-emphasised styled-runs treatment landed
in `2aab457`. The user-confirmed scope (per session discussion) went
slightly beyond §4's "echo + caveat" to cover the existing
illuminating cat-3 notes too — visual consistency for every cat-3
prose line, matching §6's "de-emphasised prose line" wording.

**The polish in code:**

- **`OutputKind::TeachingEcho`** (new). Lines with this kind go through
  a custom `ui::render_output_line` branch that mirrors the
  `OutputKind::Echo` simple-mode input-echo path: strip the canonical
  `crate::echo::TEACHING_ECHO_LABEL` ("Executing SQL: "), render the
  prefix dimmed (`theme.muted`), then lex the rest in `Mode::Advanced`
  via `input_render::lex_to_runs_in_mode` and emit one span per token.
  Tag stays `[system]` for visual consistency with other system
  output.
- **`OutputStyleClass::Hint`** (new), resolved to `theme.muted` by
  `output_span_style`. Carried on category-3 prose lines as a single
  styled-runs span covering the whole text (so the body renders
  dimmed; the `[system]` tag keeps its kind tint).
- **`crate::echo::TEACHING_ECHO_LABEL`** (new pub const) — the fixed
  byte boundary the ui.rs branch needs. The label moved out of the
  `echo.executing_sql` i18n key (now retired in en-US.yaml + keys.rs;
  a comment in en-US.yaml points future locales at re-introducing
  it).
- **App-side helpers**: `App::push_teaching_echo(sql)` builds the
  TeachingEcho line; `App::push_category_three_prose(text)` builds a
  System line with a whole-text Hint span. `note_ok_summary` and
  `handle_dsl_change_column_success` / `handle_dsl_add_column_success`
  use these instead of plain `note_system` for the echo, the
  DontConvert caveat, and the illuminating client-side notes.

**Where each rendering rule lives:**

| Line | Built by | Renders as |
|---|---|---|
| `[ok] verb subject` | `note_ok_summary` via `note_system` | `[system]` tag + `system` green body (unchanged) |
| `Executing SQL: <sql>` (one per echo line) | `push_teaching_echo` | `[system]` tag + dimmed prefix + token-coloured SQL |
| `[client-side] N row(s) were transformed …` | `push_category_three_prose` (auto_fill_*, transformed*) | `[system]` tag + whole-body dim |
| `[client-side] --dont-convert kept …` | `push_category_three_prose` (caveat path) | `[system]` tag + whole-body dim |
| structure render, row counts, etc. | `note_system` | unchanged |

**Coverage:** four new tests landed with the polish itself
(`2aab457`) — `ui::tests::teaching_echo_line_renders_dim_prefix_and_lexed_sql`
(asserts the dim prefix span + keyword-coloured SQL spans confirm
advanced-mode lex), `ui::tests::category_three_prose_line_renders_all_dim`
(whole-text Hint coverage), `ui::tests::hint_class_resolves_to_muted_foreground`
(theme resolution across both palettes), and
`app::tests::polished_echo_carries_teaching_echo_kind_and_caveat_a_hint_span`
(App-side wiring kinds + styled_runs shape on the caveat path). The
pre-existing echo tests pass unchanged — the text content is
identical, only styling changed. The /runda round 2 (`6840b92`)
added three more (see §2a): kind assertions on every event arm
covered by the bucket_a / bucket_b multi-statement tests, plus a
focused test pinning the broader-scope `client_side_notes` →
`push_category_three_prose` path on add column.

## §4. Notable observations carried over from handoff-48

These are the same ones flagged before the polish — none became
blockers, the polish didn't introduce new ones.

- **Unquoted-identifier round-trip caveat.** Echo style is bare
  identifiers (matching the original create-table echo aesthetic). A
  user-created column or table named after a SQL keyword (e.g.
  `ORDER`, `SELECT`) would produce an echo whose round-trip is
  fragile. Pre-existing limitation; the §1 contract is only formally
  violated for this edge case. Fix is identifier-quoting if it ever
  bites a learner.
- **No full-spawn integration test for the echo pipeline.** Coverage
  is layered (pure renderers + runtime-helper unit tests with real
  Database + App-level rendering tests + ui.rs styling tests). The
  unwired glue is small; a Tier-3 end-to-end test would complete the
  picture, not blocking.
- **Pure-Command Schema commands double-compute echo.** `echo_for` is
  called for every command; the Schema arm recomputes via
  `build_schema_echo` (whose catch-all redelegates to
  `command_to_sql`). Minor inefficiency, no behaviour bug.

## §5. What's next

Up to you. ADR-0038 won't pull on any more rope. Candidate features:

- **ADR-0039 — EXPLAIN over advanced-mode SQL queries** (`Accepted`,
  implementation deferred). Self-contained: lets `explain` wrap the
  advanced SQL commands (`Select`/`SqlInsert`/`SqlUpdate`/
  `SqlDelete`) in addition to the DSL `ShowData`/`Update`/`Delete` it
  already covers (ADR-0028). Test-first when picked up.
- **Other tracks** from `requirements.md` — see the file for the
  pending list. Likely candidates: track 2 (project storage Iter 5/6
  — export/import + `--resume` + persistent input history + migration
  framework), `C3a` (modify relationship), `C4` (m:n convenience),
  `H1`/`H1a` (friendly error layer + syntax-help in parse errors),
  the tutorial/lesson system, V4 session log + Markdown export, the
  remaining input UX items (`I1`/`I1b` multi-line + readline
  shortcuts, `I3` tab completion polish, `I4` syntax highlighting
  beyond input echo).
- **Polish-spawned ideas** from this session — none currently
  outstanding; the OutputStyleClass vocabulary now has `Hint` and
  could grow further if another consumer needs it.

## §6. Process pins (unchanged)

- **Confirm every commit** (propose message, wait). **No AI attribution.**
- **Test-first**; green + clippy-clean is the only acceptable end
  state; current baseline **2020 / 0 / 1**.
- **Keep docs lockstep**: ADR + `README.md` index + `requirements.md`.
  This session's polish commit ships alongside this handoff and the
  three doc-update edits (M4 / ADR-0038 Status / ADR-0037 + ADR-0038
  README index entries).
- **Round-trip every catalogue row** (the §1 copy-paste contract; for
  multi-statement, *per line*).

## §7. How to take over

1. **Read, in order:** this file → `requirements.md` for the open
   tracks → the relevant ADR for whatever feature you pick up.
   ADR-0038 / ADR-0037 are done and well-documented; touch them only
   to amend if a real correction comes up.
2. **Baseline:** `cargo test` (2020 / 0 / 1) + `cargo clippy
   --all-targets -- -D warnings` (clean).
3. **For a fresh feature**: write the ADR (or extend an existing
   one), run `/runda` over the design before building, then build
   test-first.
4. **The ADR-0028 styled-runs vocabulary** is now richer: `Neutral`,
   `Efficient`, `Expensive`, `AutomaticIndex`, `Hint`. Adding a new
   consumer? Pattern is one variant per semantic class, theme-resolved
   in `ui::output_span_style`, used via `OutputLine::styled` or a
   dedicated kind + custom render branch (as `TeachingEcho` does for
   the dim-prefix + lex-rest case).
