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 only — create 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):
app.rs::submitcomputes the three-wayEffectiveMode(Simple/AdvancedPersistent/AdvancedOneShot) — reusing the pre-existingEffectiveModeenum, NOT a newSubmissionMode(ADR-0037 was corrected to reuse it). Passes it todispatch_dsl.app.rs::dispatch_dsl(input, submission_mode: EffectiveMode)parses withsubmission_mode.as_mode()(the two-wayModethe walker needs), and emitsAction::ExecuteDsl { command, source, submission_mode }(new field,action.rs).runtime.rsAction::ExecuteDsl handler →spawn_dsl_dispatch(…, submission_mode).runtime.rs::spawn_dsl_dispatch: computesecho = crate::echo::echo_for(&command, submission_mode)→Option<String>, executes the command, and attachesechoto theAppEvent::DslSucceeded { …, echo }(new field,event.rs).app.rsupdate() DslSucceeded arm stashesself.pending_echo = echojust before callinghandle_dsl_success.app.rs::note_ok_summary(the shared[ok]pusher, called by every success handler) pushes[ok] …then, ifpending_echoisSome, pushes the echo lineExecuting SQL: <sql>(i18n keyecho.executing_sql). The stash is set+consumed within one synchronousupdate(), 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::CreateTable → CREATE 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 ty —
now 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
echoinspawn_dsl_dispatch's matching arm, - stash
self.pending_echo = echoin the App's matching update() arm. (note_ok_summaryalready 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 isas N(notnamed). - 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.mdindex +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
- 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). - Baseline:
cargo test(1970 / 0 / 1) +cargo clippy --all-targets -- -D warnings(clean). - 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.
- ADR-0039 (EXPLAIN over advanced SQL) is a separate deferred follow-up, not this feature.