Files
claude@clouddev1 abc9bb6d0f 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
2026-05-28 22:11:43 +00:00

15 KiB

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 VALUES-list completion stops giving useful hints once the first value is a string literal bug
7 Advanced mode: explain not yet supported enhancement
8 Advanced-mode syntax highlighting: identifiers and type keywords share the same teal color bug
9 [ok] explain <Table> is terse; reconsider whether [ok] line duplicates the SQL-echo line above it bug
10 Output panel: [error] tag color identical to [system] — gap in ADR-0037 enhancement
11 Copy output panel contents to the system clipboard enhancement
12 Long input hints overflow horizontally bug
13 Undo confirmation dialog: too narrow and language polish bug
14 --resume should restore the last-used input mode enhancement
15 Tab completion: offer common SQL function names in expression positions enhancement
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.