Files

245 lines
13 KiB
Markdown

# Session handoff — 2026-05-23 (33)
Thirty-third handover. This session implemented **ADR-0033 sub-phase
3j** (dispatch wiring — making `insert`/`update`/`delete` shared
DSL/SQL entry words), and the implementation surfaced a chain of
cross-cut interactions that were escalated, decided with the user, and
resolved by **ADR-0033 Amendment 3** (the command-identity / mode model
+ a new combined-error UX feature). A user-invoked `/runda` round at the
end found and fixed two more issues.
The next session does **sub-phase 3k** — the Phase-3 verification sweep
and phase-exit report. See §4.
## §1. State at handoff
**Branch:** `main`. **Tests: 1626 passing, 0 failing, 1 ignored.**
**Clippy:** clean (`cargo clippy --all-targets -- -D warnings`).
**Latest commit (local-only):**
```
d5c7f63 grammar+walker: 3j — shared insert/update/delete entry words (ADR-0033 §2 / Amendments 1 & 3)
```
`origin/main` is at `6b8888f` (3h), so **8 commits are local-only**
(the six 3i commits, the handoff-32 doc commit `c16196f`, and this
3j commit `d5c7f63`). Unpushed commits are a normal working state;
pushing is the user's step — do not prompt about it.
## §2. Process lessons (read first)
1. **The "DSL is the Simple-mode surface" premise was wrong about the
tests.** The plan's 3j exit gate assumed the DSL `insert/update/
delete` tests run in Simple mode. They do not — the common helpers
(`ok`/`err`/`parse`, `parse_command`, db `parse_filter`, the
`typing_surface` `assess`) default to **Advanced** mode. Pre-3j that
was harmless (those words were DSL-only, so Advanced still hit the
DSL grammar). Once the words became *shared*, Advanced routes them
to SQL. The fix was to **mode-correct the DSL tests to Simple**
(inputs/assertions unchanged), not to rewrite assertions. Recorded
as ADR-0033 Amendment 3.
2. **The dispatch model needed three escalation rounds with the user
to get right** (recorded as Amendment 3). The user's framing — which
is now the authoritative model — is:
- A command is the **mode-rooted grammar-path outcome**; its identity
is intrinsic (`Command::Insert` vs `Command::SqlInsert` are
distinct, both correct, both tested).
- **Execution is mode-independent** today; the differences are
"visual" (output/diagnostics), so a *valid* command replays /
executes identically regardless of which variant is produced.
- Simple mode **commits the DSL candidate** for a shared word
(surfacing the real DSL error); "this is SQL" is reserved for
entry words with no DSL form (`select`/`with`).
3. **`/runda` again earned its keep** (last session it found 6 bugs;
this session 2). Lesson re-confirmed: *probe, don't reason* — every
suspicion was checked with a throwaway test that printed the actual
`parse_command` / `ambient_hint` output before any conclusion.
Reasoning alone had me wrong twice (the `--all-rows` "regression"
that wasn't, and the replay "regression" that wasn't).
4. **Escalate ADR-vs-implementation mismatches; don't "improve"
silently.** The simple-mode behaviour, the replay mode, and the
combined-pointer UX were all escalated to the user before coding and
resolved by Amendment 3. The user values this; keep doing it.
## §3. What shipped this session (detail)
All in commit `d5c7f63`; the authoritative record is **ADR-0033
Amendment 3** (`docs/adr/0033-sql-dml-grammar.md`) — read it.
### 3j dispatch wiring (the planned work)
- `data.rs`: `SQL_INSERT`/`SQL_UPDATE`/`SQL_DELETE` CommandNodes moved
off the dev words (`sqlinsert`/`sql_update`/`sql_delete`) to the real
entry words `insert`/`update`/`delete`, category `Advanced`, alongside
the `Simple` DSL nodes. `build_sql_{insert,update,delete}` collapsed
to `source.trim()` (the row-source extraction is span-based, so it was
entry-word-agnostic already).
- `walker/mod.rs`: the two REGISTRY entry-word listing sites
(`completion_probe_in_mode`, `expected_at_input_in_mode`) now
de-duplicate the shared primaries.
- Dev-word inputs migrated to the real words across `tests/sql_*.rs`,
the walker diagnostic tests, and `completion.rs` (advanced mode).
### Dispatch model fixes (the cross-cut chain)
- **`decide` (walker/mod.rs)** — *Simple mode* now commits the DSL
candidate for a shared word (was: emitted "this is SQL" on
DSL-mismatch + SQL-match, which discarded the actionable DSL error
and broke phase-D / completion). *Advanced mode* commits the first
candidate that is `Match` **or** `ValidationFailed` (so an internal-
table rejection on the SQL candidate is surfaced, not masked by the
DSL fallback). Removed the now-dead `scratch_full_match`.
- **Mode-aware helpers** so simple-mode hints stop leaking the advanced
SQL view of a shared word: `classify_input_with_schema_in_mode`
(input_render), `invalid_ident_at_cursor_in_mode` (completion).
- **Test-mode correction:** DSL grammar / completion / phase-D / db
tests parse in **Simple** mode (`parse_command_in_mode(.., Simple)`,
`cands_simple`, `assess` pinned to Simple). `replay` keeps its
**Advanced** model (one stale "parse error" assertion relaxed to
"rejected, state intact").
### Combined DSL-error + advanced-SQL pointer (user-requested feature)
A Simple-mode **definite** DSL error whose line would run as SQL in
advanced mode keeps its DSL prose **and** gains the
`advanced_mode.also_valid_sql` suffix — e.g. *"for `Name`: Type a
quoted string … (valid as SQL in advanced mode — `mode advanced` or
prefix `:`)"*. Lives in `input_render::ambient_hint_in_mode` (live
typing) and `App::dispatch_dsl` (submit), both via the shared
`input_render::advanced_alternative_note`. New catalog key
`advanced_mode.also_valid_sql` (keys.rs + en-US.yaml).
### `/runda` round (two findings)
- **Finding A (fixed):** the combined pointer reached multi-row /
UPSERT in the live hint but **not** `delete … returning` (live
completion shadowed the error) and **not the submit path at all**.
Fixed by adding the pointer to `dispatch_dsl` (submit) — now every
Simple-mode definite-DSL-error-that's-valid-SQL gets it on submit.
- **Finding B (fixed):** simple-mode `insert into __rdbms_* …` parsed
to `Command::Insert` — the DSL data-command target slots had **no**
`reject_internal_table` (advanced SQL rejected them; simple did not).
Added the validator to the three DSL target slots
(`TABLE_NAME_EXISTING` / `_INSERT` / `_WRITES` in data.rs) so
insert/update/delete/show-data/show-table refuse `__rdbms_*` in both
modes (ADR-0030 §6 — "every table-source slot").
## §4. Sub-phase 3k — the NEXT job (verification sweep)
Read `docs/plans/20260520-adr-0033-phase-3.md` "Sub-phase 3k" and the
"Cross-cut verification matrix" section.
**Goal:** the Phase-3 phase-exit verification. Per the plan:
1. Author/extend the **end-to-end (Tier-3) integration tests** for the
real-world DML shapes listed in 3k's exit gate (INSERT…SELECT
cross-table; multi-row INSERT covering the ten types; UPDATE with
subquery in SET; DELETE with cascade; UPSERT round-trip; RETURNING
on all three; `history.log` replay of every Phase-3 form).
2. **Fill the cross-cut verification matrix** (every "X comes for free"
claim from ADR-0030/0031/0032/0033 → a passing test whose INPUT is
SQL syntax for SQL claims). Mark each row's `file::function`.
3. **Final DA review** — genuine, specific critiques first, verdict
last; rubber-stamp PASS is a process failure.
4. Produce the **phase-exit report** at
`docs/handoff/<date>-phase-3-verification.md`.
5. Confirm zero failures / zero skips / no regression from the Phase-2
baseline (1446/0/1; this session's count is **1626/0/1** and rising
as tests were added per sub-phase). Clippy clean.
**3k heads-up — re-run the full diagnostic + dispatch set.** 3j changed
how shared-word inputs route by mode; the new dispatch (Amendment 3) is
covered but exercise the compound forms (INSERT…SELECT…ON CONFLICT…
RETURNING) in *both* modes, and confirm the combined-pointer + internal-
table behaviour on the awkward inputs (per §2 lesson 3, *probe* the
output, don't assume).
## §5. Decisions settled this session (do not re-litigate)
Recorded in **ADR-0033 Amendment 3** (Accepted-in-spirit; the ADR is
still "Proposed" overall pending 3k). Key points:
- **Simple mode = DSL surface; commit the DSL candidate for shared
words.** "This is SQL" (bare) only for `select`/`with`. A shared-word
SQL construct in simple mode → DSL error **+ combined pointer**.
- **Advanced mode = SQL-first, DSL fallback.** Fallback fires on a
structural mismatch (`delete … --all-rows`); a content rejection
(internal table) on the SQL candidate is committed, not fallen back.
- **`update … --all-rows` in advanced does NOT fall back** — the SQL
`SET` expression absorbs `--all-rows` as `42 - -all - rows`; harmless
because the engine treats `--all-rows` as a SQL comment, so it runs as
"all rows" anyway. (Only `delete … --all-rows` falls back.)
- **Replay parses in Advanced mode** (the full surface, same parser as
interactive) — `run_replay` is unchanged in mode; a valid log replays
identically by the §6/§7 parity guarantees, so replay needs **no**
per-line mode. The deferred M4 is *not* a replay prerequisite.
- **Execution-time mode side-channel = deferred (M4).** Three-way `Mode`
(simple / advanced / advanced-one-shot) threaded to the worker for
mode-dependent *output* (e.g. simple `create table` echoing generated
SQL in advanced). Tracked in `requirements.md` **M4**; gets its own
ADR. **Not** a Phase-3 dependency.
## §6. Tracked deferred items (nothing lost)
Pick up after Phase 3 (3k) per the user's standing "extra tasks after
phase 3 is complete".
- **M4 — execution-time mode side-channel** (new this session;
`requirements.md`). See §5. Its own future ADR.
- **TASK #8 — implement ADR-0034 (history journal).** `history.log`
success-only ⇒ failed commands recallable in-session but lost across
sessions. ADR-0034 (`docs/adr/0034-…`, Accepted): complete journal
tagged `ok`/`err`; hydration reads all, replay reads `ok` only.
- **TASK #9 — fix broken replay + add the missing test.** `run_replay`
parses each whole line through the DSL parser with no understanding of
the `<ts>|<status>|<source>` journal format, so `replay history.log`
fails on line 1. (Note: 3j confirmed replay's *mode* is correct —
Advanced; #9 is about the *line format*, orthogonal.)
### Lower-priority observations (discussed, acceptable)
- **DDL internal-table rejection** is still absent: `drop table
__rdbms_*`, `add column to __rdbms_* …` etc. are not refused at parse
(Finding B fixed only the *data* commands, which have SQL
counterparts). No SQL DDL exists to compare against; flagged for a
future pass.
- The migrated test helpers `run_sqlinsert` / `run_update` /
`run_delete` (tests/sql_*.rs) keep their dev-word-era names though
they now parse the real words — cosmetic, low priority.
- `also_valid_sql` is *not* appended to mid-typing (incomplete) hints,
by design (avoids noise during normal DSL entry).
## §7. Process pins (unchanged, still binding)
- **Confirm every commit.** Propose the message; wait for the go-ahead.
No auto-commit at sub-phase gates (the user confirmed each commit).
- **Push is the user's step.** Never push; never prompt about it.
- **No AI attribution** in commits (global rule).
- **Test-first / probe-then-assert.** Reproduce with a failing (or
printing) test before concluding. `/runda`'s model: probe → confirm →
fix → keep the test.
- **Core walker changes** (`walk_seq` / `walk_choice` / `walk_repeated`)
need explicit user OK. `decide` (the dispatcher) and new post-walk
passes do not — but Amendment-worthy *behaviour* changes are
escalated and recorded (as Amendment 3 was).
- **Escalate ADR-mechanism mismatches; never classify work "out of
scope" without user confirmation.** (Finding B was fixed only after
the user said to; the DDL gap was flagged, not silently dropped.)
## §8. How to take over
1. **Read, in order:** this file →
`docs/adr/0033-sql-dml-grammar.md` (**Amendment 3** is the model
this session settled; also Amendment 1 = dispatch, Amendment 2 =
cascade) → `docs/plans/20260520-adr-0033-phase-3.md` "Sub-phase 3k"
+ "Cross-cut verification matrix" → `CLAUDE.md` →
`docs/requirements.md` (note new **M4**).
2. **Baseline:**
```
cargo test # expect 1626 passing / 0 failing / 1 ignored
cargo clippy --all-targets -- -D warnings # clean
```
3. **Start 3k** per §4: end-to-end DML integration tests, fill the
cross-cut matrix, final DA review, phase-exit report at
`docs/handoff/<date>-phase-3-verification.md`.
4. **Escalate** anything not settled in ADR-0033 / its amendments / the
plan; the user wants mismatches surfaced, not silently fixed.