feat: DSL→SQL teaching echo — channel + create-table slice (ADR-0037 + ADR-0038)

Walking skeleton validating the whole echo architecture end to end; the
Command→SQL renderer currently covers `create table`, with the rest of
Bucket A / B / category-3 to follow (ADR-0038 §8).

- Channel (ADR-0037): the three-way EffectiveMode (reusing the existing
  enum, not a new SubmissionMode — recorded in the ADR) rides on
  Action::ExecuteDsl to the runtime. `replay` bypasses the interactive
  spawn, so it never echoes (silent, for free).
- Echo (ADR-0038): built at the runtime's ExecuteDsl dispatch — the worker
  gets decomposed calls, not the Command, so ADR §4's "worker builds it"
  was corrected to the dispatch layer. Gated by echo_for (advanced
  effective mode + DSL-form). Carried on DslSucceeded; rendered by
  note_ok_summary as `Executing SQL: …` immediately beneath `[ok]`. New
  src/echo.rs renderer; echo.executing_sql i18n key.
- command_to_sql: `create table` → `CREATE TABLE T (id serial PRIMARY KEY)`
  (single inline / compound table-level PK), playground type vocabulary,
  round-trip-verified against the advanced walker (the §1 contract).

Tests: echo.rs (render, round-trip contract, mode gate, Sql*-not-echoed);
app.rs (submit carries the 3-way mode; echo renders beneath [ok]).
Suite 1970/0/1; clippy clean.
This commit is contained in:
claude@clouddev1
2026-05-27 22:09:54 +00:00
parent 9a23e28f30
commit 04c8e4295f
12 changed files with 350 additions and 29 deletions
@@ -109,20 +109,24 @@ effective mode it ran under. The value is **output-only**: no executor
branches its *effect* on it (that would be a behavioural mode dependency,
which ADR-0033 Amendment 3 forbids — identity and effect are intrinsic).
### 3. The worker produces mode-dependent output; the App renders it
### 3. The runtime's execution dispatcher produces the echo; the App renders it
For the first consumer (ADR-0038): when the command is a **DSL-form**
command (`Command::CreateTable`/`Insert`/… — *not* the `Sql*` variants)
and `submission_mode` is `Advanced` or `AdvancedOneShot`, the worker
builds the teaching echo (equivalent SQL + any category-3 expansion
data — ADR-0038) and returns it on the result event. In `Simple` mode,
or for a command typed as SQL, no echo is produced. The App renders the
returned echo as de-emphasised `OutputLine`(s) beneath `[ok]`.
and `submission_mode` is `Advanced` or `AdvancedOneShot`, the teaching
echo (equivalent SQL + any category-3 expansion data — ADR-0038) is built
from the `Command` **plus the worker's execution result**, and the App
renders it as de-emphasised `OutputLine`(s) beneath `[ok]`. In `Simple`
mode, or for a command typed as SQL, no echo is produced.
Co-locating echo construction with execution is deliberate: the echo's
harder forms (resolved auto-names, generated `shortid`s, conversion
counts) are facts the worker already computes. Gating on the threaded
mode means the work happens **only when an echo will be shown**.
**Where it is built (build correction — see Implementation notes).** Not
in the db.rs worker: the worker receives *decomposed* calls, not the
`Command`, so it cannot render `Command → SQL`. The echo is built at the
**runtime's `ExecuteDsl` handler**, the one place where the `Command`,
the threaded `EffectiveMode`, and the worker's result (resolved
auto-names, generated `shortid`s, conversion counts) all converge. This
is still **execution-time aware** — it consumes the execution *results*
it just lives at the dispatch layer, not inside the storage worker.
**Non-interactive re-execution does not echo.** `replay` (ADR-0034)
re-runs recorded commands through the dispatch pipeline in advanced mode
@@ -172,6 +176,26 @@ the gating contract in §3.
`Action` → worker round-trip; a Simple-mode DSL command yields no echo
request while an Advanced / one-shot one does (the gating contract).
## Implementation notes (2026-05-27, during build)
Two refinements found when building, recorded so the ADR matches reality:
- **Reuse the existing `EffectiveMode`, do not add `SubmissionMode`.** The
codebase already has `EffectiveMode { Simple, AdvancedPersistent,
AdvancedOneShot }` (`app.rs`), computed by `effective_mode()` and used
today for the `:` one-shot UI feedback. It is exactly the three-way,
per-submission, *separate-from-`Mode`* enum §1 argued for — so §1's
"new enum" is already satisfied; the build reuses `EffectiveMode`
(`AdvancedPersistent` is the ADR's `Advanced`). No new type.
- **The channel ships with its consumer (merged with ADR-0038).** A
threaded-but-unread `EffectiveMode` on the worker request is dead code,
which this project's `-D warnings` (nursery) rejects. The side-channel
has no consumer other than the echo, so the `Action`→worker threading
is built **together with ADR-0038** rather than as a standalone commit
— the submit-side resolution (which `Action` carries which
`EffectiveMode`) is Tier-1 testable, and the worker-side threading
becomes live + end-to-end testable the moment the echo reads it.
## See also
- ADR-0033 Amendment 3 — deferred this side-channel; defines the