# Session handoff — 2026-06-06 (58) Fifty-eighth handover. Continues from handoff-57, whose **next job was H1a**. This session did exactly that, end to end: **H1a (strong syntax-help in parse errors) is now done and marked `[x]`** in `requirements.md`, via a new ADR-0042 systematic pass. The arc was audit → ADR → test-first matrix → four gap fixes → two adversarial review passes that each caught a real defect. See §2. ## §1. State at handoff **Branch:** `main`. **HEAD `c305dc7`.** **origin/main at `10f8c2a`** (pushed mid-session) → **4 commits unpushed** (`649fdcb`, `1d4923b`, `d6e229f`, `c305dc7`). Push is the user's step. **Tests: 2158 passing / 0 failing / 1 ignored** (lib 1578, it 388, typing_surface_matrix 192; the 1 ignored is the pre-existing one). **Clippy clean** (nursery, all targets, `-D warnings`). This session's commits (since handoff-57's `a8d0138`): ``` c305dc7 docs: mark H1a done via the ADR-0042 systematic pass d6e229f feat: H1a CROSS JOIN ON teaching message; advanced-SQL gaps re-verified (ADR-0042) 1d4923b fix: H1a G3 advanced usage shows all valid forms; complete near-miss matrix (ADR-0042) 649fdcb feat: H1a parse-error gaps G2–G4 + advanced near-miss matrix (ADR-0042) 10f8c2a test: H1a near-miss matrix + friendlier `add 1:n relationship` label (ADR-0042) 0e6f767 docs: ADR-0042 — continue H1a parse-error pedagogy on the grammar tree ``` ## §2. What happened this stretch — H1a, start to finish ### Audit first (the big correction) The handoff-57 §6 pointer said "read ADR-0021 + ADR-0020". **Both are obsolete.** They specify a `chumsky`-over-tokens mechanism (`UsageEntry` registry, `parse.token.*` keys, a lexer) that **ADR-0024 deleted** — chumsky is not a dependency; the parser is the scannerless unified grammar-tree walker. ADR-0020/0021 are now marked **Superseded** (status notes + README), kept as memory. ADR-0021's *intent* survived and was already ~80% shipped via the grammar tree. **Read `docs/adr/0042-h1a-parse-error-pedagogy-grammar-tree.md`, not 0020/0021, for the live H1a design.** ### ADR-0042 + the user's three scope decisions Wrote **ADR-0042** (continues H1a against the grammar tree). Three forks escalated and decided by the user: (1) ADR hygiene = superseded-notes + new ADR; (2) scope = matrix-verify + friendlier literal labels; (3) advanced-SQL **in scope**. ### The near-miss matrix (the definition of done) `tests/it/parse_error_pedagogy.rs` now holds a per-command near-miss matrix, built **test-first** from an empirical baseline capture. Covers, in both modes: every entry word's bare / missing-clause / wrong-token cases, the app-lifecycle trailing-junk cases, and the **committed multi-forms** (`add index`, `add constraint`, `add 1:n relationship`, `drop index/constraint/ relationship`, `show table`, `change column`, `create index`, `alter table add/drop`). Tests: `near_miss_matrix_simple_mode`, `near_miss_matrix_advanced_mode`, `near_miss_matrix_committed_multiforms`, plus per-gap tests. ### Four gap fixes (each test-first) - **G1** — bare `1` cardinality literal → `` `1:n relationship` `` in `format_expectation` (render-only; completion still offers `1`). - **G2** — bare `select`'s 14-item expression first-set → "a projection: `*`, a column, or an expression", detected by the `distinct`+`all` quantifier pair (unique to a projection start; empirically verified non-misfiring). Render-only in `format_walker_error`. - **G3** — usage block was mode-blind. Added `usage_*_in_mode` (`src/dsl/grammar/mod.rs`) + mode threading through `render_usage_block` (`app.rs`) and the ambient usage (`input_render.rs`). **Decision (user, after review):** advanced mode shows **all forms valid in the mode, SQL-first then the DSL fallback forms** — DSL forms (`create table … with pk`, `drop column …`) remain valid input in advanced mode (verified), so a usage hint must not hide them. Simple mode = DSL only. - **G4** — `with` got its own `parse.usage.with` CTE template (was borrowing `select`'s). - **CROSS JOIN ON** — `parse.cross_join_no_on` teaches "a CROSS JOIN has no ON clause …" when the failing token is `on` and the most recent consumed join is a CROSS join. `is_cross_join_on` in `parser.rs`; render-only. ### Two adversarial review passes earned their keep - Pass 1 caught **G3 over-correction**: an initial "SQL-only" advanced usage block *hid* valid DSL fallback forms. Escalated → user chose "show all valid forms" → fixed (`1d4923b`). - "Verify, don't trust the survey" **reversed two of three** advanced-SQL "gaps": INSERT…SELECT count and RETURNING scope were *already handled* (the Explore-survey list was wrong, twice). Only CROSS JOIN ON was real. - The matrix itself caught a regression mid-work (advanced insert/update/delete falling back to available-commands because the SQL nodes have empty `usage_ids`; fixed with a union fallback). ### Deferred by decision (low-priority residual) At **submit** time, a non-projection expression position (bare `where `, `returning `, `having `, `set col=`) still renders the raw ~14-item expression first-set; only the SELECT projection is glossed (G2). Low-impact because **typing-time completion already offers the right candidates** there. User chose to leave it. Documented in ADR-0042 + `requirements.md`. Plus one **pre-existing caveat** (not this session's work, noted in ADR-0042): `insert into T (one_col) select * from Multi` isn't pre-caught for arity — `SELECT *` isn't expanded; the engine rejects it at execution (brushes ADR-0019 §OOS-2 engine-error territory). ## §3. ⚠️ Where parse-error pedagogy lives now (read before touching) - **Usage templates:** `parse.usage.*` in `src/friendly/strings/en-US.yaml`; `usage_ids` on each `CommandNode` (`src/dsl/grammar/mod.rs`). Mode-aware selection: `usage_keys_for_input_in_mode` / `usage_key_for_input_in_mode`. - **Structural error wording:** `format_walker_error` + `format_expectation` in `src/dsl/parser.rs` (this is where the G1 label, G2 projection gloss, and CROSS JOIN message live — render-only, they do **not** mutate the `Expectation` set the completion/hint layer consumes). - **Catalog discipline (ADR-0019):** every new key goes in `en-US.yaml` **and** `src/friendly/keys.rs::KEYS_AND_PLACEHOLDERS` (the `keys_validate_against_catalog` test enforces it). - **Tests:** integration parse-error tests live in `tests/it/` per the handoff-57 §3 rule — drop the file in `tests/it/` + add a `mod` line to `tests/it/main.rs`. Schema-aware diagnostics are tested at the walker level with a `SchemaCache` (`vschema` helper in `tests/it/sql_insert.rs`). ## §4. Carried / unchanged - **arboard decisions** (handoff-55 §3): X11-only on Linux; `copy` reproduces `[system]` tags. One-line changes if revisited. - No open GitHub issues (`gh issue list` empty; the project's issue tracker is GitHub, not the gitea host `tea` is configured for). ## §5. Other tracks (from `requirements.md`) Unchanged: Track 2 Iter 6 leftovers (history.log input-history hydration polish, migration-framework exercise); C3a modify relationship; C4 m:n convenience; **H1 done** (ADR-0019), **H1a done** (ADR-0042); H2 `hint`; H3 `help` (partial — general reference + `help ` still missing); V4 session-log / Markdown export; I1/I1b multi-line + readline; I3 tab completion / I4 syntax highlighting (the walker already exposes the hooks); TU1 tutorial (needs ADR); TT5 CI (not configured). ## §6. Next job — pick one No single forced next step. Candidates, roughly by readiness: 1. **H3 `help` completion** — the grammar tree already iterates the REGISTRY for the command list; the missing pieces are a general reference and `help ` per-command detail. The `help_id` per `CommandNode` is the hook. Small-to-medium. 2. **I3 tab completion** — the walker's expected-set + completion candidates already exist (used by ambient hints); I3 is the **UI/UX** (cursor handling, menu, accept). Needs its own ADR. 3. **The deferred H1a residual** (§2) — generalise the projection gloss to other expression positions. Low value (completion already covers typing-time); only if it bugs you. 4. **CI (TT5)** — test infra is solid (2158 green); no workflow yet. ## §7. How to take over 1. Read handoffs 56 → 57 → 58, then `CLAUDE.md`, then `docs/requirements.md` (H1 and **H1a now `[x]`**), `docs/adr/README.md`. 2. **For anything parse-error/pedagogy: read ADR-0042, not ADR-0020/0021** (those are superseded; chumsky is gone). 3. Codebase on `main` at `c305dc7`, clean, 4 unpushed. 4. Process pins that paid off this arc, again: **audit before assuming** (ADR-0021 was obsolete; H1a was mostly already shipped), **verify empirically — don't trust the docs/survey** (the advanced-SQL gap list was wrong twice; a regression hid in "looks fine"), **escalate genuine forks** (the G3 all-forms decision was the user's, not mine), and **test-first + matrix as a regression lock** (it caught a regression I introduced). Commits user-confirmed, append-only, no AI attribution.