Simple mode: wrong-count insert tuples miss the friendly arity diagnostic that advanced mode shows #17

Closed
opened 2026-05-29 11:21:04 +01:00 by oliversturm · 1 comment
oliversturm commented 2026-05-29 11:21:04 +01:00 (Migrated from github.com)

Observed

The friendly arity diagnostic (diagnostic.insert_arity_mismatch / insert_arity_mismatch_form_b, ADR-0033 §8.1 / Amendment 5) fires in advanced mode for wrong-count insert … values (…) tuples, but not in simple mode for the equivalent inputs.

Probed behaviour (schema Customers(id serial, Name, Age, SerNo) and Customers(id serial, Name, Email)):

Input Simple mode Advanced mode
insert into Customers values ('Oli', 52, 3) diags: [] → generic expected \)`` with no column list, all 4 column(s) need a value but 3 value(s) are given
insert into Customers values ('Alice') diags: [] → generic expected \,`` all 3 column(s) need a value but 1 value(s) are given
insert into Customers (Name, Email) values ('a', 'b', 'c') diags: [] → generic expected \)`` the column list names 2 column(s) but 3 value(s) are given

Root cause (hypothesis)

In simple mode the dispatch/grammar routes these to a structural Mismatch (the typed-slot path rejects the tuple — simple-mode Form B serial-skip changes the expected value count), so input_diagnostics_in_mode returns [] (the diagnostic pass runs only on a successful Match). In advanced mode the wrong-arity tuple takes the type-blind fallback, structurally Matches, and the diagnostic fires on the matched path.

The friendly message is computed by dml_insert_arity_diagnostics (src/dsl/walker/mod.rs:1465); the unit tests for it (insert_arity_mismatch_*, insert_form_b_arity_mismatch_*) all run in advanced mode via the diag_keys helper, which is why the simple-mode gap was never caught.

Expected

Simple-mode learners (the primary audience) should get the same friendly "N values for M columns" message as advanced mode, rather than a raw expected \,`/`)``.

Context

Surfaced during the fix for #2 (between-values hint). #2 made the simple-mode hint accurate (it surfaces the real parse error instead of a misleading "submit with Enter"); this issue is about making it friendly in simple mode too.

### Observed The friendly arity diagnostic (`diagnostic.insert_arity_mismatch` / `insert_arity_mismatch_form_b`, ADR-0033 §8.1 / Amendment 5) fires in **advanced mode** for wrong-count `insert … values (…)` tuples, but **not in simple mode** for the equivalent inputs. Probed behaviour (schema `Customers(id serial, Name, Age, SerNo)` and `Customers(id serial, Name, Email)`): | Input | Simple mode | Advanced mode | |---|---|---| | `insert into Customers values ('Oli', 52, 3)` | `diags: []` → generic `expected \`)\`` | `with no column list, all 4 column(s) need a value but 3 value(s) are given` | | `insert into Customers values ('Alice')` | `diags: []` → generic `expected \`,\`` | `all 3 column(s) need a value but 1 value(s) are given` | | `insert into Customers (Name, Email) values ('a', 'b', 'c')` | `diags: []` → generic `expected \`)\`` | `the column list names 2 column(s) but 3 value(s) are given` | ### Root cause (hypothesis) In simple mode the dispatch/grammar routes these to a structural **Mismatch** (the typed-slot path rejects the tuple — simple-mode Form B serial-skip changes the expected value count), so `input_diagnostics_in_mode` returns `[]` (the diagnostic pass runs only on a successful `Match`). In advanced mode the wrong-arity tuple takes the type-blind fallback, structurally Matches, and the diagnostic fires on the matched path. The friendly message is computed by `dml_insert_arity_diagnostics` (`src/dsl/walker/mod.rs:1465`); the unit tests for it (`insert_arity_mismatch_*`, `insert_form_b_arity_mismatch_*`) all run in **advanced** mode via the `diag_keys` helper, which is why the simple-mode gap was never caught. ### Expected Simple-mode learners (the primary audience) should get the same friendly "N values for M columns" message as advanced mode, rather than a raw `expected \`,\`/\`)\``. ### Context Surfaced during the fix for #2 (between-values hint). #2 made the simple-mode hint *accurate* (it surfaces the real parse error instead of a misleading "submit with Enter"); this issue is about making it *friendly* in simple mode too.
oliversturm commented 2026-05-29 21:45:36 +01:00 (Migrated from github.com)

Fixed in 10e5197.

Simple-mode wrong-count inserts now reach the same friendly arity diagnostic that advanced mode shows, at typing time — instead of a bare expected \,`/`)``.

Root cause confirmed. Simple-mode insert and advanced-mode insert use different grammar nodes. Advanced routes a wrong-count VALUES tuple to a type-blind fallback (tuple_value_list) so it structurally matches and dml_insert_arity_diagnostics fires; the simple-mode DSL value list (column_value_list) built a fixed-length typed Seq, so a wrong-count tuple Mismatched and the diagnostic never ran. (The issue #1 submit-time teaching note was a workaround for exactly this gap.)

Fix — unified onto the one ADR-0027 model (structural parse + ERROR diagnostic), advanced untouched:

  1. Grammar: a tuple_value_list-style gate (dsl_insert_value_list) routes a wrong-count DSL insert tuple to the shared type-blind fallback so it matches and the diagnostic fires. Gated to simple mode — in advanced the DSL node stays strict, so advanced behaviour is byte-for-byte unchanged (verified empirically). count_tuple_values + insert_target_columns are now shared by both grammars.
  2. Diagnostic is mode-aware: advanced Form B expects all columns; simple Form B/C expects the user-fillable columns (serial/shortid auto-fill, ADR-0018 §3). It now counts the DSL Form A role (insert_first_item) and scans the keyword-less Form C tuple. New catalog keys diagnostic.insert_arity_mismatch_form_b_simple (names the fillable and auto-generated columns) and diagnostic.insert_arity_mismatch_all_auto.
  3. Submit safety: a wrong-count DSL insert now parses Ok + carries the ERROR diagnostic (the [ERR] verdict), so a unified Ok-arm pre-flight (dsl_insert_count_mismatch_notes) blocks dispatch and shows the teaching note — the bad insert never reaches the worker. The issue #1 Err-arm note retires.

Scope guard: arity-diagnostic UX parity only — no consolidation of value-handling, execution, or auto-fill (ADR-0036's deliberate mode-distinctness stands; the per-mode count difference is a consequence of the auto-fill difference).

Documented as ADR-0036 Amendment 2 (cross-ref ADR-0033 §8.1) + README index + requirements.md H1a. Tests: simple Form A/B/C + all-auto arity diagnostics, execution-safety (no dispatch) for Form A/B, advanced-unchanged guard, typing-surface verdict assertions; full suite 2051 passing / 0 failing / 1 ignored, clippy clean.

Fixed in `10e5197`. Simple-mode wrong-count inserts now reach the same friendly arity diagnostic that advanced mode shows, at typing time — instead of a bare `expected \`,\`/\`)\``. **Root cause confirmed.** Simple-mode `insert` and advanced-mode `insert` use different grammar nodes. Advanced routes a wrong-count `VALUES` tuple to a type-blind fallback (`tuple_value_list`) so it structurally matches and `dml_insert_arity_diagnostics` fires; the simple-mode DSL value list (`column_value_list`) built a fixed-length typed `Seq`, so a wrong-count tuple Mismatched and the diagnostic never ran. (The issue #1 submit-time teaching note was a workaround for exactly this gap.) **Fix — unified onto the one ADR-0027 model (structural parse + ERROR diagnostic), advanced untouched:** 1. **Grammar:** a `tuple_value_list`-style gate (`dsl_insert_value_list`) routes a wrong-count DSL insert tuple to the shared type-blind fallback so it matches and the diagnostic fires. **Gated to simple mode** — in advanced the DSL node stays strict, so advanced behaviour is byte-for-byte unchanged (verified empirically). `count_tuple_values` + `insert_target_columns` are now shared by both grammars. 2. **Diagnostic is mode-aware:** advanced Form B expects all columns; simple Form B/C expects the **user-fillable** columns (`serial`/`shortid` auto-fill, ADR-0018 §3). It now counts the DSL Form A role (`insert_first_item`) and scans the keyword-less Form C tuple. New catalog keys `diagnostic.insert_arity_mismatch_form_b_simple` (names the fillable *and* auto-generated columns) and `diagnostic.insert_arity_mismatch_all_auto`. 3. **Submit safety:** a wrong-count DSL insert now parses `Ok` + carries the ERROR diagnostic (the `[ERR]` verdict), so a unified Ok-arm pre-flight (`dsl_insert_count_mismatch_notes`) **blocks dispatch** and shows the teaching note — the bad insert never reaches the worker. The issue #1 Err-arm note retires. **Scope guard:** arity-diagnostic UX parity only — no consolidation of value-handling, execution, or auto-fill (ADR-0036's deliberate mode-distinctness stands; the per-mode count difference is a *consequence* of the auto-fill difference). Documented as **ADR-0036 Amendment 2** (cross-ref ADR-0033 §8.1) + README index + requirements.md H1a. Tests: simple Form A/B/C + all-auto arity diagnostics, execution-safety (no dispatch) for Form A/B, advanced-unchanged guard, typing-surface verdict assertions; full suite 2051 passing / 0 failing / 1 ignored, clippy clean.
Sign in to join this conversation.