Files

9.6 KiB

Session handoff — 2026-05-27 (46)

Forty-sixth handover. We are mid-feature — the DSL → SQL teaching echo (ADR-0038) is partially built (a working walking skeleton). Read this carefully before continuing; §4 and §5 are the load-bearing parts.

§1. State at handoff

Branch: main. HEAD 04c8e42. Tests: 1970 passing, 0 failing, 0 skipped, 1 ignored. Clippy: clean (--all-targets -D warnings, nursery).

This session designed the DSL → SQL teaching echo (ADR-0030 §10) as a /runda'd design set and began building it. Commits since handoff-45's 2bcc55f:

04c8e42 feat: DSL→SQL teaching echo — channel + create-table slice (ADR-0037 + ADR-0038)
9a23e28 fix: update … --all-rows falls back to the DSL instead of misparsing (ADR-0033 Am4)
338dc8a feat: advanced ALTER COLUMN SET/DROP NOT NULL & DEFAULT, SET DATA TYPE (ADR-0035 Am2)
9f15f38 docs(adr): design the DSL→SQL teaching echo (ADR-0038) + dependencies

§2. The feature & its build plan

Goal: when a DSL-form command runs in advanced mode, echo the equivalent SQL beneath [ok], so a learner reads off the SQL spelling (ADR-0030 §10). Authoritative spec: ADR-0038 (read it — the catalogue in §7, the copy-paste contract §1, the three-category framework §6).

Five ADRs, all Accepted/Proposed and /runda'd (the design /runda verdict was PASS with fixes applied — see the ADRs):

ADR What Build status
ADR-0035 Am2 standard-first dialect + ALTER COLUMN SET/DROP NOT NULL, SET/DROP DEFAULT, ISO SET DATA TYPE done (338dc8a)
ADR-0033 Am4 update … --all-rows falls back to DSL (was a misparse) done (9a23e28)
ADR-0037 EffectiveMode execution-time side-channel (the echo's gate) channel done (04c8e42)
ADR-0038 the echo + full catalogue 🚧 skeleton onlycreate table echoes; rest of the catalogue pending
ADR-0039 EXPLAIN over advanced SQL deferred follow-up — decision recorded, NOT this feature

Build order was Am2 → Am4 → (0037+0038 merged). 0037 and 0038 were merged into one build step because the channel is dead code without its consumer (-D warnings rejects it) — see ADR-0037 Implementation notes.

§3. The doc-drift fix (already committed, FYI)

9f15f38 also reconciled stale notes: simple-mode column ops (B2/C2) are implemented, not pending. requirements.md C2/B2 were already [x]; the project CLAUDE.md was corrected. (Don't re-flag this.)

§4. The echo architecture — how it works NOW (read before editing)

Data flow for the interactive path (replay is separate — see below):

  1. app.rs::submit computes the three-way EffectiveMode (Simple / AdvancedPersistent / AdvancedOneShot) — reusing the pre-existing EffectiveMode enum, NOT a new SubmissionMode (ADR-0037 was corrected to reuse it). Passes it to dispatch_dsl.
  2. app.rs::dispatch_dsl(input, submission_mode: EffectiveMode) parses with submission_mode.as_mode() (the two-way Mode the walker needs), and emits Action::ExecuteDsl { command, source, submission_mode } (new field, action.rs).
  3. runtime.rs Action::ExecuteDsl handlerspawn_dsl_dispatch(…, submission_mode).
  4. runtime.rs::spawn_dsl_dispatch: computes echo = crate::echo::echo_for(&command, submission_mode)Option<String>, executes the command, and attaches echo to the AppEvent::DslSucceeded { …, echo } (new field, event.rs).
  5. app.rs update() DslSucceeded arm stashes self.pending_echo = echo just before calling handle_dsl_success.
  6. app.rs::note_ok_summary (the shared [ok] pusher, called by every success handler) pushes [ok] … then, if pending_echo is Some, pushes the echo line Executing SQL: <sql> (i18n key echo.executing_sql). The stash is set+consumed within one synchronous update(), so it's safe (no interleaving).

The renderer: src/echo.rs. echo_for(command, mode) gates (advanced effective mode + DSL-form) and calls command_to_sql(command) -> Option<String>. command_to_sql currently handles only Command::CreateTableCREATE TABLE T (id serial PRIMARY KEY) (single inline / compound table-level PK, playground type vocabulary). Everything else returns None (no echo yet).

Replay is silent for free: run_replay calls execute_command_typed directly, bypassing spawn_dsl_dispatch, so replayed lines never reach the echo path. No interactive flag needed.

Where the echo is built (ADR correction): NOT in the db.rs worker — the worker gets decomposed calls, not the Command. The runtime's dispatch is where Command + mode + result converge. ADR-0037 §3 / ADR-0038 §4 were corrected to say so.

§5. What's next — expanding the renderer (the actual work)

Per ADR-0038 §8 phasing. The catalogue (ADR-0038 §7) is the spec — each row is a round-trip test (parse the echo in advanced mode → a same-effect command; the §1 contract). Order:

Phase 1 — rest of Bucket A (single-statement)

Expand command_to_sql for: add column, drop column (non-cascade), rename column, change column (→ ALTER COLUMN c SET DATA TYPE tynow runnable, Am2 shipped), add constraint (NotNull→SET NOT NULL, Default→SET DEFAULT v, Unique→ADD UNIQUE (c), Check→ADD CHECK (e)), drop constraint (NotNull/Default only; Unique/Check column-level → Bucket C), show data (→ SELECT * FROM T [WHERE …] [ORDER BY <pk> LIMIT n]), and the delete … --all-rows / update … --all-rows fall-throughs (now fall back, Am4 shipped).

For EACH new command, also:

  • add an echo: Option<String> field to its success event (DslAddColumnSucceeded, DslDropColumnSucceeded, DslChangeColumnSucceeded, DslDataSucceeded, DslUpdateSucceeded, DslDeleteSucceeded),
  • set it from echo in spawn_dsl_dispatch's matching arm,
  • stash self.pending_echo = echo in the App's matching update() arm. (note_ok_summary already renders it for all.)

Needs Expr→SQL + Value→SQL-literal renderers (ADR-0038 §5 literal table): for show data WHERE filters, add constraint check/default values, etc. blob has no literal (moot — no blob literal syntax). Auto- gen columns omitted from INSERT echoes.

⚠️ CRITICAL gotcha for Bucket B + category-3

The skeleton computes echo BEFORE execute_command_typed (it only needs the Command). Bucket B (resolved auto-names) and category-3 (generated shortids, conversion counts) need the execution result. So when you implement those, move/augment the echo build to AFTER execution, reading the CommandOutcome/result (the resolved index name, the client_side.* notes — ADR-0017 §6 / ADR-0018 §9). The runtime has both (it builds the event from command + outcome). This is the one place the current skeleton structure must change.

Phase 2 — Bucket B

Resolved names (drop index on T(cols)DROP INDEX <resolved>, drop/ add relationship, auto-named add index) and multi-line echoes (one statement per line: drop column --cascade, add relationship --create-fk). ADR-0038 §6 category 2. The echo payload likely becomes Vec<String> (one per statement) — generalise Option<String>.

Phase 3 — category-3 prose expansion

shortid generation, type-conversion transforms, and the change column --dont-convert caveat (ADR-0038 §6). De-emphasised prose from the worker's client_side.* notes.

Polish (not yet done)

The echo line is currently a plain [system] line via note_system. ADR-0038 §4 wants it de-emphasised (styled-runs, ADR-0028). Refine the rendering (an OutputLine with styled_runs, dimmed Executing SQL: prefix) — a TODO, deferred so the skeleton stayed small.

§6. Catalogue cheat-sheet (authoritative: ADR-0038 §7)

  • Echoes (DSL-only spellings in advanced mode): all DDL forms + show data + delete/update … --all-rows. DSL column-op syntax is <verb> column in/from/to T: c (type) (colon + parens); index/rel naming is as N (not named).
  • NOT echoed: insert/update … where/delete … where (SQL-first → Sql* = already SQL), drop table, drop index <name> (→ Sql*), show table, explain, replay, app commands, column-level UNIQUE/CHECK drop (residual gap, ADR-0035 Am2). change column --dont-convert → echoes the headline + a category-3 caveat.

§7. Process pins (unchanged)

  • Confirm every commit (propose message, wait). No AI attribution.
  • Test-first; green + clippy-clean is the only acceptable end state; baseline 1970 / 0 / 1.
  • Keep docs lockstep: ADR + README.md index + requirements.md. Amend ADRs, don't re-litigate. Raise implementation deviations and update the ADR (this session corrected ADR-0035 Am2's SET DEFAULT executor, ADR-0037's enum + build-layer, ADR-0038 §4 in-place).
  • Round-trip every catalogue row (the §1 copy-paste contract).

§8. How to take over

  1. Read, in order: this file → ADR-0038 (§1 contract, §6 categories, §7 catalogue, §8 phasing) → ADR-0037 (channel + Implementation notes) → the four commits above → src/echo.rs (the renderer to expand).
  2. Baseline: cargo test (1970 / 0 / 1) + cargo clippy --all-targets -- -D warnings (clean).
  3. Continue with §5 Phase 1 (rest of Bucket A), test-first, one command at a time, round-tripping each echo. Heed the §5 ⚠️ gotcha before touching Bucket B / category-3.
  4. ADR-0039 (EXPLAIN over advanced SQL) is a separate deferred follow-up, not this feature.