docs: session handoff 50 — issue triage + 6 issues closed, ADR-0033 Am5
Bug-report intake + triage + fix session — different shape from the recent feature-development handovers. Fourteen distinct observations triaged into GitHub issues; six resolved across three commits (c12ed1d,6f87ad1,24c2685). ADR-0033 gained Amendment 5 (`also_valid_sql` fires on validity, not just parse). Two enhancement trackers spawned from the /runda pass on the function-call validation work. Pins for the next session: - user preference: no issue numbers in commit messages - tests: 2040 / 0 / 1 (ignored), clippy clean - open ticket categorisation in §5 with a recommended pairing for the two enhancement trackers
This commit is contained in:
@@ -0,0 +1,293 @@
|
||||
# Session handoff — 2026-05-28 (50)
|
||||
|
||||
Fiftieth handover. **A bug-report triage + fix session** — different
|
||||
shape from the recent feature-development handovers. The user surfaced
|
||||
fourteen distinct issues from a single session of using the app; the
|
||||
session triaged all of them into GitHub issues, then resolved six
|
||||
clusters. Three commits, three closed issues (six original tickets
|
||||
folded into them), two enhancement trackers spawned for follow-up
|
||||
work outside bug-fix scope. **ADR-0033 gained Amendment 5.**
|
||||
|
||||
## §1. State at handoff
|
||||
|
||||
**Branch:** `main`. **HEAD `24c2685`.** **Tests: 2040 passing, 0
|
||||
failing, 0 unexpected skips, 1 pre-existing ignored** (the same
|
||||
ignored doctest as previous baselines). **Clippy: clean.**
|
||||
|
||||
Commits since handoff-49's `9468324`:
|
||||
|
||||
```
|
||||
24c2685 fix: SQL function-call names not flagged as columns
|
||||
6f87ad1 fix: advanced CREATE TABLE completion cluster
|
||||
c12ed1d fix: INSERT Form B value-count UX (ADR-0033 Amendment 5)
|
||||
```
|
||||
|
||||
Test count moved 2020 → 2040 (+20 across all three commits).
|
||||
|
||||
## §2. The shape of this session
|
||||
|
||||
This session was a **bug-report intake + triage + fix** loop. The
|
||||
user dumped a list of fourteen distinct observations from a session
|
||||
of actually using the app. The session:
|
||||
|
||||
1. Confirmed via `gh` CLI that GitHub issue tracking is available
|
||||
on `oliversturm/rdbms-playground` (the project intends to migrate
|
||||
to Gitea eventually, but `gh` works for now).
|
||||
2. **Investigated each observation** before filing — grounded every
|
||||
ticket body in concrete file:line references the explore agent
|
||||
surfaced or that direct grep confirmed.
|
||||
3. **Filed all fourteen as GitHub issues** with sensible grouping:
|
||||
- Some bundled (undo dialog width + undo dialog wording → one
|
||||
ticket).
|
||||
- Some split (the three CREATE TABLE completion bugs → three
|
||||
separate tickets because each closes cleanly on its own).
|
||||
- Some recategorised (the `[error]` vs `[system]` tag colour
|
||||
was on the fence between "documented design" and "real defect";
|
||||
filed as enhancement after user clarification).
|
||||
4. **Picked tickets in clusters of related code paths** to amortise
|
||||
the exploration cost.
|
||||
5. **Followed CLAUDE.md solo-mode discipline** at each step:
|
||||
requirements check → failing test first → implement → green +
|
||||
clippy → DA pass (often via `/runda`) → commit-with-approval →
|
||||
close-with-summary → enhancement spinoffs for adjacent ideas.
|
||||
|
||||
### User-preferred commit-message style — pinned
|
||||
|
||||
The user explicitly **does not want issue numbers in commit messages**
|
||||
(the project will migrate trackers; numbers won't point at anything
|
||||
later). Issue numbers in **issue bodies and close-comments** are fine
|
||||
(those migrate with the tracker). Cross-referencing issues inside the
|
||||
tracker is encouraged.
|
||||
|
||||
## §3. Closed issues
|
||||
|
||||
### #1 — INSERT Form B value-count UX (commit `c12ed1d`)
|
||||
|
||||
The user's original bug case: `insert into Customers values('Oli',
|
||||
52, 3)` against a 4-column table (`id serial PK, Name text, Age int,
|
||||
SerNo serial`) failed in simple mode AND in advanced mode, and the
|
||||
cross-mode pointer ("valid as SQL in advanced mode") fired
|
||||
misleadingly. Three layered fixes plus **ADR-0033 Amendment 5**:
|
||||
|
||||
- **Walker diagnostic** (`dml_insert_arity_diagnostics`): the
|
||||
function's own doc-comment recorded the Form B (no-column-list)
|
||||
branch as "deferred". This commit closed that gap — Form B
|
||||
mismatches now emit a new `diagnostic.insert_arity_mismatch_form_b`
|
||||
ERROR per offending tuple, keyed off the schema cache's column
|
||||
count. The `[ERR]` validity indicator (ADR-0027) now lights up at
|
||||
typing time for the user's reported scenario.
|
||||
- **Cross-mode pointer gate** (`advanced_alternative_note` in
|
||||
`src/input_render.rs`): refactored from a hand-rolled count check
|
||||
to a single `input_verdict_in_mode(input, schema, Mode::Advanced)`
|
||||
call. The pointer fires only when the verdict is `None` — the
|
||||
ADR-0027 sense of "valid". Any future static check added to the
|
||||
verdict pipeline participates automatically.
|
||||
- **Teaching notes** for the submit path:
|
||||
- simple-mode submit: `insert.form_b_extra_values_note` covers
|
||||
under-, in-window, and over-supply.
|
||||
- advanced-mode dispatch pre-flight:
|
||||
`insert.form_b_positional_count_mismatch_note`.
|
||||
|
||||
The `advanced_mode.also_valid_sql` pointer was reworded to *"trying
|
||||
to write SQL? switch with `mode advanced`, or prefix `:` to run
|
||||
once"* (one insta snapshot regenerated). **ADR-0033 Amendment 5**
|
||||
records the gate semantics with an explicit definition of "valid".
|
||||
`docs/requirements.md` H1a cites the three new pedagogical strings.
|
||||
|
||||
The /runda round on this issue surfaced and fixed a sub-issue: my
|
||||
initial gate was Form-B-specific, but the user pointed out that
|
||||
validity-verdict-driven is the principled answer. That led to the
|
||||
walker diagnostic (so the verdict picks up the mismatch) + the
|
||||
broader gate refactor.
|
||||
|
||||
### #3 + #4 + #5 — Advanced CREATE TABLE completion cluster (commit `6f87ad1`)
|
||||
|
||||
Three bugs in the same advanced-mode grammar + walker path:
|
||||
|
||||
- **#3:** `create table T ` (trailing space, advanced) offered only
|
||||
`with` — `(` for the SQL column-def list was missing. Root cause:
|
||||
the shared-entry-word completion merge in
|
||||
`completion_probe_in_mode` only fired at the entry-word boundary.
|
||||
Fix: broadened to fire at any cursor depth + handle
|
||||
`Expectation::Punct` continuations alongside `Word`/`Literal`.
|
||||
- **#4:** `create table T (` listed only the table-level constraint
|
||||
keywords (`primary`, `unique`, `check`, `constraint`, `foreign`) —
|
||||
the column-name role was invisible because `COLUMN_DEF` starts
|
||||
with an `Ident::NewName` slot that produces no concrete candidate.
|
||||
Fix: added a new **`HintMode::IntroProse(&'static str)`** variant
|
||||
that surfaces catalog prose at slot entry without suppressing Tab
|
||||
completion (unlike `ProseOnly`) and without requiring
|
||||
`typing_name_at_cursor` to fire (unlike `ForceProse`). Wrapped
|
||||
`ELEMENT` in `Node::Hinted { mode: IntroProse(
|
||||
"hint.create_table_element"), … }`. The prose reads *"Type a
|
||||
column name, or a table-level constraint: `primary`, `unique`,
|
||||
`check`, `constraint`, `foreign`"*.
|
||||
- **#5:** `create table T (count` and `create table T (count ` both
|
||||
leaked the bare keyword `double` (the first token of the dedicated
|
||||
`double precision` Choice branch per ADR-0035 §6.3) alongside the
|
||||
regular type list. Fix: added `("double", "double precision")` to
|
||||
`COMPOSITE_CANDIDATES` + extended the keyword filter to drop
|
||||
composite openers. The partial-typing prose case is subsumed by
|
||||
#4's IntroProse (user reads "Type a column name…" while
|
||||
mid-typing, then advances to the clean type list).
|
||||
|
||||
**Worth flagging for future readers:** the new `HintMode::IntroProse`
|
||||
variant is an additive extension to the ADR-0024 HintMode-per-node
|
||||
model. No behaviour change to existing modes. **No ADR amendment
|
||||
written** — the variant is currently used at one slot and the
|
||||
extension is straightforward. If a second use case lands, an ADR-0024
|
||||
amendment recording the variant alongside `ProseOnly` / `ForceProse`
|
||||
would be the right move.
|
||||
|
||||
### #6 — SQL function-call names not flagged as columns (commit `24c2685`)
|
||||
|
||||
`select sum(Age) from Customers` runs cleanly at the engine but the
|
||||
validator was treating `sum` as a column reference and flagging "no
|
||||
such column `sum` on table `Customers`". Two layered fixes for the
|
||||
same bug class:
|
||||
|
||||
1. **Walker** (`schema_existence_diagnostics`): the bare-column check
|
||||
on `sql_expr_ident` items now skips when the ident is immediately
|
||||
followed by `(` — it's a function-call name, not a column
|
||||
reference. New helper `is_followed_by_call_args` mirrors the
|
||||
existing `is_followed_by_qualified_ref` guard. Cascades to the
|
||||
`[ERR]` indicator, the red highlight overlay, and the diagnostic-
|
||||
driven ambient hint.
|
||||
2. **Typing-time** (`invalid_ident_at_cursor_in_mode`): early-return
|
||||
at `sql_expr_ident` positions. The partial could resolve to either
|
||||
a column reference or a function-call name; without lookahead for
|
||||
a trailing `(` we can't tell. Submit-time still catches genuine
|
||||
column typos via the schema-existence diagnostic and
|
||||
`pick_hint_diagnostic`.
|
||||
|
||||
The scope question in the original ticket body (which aggregate set
|
||||
to enumerate?) turned out to be moot — the fix is **all function
|
||||
calls**, matching ADR-0031 §1's stated posture (*"the grammar admits
|
||||
the call shape structurally; it does not know which names are
|
||||
aggregates"*). No grammar change; no ADR amendment.
|
||||
|
||||
**Trade-off worth knowing:** typing `select Agx` (no FROM yet) is
|
||||
now silent until FROM is added; previously the typing-time path
|
||||
flagged it as "No such column". This makes typing-time **consistent**
|
||||
with submit-time — the schema-existence pass already silently skipped
|
||||
no-FROM expressions ("no FROM in scope — engine catches"). For any
|
||||
expression-with-scope (SELECT with FROM, WHERE, etc.) the
|
||||
diagnostic-driven hint still fires for column typos. Pinned by the
|
||||
test `genuine_column_typo_in_complete_select_still_hints_via_diagnostic`.
|
||||
|
||||
Two **enhancement trackers spawned** from the /runda DA pass on this
|
||||
issue — see §5 below.
|
||||
|
||||
## §4. ADR work
|
||||
|
||||
**ADR-0033 Amendment 5** (2026-05-28, in `c12ed1d`):
|
||||
`advanced_mode.also_valid_sql` (Amendment 3's cross-mode pointer)
|
||||
fires on **validity**, not just **parse** — *"valid"* meaning
|
||||
`input_verdict_in_mode(input, schema, Mode::Advanced) == None` in
|
||||
the ADR-0027 sense. The amendment text spells out the exact
|
||||
condition so future readers can't drift back to a syntactic-only
|
||||
reading. Index entry in `docs/adr/README.md` updated. The user
|
||||
explicitly asked for the precise definition to be inlined, and
|
||||
agreed with the term **"valid"** (over "clean", "fully valid", etc.)
|
||||
because it ties cleanly to ADR-0027's existing vocabulary.
|
||||
|
||||
No other ADRs touched. ADR-0024's `HintMode` got a new variant
|
||||
(`IntroProse`) without an amendment — flagged in §3 above for the
|
||||
next session to consider if a second use case lands.
|
||||
|
||||
`docs/requirements.md` H1a (strong syntax-help in parse errors) got
|
||||
a citation line listing the three new pedagogical strings
|
||||
(`insert.form_b_extra_values_note`,
|
||||
`insert.form_b_positional_count_mismatch_note`,
|
||||
`diagnostic.insert_arity_mismatch_form_b`) as concrete contributions.
|
||||
|
||||
## §5. What's open
|
||||
|
||||
### Bug reports filed this session, still open
|
||||
|
||||
| # | Title | Label |
|
||||
|---|---|---|
|
||||
| [2](https://github.com/oliversturm/rdbms-playground/issues/2) | VALUES-list completion stops giving useful hints once the first value is a string literal | bug |
|
||||
| [7](https://github.com/oliversturm/rdbms-playground/issues/7) | Advanced mode: `explain` not yet supported | enhancement |
|
||||
| [8](https://github.com/oliversturm/rdbms-playground/issues/8) | Advanced-mode syntax highlighting: identifiers and type keywords share the same teal color | bug |
|
||||
| [9](https://github.com/oliversturm/rdbms-playground/issues/9) | `[ok] explain <Table>` is terse; reconsider whether `[ok]` line duplicates the SQL-echo line above it | bug |
|
||||
| [10](https://github.com/oliversturm/rdbms-playground/issues/10) | Output panel: `[error]` tag color identical to `[system]` — gap in ADR-0037 | enhancement |
|
||||
| [11](https://github.com/oliversturm/rdbms-playground/issues/11) | Copy output panel contents to the system clipboard | enhancement |
|
||||
| [12](https://github.com/oliversturm/rdbms-playground/issues/12) | Long input hints overflow horizontally | bug |
|
||||
| [13](https://github.com/oliversturm/rdbms-playground/issues/13) | Undo confirmation dialog: too narrow and language polish | bug |
|
||||
| [14](https://github.com/oliversturm/rdbms-playground/issues/14) | `--resume` should restore the last-used input mode | enhancement |
|
||||
| [15](https://github.com/oliversturm/rdbms-playground/issues/15) | Tab completion: offer common SQL function names in expression positions | enhancement |
|
||||
| [16](https://github.com/oliversturm/rdbms-playground/issues/16) | Restore typing-time column-typo hint for SQL expressions via known-function list | enhancement |
|
||||
|
||||
#15 and #16 were spawned from #6's /runda pass — both want a curated
|
||||
SQL-function list as a single source of truth; they should be
|
||||
tackled together.
|
||||
|
||||
### Categorisation (for next session's triage)
|
||||
|
||||
- **Spec-heavy (need discussion before code):** #9 (`[ok] explain`
|
||||
redundancy), #10 (`[error]` tag colour — needs ADR-0037
|
||||
amendment), #14 (`--resume` restore last mode — ties to ADR-0015
|
||||
Iter 6).
|
||||
- **Bounded code fixes:** #2 (VALUES completion regression), #8
|
||||
(identifier vs type colour), #13 (undo dialog), #7 (advanced
|
||||
`explain` — feature gap, more substantial).
|
||||
- **Substantial scope:** #11 (clipboard copy — user named it ~80%
|
||||
bug-report-friction reduction), #12 (long hint overflow — design
|
||||
call: wrap vs cap vs resize).
|
||||
- **Function-list cluster:** #15 + #16 (do together).
|
||||
|
||||
### Other tracks (unchanged from handoff-49, still pending)
|
||||
|
||||
From `requirements.md`:
|
||||
- Track 2 project storage Iter 5/6 — export/import + `--resume` +
|
||||
persistent input history + migration framework.
|
||||
- C3a (modify relationship), C4 (m:n convenience).
|
||||
- H1 friendly DB-error layer (partial), H1a syntax-help in parse
|
||||
errors (this session added the INSERT Form B contributions).
|
||||
- Tutorial / lesson system (needs its own ADR).
|
||||
- V4 session log + Markdown export.
|
||||
- I1 / I1b multi-line + readline shortcuts, I3 tab completion
|
||||
polish, I4 syntax highlighting beyond input echo.
|
||||
- ADR-0039 "explain over advanced SQL" — design agreed,
|
||||
implementation deferred.
|
||||
|
||||
## §6. Process pins (carried forward)
|
||||
|
||||
- **Confirm every commit** (propose message, wait). **No AI
|
||||
attribution.** **No issue numbers in commit messages** (this
|
||||
session's specific user preference — issue bodies and close
|
||||
comments may freely reference issue numbers).
|
||||
- **Test-first**; green + clippy-clean is the only acceptable end
|
||||
state; current baseline **2040 / 0 / 1**.
|
||||
- **Follow CLAUDE.md solo-mode phases** explicitly — requirements
|
||||
extraction → divergent exploration → evaluation → execution →
|
||||
verification. Each phase produces written artifacts. /runda is
|
||||
the standard tool for the DA pass between/after phases on
|
||||
non-trivial work; in this session every closed issue went through
|
||||
at least one /runda round before committing.
|
||||
- **Round-trip every catalogue row** (the ADR-0038 §1 contract; for
|
||||
multi-statement, per line) — unchanged from prior handovers.
|
||||
- **GitHub issue tracking is in use for now**, migrating to Gitea
|
||||
later. `gh` CLI works. `tea` CLI is the future-state per
|
||||
CLAUDE.md's Gitea section.
|
||||
|
||||
## §7. How to take over
|
||||
|
||||
1. **Read, in order:** this file → `requirements.md` for the open
|
||||
tracks → `docs/adr/README.md` for the ADR index → the relevant
|
||||
ADR for whatever feature/bug you pick up.
|
||||
2. **Baseline:** `cargo test` (2040 / 0 / 1) + `cargo clippy
|
||||
--all-targets` (clean).
|
||||
3. **For a bug fix from the open list:** start with the issue body,
|
||||
then probe the actual behaviour (the explore agent + targeted
|
||||
`panic!()` probe-tests in the relevant module are the fast path —
|
||||
see `simple_mode_submit_of_form_b_extra_value_teaches_serial_skip`
|
||||
in `src/app.rs` for a clean template). Then failing test → fix →
|
||||
green → /runda → commit-with-approval → close-with-summary.
|
||||
4. **For a fresh feature:** write the ADR (or extend an existing
|
||||
one), run `/runda` over the design before building, then build
|
||||
test-first.
|
||||
5. **Pick the next ticket** by checking §5's categorisation. If
|
||||
tackling #15 / #16, do them together — they share the
|
||||
known-function-list infrastructure.
|
||||
Reference in New Issue
Block a user