docs(adr): design the DSL→SQL teaching echo (ADR-0038) + dependencies

Realises ADR-0030 §10 (the DSL→SQL teaching bridge) as a /runda'd design
set, before implementation:

- ADR-0037 (new): execution-time mode side-channel — SubmissionMode
  {Simple, Advanced, AdvancedOneShot} threaded Action→worker, output-only;
  redeems ADR-0033 Amendment 3's deferred follow-up. Replay stays silent.
- ADR-0038 (new): the teaching echo + full catalogue (Buckets A/B/C),
  the copy-paste round-trip contract, the three-category framework, and
  the Value→SQL-literal renderer. DDL + show-data centric (overlapping
  DML is SQL-first, so already SQL). Build-order deps recorded.
- ADR-0035 Amendment 2: standard-first dialect stance + ALTER COLUMN
  SET/DROP NOT NULL, SET/DROP DEFAULT, ISO SET DATA TYPE gap-fill.
- ADR-0033 Amendment 4: reclassifies the `update … --all-rows`
  non-fall-back as a bug; it now falls back to the DSL Update and echoes
  (keyed on adjacent `--`; spaced arithmetic preserved).
- ADR-0039 (new): EXPLAIN over advanced SQL — decision recorded, build
  deferred; supersedes ADR-0030 §13 OOS-2.
- ADR-0000: out-of-scope discipline (deferred vs rejected). README index
  updated for all of the above.

Reconcile CLAUDE.md: simple-mode column ops are implemented, not pending
(requirements.md C2/B2 already [x]).
This commit is contained in:
claude@clouddev1
2026-05-27 20:44:38 +00:00
parent 2bcc55f939
commit 9f15f386d5
9 changed files with 775 additions and 8 deletions
+111
View File
@@ -616,6 +616,117 @@ Single-column UNIQUE column drops are a **parallel** gap (different
mechanism — ADR-0029 column-level `drop constraint`) and are **out of
scope** here.
## Amendment 2 — Standard-first dialect + `ALTER COLUMN` constraint gap-fill (2026-05-27)
Designing the **DSL → SQL teaching echo** (ADR-0030 §10, specified in
ADR-0038) surfaced two related things about this ADR's surface. First, a
**dialect drift**: ADR-0030 frames advanced mode as "the **standard-SQL**
surface," but §4f shipped the type-change verb as bare
`ALTER COLUMN … TYPE` — the **PostgreSQL shorthand** — and explicitly
declined the ISO `SET DATA TYPE` synonym (§4f, line "no `SET DATA TYPE`
synonym"). Second, **gaps**: advanced mode has no way to toggle `NOT NULL`
or `DEFAULT` on an existing column, though simple mode does
(ADR-0029 `add`/`drop constraint`), and the rebuild primitive that would
back them is already in place (it backs §4f type-change and §4g
constraint-add). This amendment records a **dialect stance** and **fills
the clean gaps** so the echo can emit portable SQL that is also runnable
in advanced mode. Recorded with explicit user approval (2026-05-27).
### The dialect stance — standard-first (refines ADR-0030)
Where ISO SQL provides a spelling, the **authored grammar's canonical
form is the ISO one**, and the **echo emits the ISO form**. A widely-
recognised vendor shorthand *may* be **accepted** as a synonym (so a
learner who knows it is not punished), but it is never the canonical or
emitted form. Where ISO provides **no** spelling for an operation the
playground teaches, **one** widely-recognised vendor spelling is adopted
as a **deliberate, documented extension** — not silently. This realigns
the surface with ADR-0030's stated posture and makes the divergence a
conscious, recorded choice rather than drift.
The stance applies to the whole advanced surface going forward; this
amendment exercises it on the `ALTER COLUMN` family.
### Type change: ISO `SET DATA TYPE` canonical, `TYPE` retained as a synonym
Reverses §4f's "no `SET DATA TYPE` synonym." The grammar now accepts
**both** `ALTER COLUMN <c> SET DATA TYPE <type>` (ISO; canonical) and
`ALTER COLUMN <c> TYPE <type>` (PostgreSQL; accepted synonym, no
breakage for already-shipped usage). Both decompose to the same §4f
`AlterColumnType` action and the same `ChangeColumnMode::ForceConversion`
executor — semantics are **unchanged**; only the accepted spelling set
and the *canonical/echoed* form change. The echo (ADR-0038) emits
`SET DATA TYPE`.
### New: `SET/DROP DEFAULT` (ISO) and `SET/DROP NOT NULL` (the one extension)
Four new `AlterColumnType`-family actions under `ALTER COLUMN <c>`:
| Spelling | Standing | Decomposes to (ADR-0029 executor) |
|---|---|---|
| `SET DEFAULT <expr>` | **ISO-standard** | `do_add_constraint(Default)` |
| `DROP DEFAULT` | **ISO-standard** | `do_drop_constraint(Default)` |
| `SET NOT NULL` | **documented extension** | `do_add_constraint(NotNull)` |
| `DROP NOT NULL` | **documented extension** | `do_drop_constraint(NotNull)` |
`SET DEFAULT`/`DROP DEFAULT` are taken directly from the ISO
`<alter column action>` set. **`NOT NULL` toggling has no ISO spelling**
— in the standard `NOT NULL` is a column constraint, not an in-place
`ALTER COLUMN` verb, and the vendors diverge (PostgreSQL
`SET/DROP NOT NULL`; SQL Server `ALTER COLUMN <c> <type> NOT NULL`;
MySQL `MODIFY`; Oracle `MODIFY`). Per the stance, **one** spelling is
adopted as a deliberate extension: **PostgreSQL's `SET/DROP NOT NULL`**,
chosen because it is the only form that is type-independent (it does not
force the user to restate the column type), reads as plain English, and
composes uniformly with the ISO `SET/DROP DEFAULT` it sits beside.
`SET DEFAULT`'s value slot reuses the §4a.2 / §4e **raw `sql_expr`**
default mechanism (`default_sql`), so a default may be any expression
the create-table `DEFAULT` accepts — one syntax, not a third
(ADR-0030 §11).
### Execution — rebuild-backed, no new low-level op
Each new action **runtime-decomposes to an existing ADR-0029 executor**
(`do_add_constraint` / `do_drop_constraint`), exactly as §4e/§4f
decompose their actions — the populated-column **pre-flight dry-run
guard** (ADR-0029 §5) and the internal-`__rdbms_*` guard come for free.
No new worker layer. The grammar discriminates the `ALTER COLUMN <c> …`
tail by its leading keyword: `type` / `set data type` (type change),
`set not null` / `drop not null`, `set default` / `drop default` — the
`set`/`drop` lead is new alongside §4f's `type` lead.
### Parity reached, and the one residual gap
This brings advanced mode to **constraint-modification parity with
simple mode (ADR-0029) for `NOT NULL` and `DEFAULT`** — add and drop,
both directions. It closes the simple↔advanced asymmetry the echo design
flagged for those ops.
**Residual gap (deliberately not closed here):** dropping a
**column-level `UNIQUE` or `CHECK`** (the single-column, *anonymous*
constraints simple mode adds via ADR-0029 `add constraint unique/check`).
`DROP CONSTRAINT <name>` (§4g) + the derived composite-UNIQUE name
(Amendment 1) resolve *table-level* / *named* constraints; a single-
column column-level `UNIQUE` lives as the column's `unique` flag and a
column-level `CHECK` is likewise anonymous, so neither has a portable
name to address. This is the same class Amendment 1 called a "parallel
gap … out of scope." Consequently ADR-0038's catalogue marks
`drop constraint unique/check from T.col` as **no headline echo** (a
residual gap), rather than inventing a name or a recipe. Flagged for the
user; closing it (e.g. extending the derived-name approach to single-
column UNIQUE) would be its own small follow-up.
### Engine neutrality holds (the rebuild stays hidden)
The chosen spellings are **portable SQL**, not engine features. The fact
that *this* engine satisfies `SET NOT NULL` / `SET DATA TYPE` via a table
rebuild (because it lacks in-place `ALTER`) is a **Category-1 engine
implementation detail** (ADR-0038's taxonomy) and stays **invisible** —
no recipe, no rebuild steps surfaced — exactly as §9 and ADR-0030 §7
require. A learner sees the standard statement; the engine's means of
honouring it is not the lesson.
## Consequences
- Advanced mode reaches DDL parity with simple mode and adds