3a (grouping dispatch / ADR-0033 Amendment 1) and 3b (SQL INSERT) done; advanced-mode ambient assistance re-enabled (ADR-0022 Amendment 1) plus F1/F2 completion fixes. F3/F4/case-sensitivity triaged as non-issues; F5 (walk_seq keyword pollution) remains and needs user OK. Old-project migration deferred. Resume at F5, then Phase 3 sub-phase 3c.
13 KiB
Session handoff — 2026-05-21 (30)
Thirtieth handover. This session did two things:
- Started ADR-0033 Phase 3 (SQL DML) — wrote the Phase-3
implementation plan, then shipped sub-phases 3a (DSL/SQL
dispatch mechanism) and 3b (SQL
INSERTgrammar + minimal execution). - Ran an advanced-mode completion/hint bug-fixing interlude triggered by manual testing — fixed the dead advanced-mode ambient assistance plus two completion bugs (F1, F2), and triaged several other reports.
The next session should finish the interlude (one bug left,
F5, which needs the user's OK because it's a core walker
change) and then resume Phase 3 at sub-phase 3c
(INSERT … SELECT).
§1. State at handoff
Branch: main. Tests: 1473 passing, 0 failing, 1 ignored.
Clippy: clean (cargo clippy --all-targets -- -D warnings).
Commits this session (newest first; the last three are
local-only, origin/main is at 4e16d97):
1c8cbc1 completion+hint: F1/F2 advanced-mode completion fixes (local)
ed40445 ui: re-enable advanced-mode ambient assistance (ADR-0022 Amendment 1) (local)
c873631 grammar+db: 3b — SQL INSERT grammar + minimal execution (ADR-0033 §1) (local)
4e16d97 walker: 3a — category-grouped mode-aware dispatch (ADR-0033 Amendment 1)
a37a0b7 docs: ADR-0033 Phase 3 — implementation plan + cross-cut matrix
(Unpushed commits are a normal working state; pushing is the user's step — do not prompt about it.)
§2. Phase 3 — the main job (ADR-0033, SQL DML)
Controlling docs (read both):
docs/adr/0033-sql-dml-grammar.md— the decision. Read Amendment 1 especially (it supersedes §2's dispatch mechanism — see below).docs/plans/20260520-adr-0033-phase-3.md— the build order (sub-phases 3a–3k), per-sub-phase exit gates + DA gates, the cross-cut verification matrix (filled in during 3k), and the standing authorizations (commits pre-authorized within the plan — but see §5 below: the user has since asked to approve each commit and watch context, so confirm commits).
2.1. Done
Sub-phase 3a — DSL/SQL dispatch mechanism (commit 4e16d97).
The ADR originally specified Node::Guard + Choice(SQL, DSL).
That was found unworkable during 3a (any guard-in-Choice
forces a walk_choice change; walk_choice only falls through
on NoMatch, and walk_seq treats a NoMatch past idx 0 as a
hard Failed). It was replaced — with the user's explicit
approval — by category-grouped, mode-aware dispatch,
recorded in ADR-0033 Amendment 1:
- Each
REGISTRYentry is taggedCommandCategory::{Simple, Advanced}(insrc/dsl/grammar/mod.rs), generalising the old whole-commandis_advanced_onlygate. walker::walkis now a thin dispatcher overdecide+walk_one_command+ scratch helpers (src/dsl/walker/mod.rs). Simple mode commits the DSL node (or emits "this is SQL"); Advanced tries Advanced candidate(s) first, DSL as fallback.- A shared entry word carries a node in both groups; the
dispatcher selects by mode. No
Node::Guard, nowalk_choice/walk_seqchange.
Sub-phase 3b — SQL INSERT grammar + minimal execution
(commit c873631).
src/dsl/grammar/sql_insert.rs::SQL_INSERT_SHAPE— `INTO [ (cols) ] VALUES tuple(s)`, `__rdbms_*` target rejection (reuses `sql_select::reject_internal_table`, now `pub(crate)`).Command::SqlInsert { sql, target_table };Request::RunSqlInsert+do_sql_insertworker (tx-guarded: execute →finalize_persistencefor CSV + history → commit, so failures roll back and don't re-persist). Auto-show is best-effort vialast_insert_rowidrange.- Isolated behind a temporary dev entry word
sqlinsert(Advanced category) so the SQL path is testable WITHOUT makinginserta shared word yet. Tests usesqlinsert into …. - Deviations from the plan's literal
Command::SqlInsertfield list (to avoid dead-code under-D warnings):listed_columnsis deferred to 3d (shortid auto-fill) andreturningto 3g — the sub-phases that actually read them. - Tests: 6 grammar accept/reject (
sql_insert.rs) + 8 integration (tests/sql_insert.rs). - 3j is where the dev
sqlinsertword is removed andinsertbecomes a real shared word (register the SQL INSERT node asAdvancedalongside the DSLinsertSimplenode). With the grouping mechanism this is mostly registry wiring. 3j must also add de-duplication to the completion entry-word lists (completion_probe_in_mode/expected_at_input_in_modeinsrc/dsl/walker/mod.rs): onceinsertappears twice inREGISTRY, the entry-word candidate lists would show it twice. (Flagged in ADR-0033 Amendment 1.) - 3j must also confirm advanced-mode DSL inserts don't regress through the (now-shared) SQL path — which is why 3j comes after 3d's shortid-auto-fill parity.
- F1 — a premature "no such table/column" ERROR shadowed the
completion for the token being typed (the hint panel is the
completion UI; there is no separate popup). Fix in
input_render.rs::ambient_hint_in_mode: suppress an under-cursor ERROR diagnostic when a completion exists for the (non-empty) partial it overlaps; fall through to candidates. Genuinely-unknown names still error; WARNINGs unaffected; both modes. - F2 —
select <cursor> from T(after deleting*) offered the global column list instead ofT's columns, because the §10.6 look-ahead's full-input walk can't reachFROMthrough an empty projection. Fix incompletion.rs::candidates_at_cursor_with_in_mode: when the look-ahead finds no scope, retry with a neutral1placeholder inserted at the cursor so the trailingFROM/CTE scope is recovered for narrowing (only the repaired walk'sfrom_scope/cte_bindingsare consumed). - F3 ("
order by Name" flagged red / no suggestions) — was a downstream symptom of the old-project migration gap (see §4), not an ORDER BY grammar bug. On a fresh db it does not occur (order by <valid column>parses clean, narrows correctly). Confirmed by reproduction. - F4 ("only one error span highlights") — multi-span
highlighting works (two simultaneous unknown columns both get
flagged). The "des red while typing" the user saw is as-you-type
harshness on a partial keyword (
descmid-typed reads as trailing junk → parse error), not a single-span limit. - Case-sensitivity (table-name case vs. column narrowing) —
not a bug.
columns_for_table(completion.rs:90) useseq_ignore_ascii_case; verifiedfrom orders/from ORDERS/from Ordersall narrow correctly. An earlier DA-gate "flag" about this was an unverified guess and was retracted. show tablecrashes (no such column: m.check_expr);describe_tablefails for every table →build_schema_cache(runtime.rs:992) silently swallows the error →table_columnsends up empty → degraded completion (this was the real cause of the "F3" symptoms above).- Confirm every commit. The ADR-0033 plan pre-authorized commits, but mid-session the user asked to approve each commit and watch context use — so propose the commit message and wait for the go-ahead. No auto-commit at sub-phase gates.
- Push is the user's step. Never push; never prompt about it.
- No AI attribution in commits (global rule).
- Test-first discipline held throughout this session and should continue: reproduce a bug with a FAILING test first, then fix. For new features, exit-gate tests before "done."
- Don't trust unverified diagnoses — this session twice produced wrong guesses (the case-sensitivity "bug"; F3 as an ORDER BY grammar bug) that empirical probes disproved. Probe before fixing.
- DA discipline: specific critiques first, verdict last; a clean PASS with no critiques is a process failure.
- Core walker changes (
walk_seq/walk_choice) need explicit user OK before coding (the F5 fix is the pending example). - Read, in order: this file →
docs/adr/0033-sql-dml-grammar.md(esp. Amendment 1) →docs/plans/20260520-adr-0033-phase-3.md→docs/adr/0022-ambient-typing-assistance.mdAmendment 1 →CLAUDE.md. - Baseline:
cargo test # expect 1473 passing / 0 failing / 1 ignored cargo clippy --all-targets -- -D warnings # clean - First: finish the interlude — F5. Confirm with the user
that the core
walk_seqchange is OK (it's the only blocker), then implement test-first per §3.3. - Then: resume Phase 3 at sub-phase 3c (
INSERT … SELECT) per the plan, continuing 3c → 3k. Remember the 3j notes in §2.2 (removesqlinsertdev word, makeinsertshared, add completion-list de-dup) and the deferredlisted_columns/returningCommand fields (3d/3g). - Escalate anything not settled in ADR-0033 / the plan; don't classify work "out of scope" without user confirmation.
2.2. Remaining sub-phases (resume here after the interlude)
Per the plan, in order: 3c INSERT … SELECT → 3d
shortid auto-fill (adds listed_columns) → 3e UPDATE →
3f DELETE + cascade summary → 3g RETURNING (adds
returning flag) → 3h UPSERT (ON CONFLICT) → 3i
diagnostics (insert_arity_mismatch, auto_column_overridden,
not_null_missing) → 3j dispatch wiring → 3k
verification sweep.
Things to remember for later sub-phases:
§3. The advanced-mode completion/hint interlude
Triggered by the user manually testing advanced mode. Paused Phase 3 to harden it because broken ambient assistance poisons every advanced-mode test we'd write.
3.1. Fixed and committed
Ambient assistance re-enabled in advanced mode (ADR-0022
Amendment 1, commit ed40445). render_hint_panel hard-
returned None for advanced mode (a stale ADR-0022 §12 gate
predating the SQL grammar), and the hint resolver defaulted to
Mode::Simple. Now: ambient_hint_in_mode +
hint_resolution_at_input_in_mode + expected_for_hint_snapshot
thread Mode; render_hint_panel calls ambient for all modes;
the one-shot : sigil is stripped (strip_one_shot_prefix)
before the ambient walk. App-level render test
(ui::advanced_mode_hint_panel_surfaces_sql_candidates) +
ambient-layer locks. (Phase 2 had marked SQL hint/completion
"green" but only at the engine layer, never the UI — the gap
this fix closes.)
F1 + F2 (commit 1c8cbc1).
3.2. Triaged as NOT bugs (no work needed)
3.3. REMAINING — F5 (needs the user's OK before coding)
F5 — the order by (and projection) candidate list is padded
with ~13 invalid clause keywords (as, left, right,
full, cross, inner, join, where, group, having,
union, intersect, except). The columns are present and
correctly filtered, but the noise shoves them off-screen. The
user is fine with keywords-before-columns ordering as long as
the keyword list is reasonably filtered — i.e. fix the spurious
keywords.
Confirmed mechanism (probed): these are stale
skipped-optional clause keywords from the clauses positioned
between the last-consumed token and order by (the FROM's
JOIN options, WHERE/GROUP BY/HAVING, set-ops). They accumulate in
walk_seq's pending_skipped and get merged into ORDER BY's
Incomplete expected set — even though ORDER BY consumed bytes
and committed past those optionals. Control inputs proved it:
… where id = 1 order by drops where+JOIN keywords (consumed),
leaving group/having/set-ops; select 1 order by (no FROM)
adds from.
Proposed fix (CORE walker change — get user OK): in
src/dsl/walker/driver.rs walk_seq, the Incomplete arm
should NOT merge the accumulated pending_skipped when the child
that produced the Incomplete consumed bytes (i.e. committed past
those optionals). The NoMatch arm (child consumed nothing →
optionals are genuine alternatives at the cursor) keeps merging.
Blast radius: all parsing (1469+ tests). This is exactly the
kind of core change the project is careful about and the user
asked to approve it first. Do it test-first: a failing test that
asserts the order by expected set excludes
where/group/join/union/etc., then the fix, then full
suite + clippy.
§4. Deferred — old-project migration (do NOT fix now)
The user's first repro used an old project
(~/.local/share/rdbms-playground/projects/20260521-repro-1/,
created_at: 2026-05-09) whose __rdbms_playground_columns is
the pre-check_expr 3-column schema. Current code's
read_schema (db.rs:4197) hard-references m.check_expr, so:
The user explicitly deferred this — "having a migration story
at the end is perfectly fine." So: no migration work now. When
the migration framework lands (ADR-0015 Iter 6, pending), the
targeted fix is to ensure-current-metadata-columns on open
(idempotent ALTER TABLE … ADD COLUMN check_expr TEXT), make
read_schema not hard-crash on a missing internal column, and
stop build_schema_cache from silently swallowing the describe
error (it masked this for a long time). ADR-0015 would get an
amendment. Recorded here so it isn't lost.