Commit Graph

360 Commits

Author SHA1 Message Date
claude@clouddev1 638b4c9664 feat(app): vi-style j/k/g/G navigation in the load picker (#24)
Add j (down), k (up), g (first) and G (last) to the load picker's
list sub-mode, alongside the existing arrow keys. Typeable keys keep
the picker drivable by autocast in the website's documentation casts,
which cannot emit arrow keys. Footer hint left unchanged.
2026-06-10 21:36:18 +00:00
claude@clouddev1 18303784a0 docs: session handoff 63 + ADR-0046 marked implemented (#20/#21/#23)
ADR-0046 status -> Accepted + implemented (8 commits 9f5f76b..22bec61);
README index updated; the two draft-divergent decisions recorded inline
(App.relationships not SchemaCache; nav overlay partial-clear + gutter).
Handoff 63 covers the full UI build across Phases A/B/C; issues
#20/#21/#23 closed on Gitea.
2026-06-10 21:30:00 +00:00
claude@clouddev1 22bec61d11 feat(ui): scroll the focused sidebar panel + refine the nav overlay (#21, ADR-0046 DC3 + DC2)
DC3 — navigation-mode scroll: the focused Tables / Relationships panel
scrolls (Up/Down by a line, PageUp/PageDown by its visible-row count).
Per-panel offsets are clamped to content at render time, and the
renderer reports each panel's visible rows for paging — mirroring the
output panel's scroll. render_items_panel / render_relationships_panel
take &mut App, count their rows, and store+clamp the offset before
building the borrowing lines.

DC2 refinement: the expand-on-focus overlay now clears only the sidebar
strip plus a one-column gutter, leaving the base output/input/hint
visible (unchanged) to the right rather than blanking the whole area —
truer to "underneath keeps its layout", with the gutter keeping the
cut-off edge clean (chosen after eyeballing both variants). ADR DC2 and
the overlay snapshot updated to match.

Tests: line/page scroll move only the focused panel and clamp; the
render clamps a past-the-end offset so the last row stays visible.
2026-06-10 21:27:13 +00:00
claude@clouddev1 c9da6ff785 feat(ui): Ctrl-O navigation mode — peek + expand the schema sidebar (#21, ADR-0046 DC1/DC2/DC4)
Ctrl-O enters a navigation mode orthogonal to the input mode, cycling
focus Input -> Tables -> Relationships -> Input (Esc exits). While a
sidebar panel is focused the sidebar is revealed (a peek, even when
width-hidden) and drawn as an expanded 45-column overlay over a cleared
main area, so the schema is browsable without the cramped 26-column
unfocused width. The focused panel gets an accent border.

Routing lives in the main key handler after the modal gate, so Ctrl-O
and nav keys are inert while a modal is open; in nav mode every
non-navigation key (printable/Enter/Tab/Backspace/...) is inert because
the input is occluded. Scroll keys (Up/Down, PageUp/PageDown) are
reserved for DC3 (next).

New App state: NavFocus { Input, SidebarTables, SidebarRelationships }.
Tests: the focus cycle, Esc exit, input-keys-inert, overlay reveal +
expansion, the accent-border style, and an overlay snapshot.
2026-06-10 18:56:39 +00:00
claude@clouddev1 94825d0f36 feat(ui): relationships sidebar panel + schema data (#21, ADR-0046 DB2/DB4)
The left column now stacks a Tables panel over a Relationships panel.
Each relationship renders as three narrow lines — its name, then the
endpoints broken at the arrow (Customers.id -> / indented
Orders.customer_id) — ellipsized past the inner width. The panel is
content-sized within [5 rows ("(none)" when empty), half the column];
the Tables panel keeps the rest (>=3 rows). Phase C adds focus+scroll
for content beyond the cap (clipped for now).

Data path: a new worker Request::ReadAllRelationships +
Database::read_all_relationships returns full RelationshipSchema
records; the runtime posts them via a RelationshipsRefreshed event
alongside the schema-cache refresh, and the App holds them in a new
`relationships` field.

ADR deviation (recorded in ADR-0046 DB2 + index): DB2 specified this
data on SchemaCache; it lives on the App instead — SchemaCache is
walker/completion-facing and needs only relationship names (untouched),
while the full records are UI-only, so App is the cleaner home and it
avoids editing ~23 SchemaCache literals. No behavioural difference.

Tests: panel-height bounds, the three-line render, the empty "(none)"
case, a snapshot, read_all_relationships end-to-end (real DB via the
m:n junction), and the event->field handler.
2026-06-10 18:44:27 +00:00
claude@clouddev1 386627a262 feat(ui): width-derived sidebar visibility — hide at <=90 cols (#21, ADR-0046 DB1)
The schema sidebar (the left Tables column) is now shown only when the
terminal is wider than 90 columns; at or below that it is hidden and
the output/input panels span the full width. This reclaims horizontal
space on narrow terminals — notably the 90-column screencasts, where
the sidebar added little and cost the output panel its width.

Visibility is a pure function of terminal width (sidebar_visible);
the Ctrl-O peek-reveal lands in Phase C. render() splits the layout
conditionally — full-width right column when the sidebar is hidden.

Snapshots/tests that rendered at 80 wide now reflect the hidden
sidebar; those whose intent IS the sidebar (populated_with_table, the
items-panel and drop-table integration checks) render at 110 so the
Tables list is actually exercised — one masked-intent integration
check (matched "Customers" in the output, not the panel) is corrected
the same way. New tests cover the width gate and the show/hide
boundary.
2026-06-10 18:28:57 +00:00
claude@clouddev1 41bae99ab3 feat(ui): two-row input display on tall terminals (#23, ADR-0046 DA4)
On a comfortable terminal (height >= 40) the input panel shows two
rows: the single logical command soft-wraps across them — the first
row stops 6 columns short for the ADR-0027 validity indicator, the
second uses the full width — so a medium command is fully visible
without horizontal scrolling. A line longer than both rows still
scrolls (DA3-style, one column each side reserved for < / > markers)
to keep the cursor visible.

hint_rows generalises to panel_heights(area) -> (input_rows, hint_rows):
compact (<40) stays input 1 / hint 2; comfortable becomes input 2,
degrading hint-then-input on tiny terminals to protect the output
Min(5). render_input_panel splits into render_input_one_row (the
existing DA3 path, unchanged) and render_input_two_rows, with a new
expand_runs_to_cells helper placing styled cells across the rows.

Tests: panel_heights geometry, two-row wrap, overflow-scroll, the
indicator-stays-on-the-first-row case, and a two-row layout snapshot.
Compact one-row snapshots are byte-identical (that path is untouched).
2026-06-10 18:19:15 +00:00
claude@clouddev1 e0b9470feb feat(ui): horizontal-scroll long input so the cursor stays visible (#23, ADR-0046 DA3)
A command longer than the input field used to clip silently at the
right edge, hiding the cursor and the command tail. Now the single
logical input line scrolls horizontally to keep the cursor in view,
with muted `<` / `>` markers at the reserved edge columns signalling
hidden content on either side.

The offset is a pure function of (line length, cursor column, field
width, previous offset) — input_scroll_offset — so the view only moves
when the cursor would leave the window, and one column is held on each
side for the markers so a marker never hides the cursor. The stored
App::input_scroll_offset resets when the buffer is replaced wholesale
(submit, history recall). The ADR-0027 6-column indicator reserve is
preserved.

Tests: pure-offset cases, tail-visible + head-visible render checks,
and the reset-on-submit/history check. One layout snapshot now shows a
long command's tail instead of its clipped head.
2026-06-10 18:08:45 +00:00
claude@clouddev1 9f5f76b05d fix(ui): geometry-fixed hint-panel height kills the typing jump (#20, ADR-0046 DA1/DA2)
The hint panel's height was recomputed every frame from the wrapped
hint content (1–3 rows), so it resized as the user typed and shoved
the input/output panels — the flicker visible in the screencasts.

Make the height a pure function of terminal geometry (new hint_rows),
fixed between resizes: 2 content rows on compact (<40-row) terminals,
3 only on comfortable terminals narrow enough (<54 inner cols) to wrap
the longest catalog hint past two lines, degrading toward 1 on tiny
terminals to protect the output Min(5). resolve_hint_lines clamps to
that fixed budget (long hints ellipsize; short ones leave rows blank).

This reverses issue #12's shrink-to-content "reclaim"; its two tests
are replaced by an anti-jump invariant plus geometry-helper and
third-row tests. Two layout snapshots regenerated.
2026-06-10 17:08:25 +00:00
claude@clouddev1 93266b99c9 docs: ADR-0046 UI sidebar nav-mode + responsive input/hint (#20/#21/#23)
Accepted; implementation pending, phased A→B→C. Treats the three
coupled UI issues as one decision (shared width/height budget):

- #20 hint jumpiness: hint height becomes a function of terminal
  geometry, fixed between resizes, so it no longer shoves the
  input/output panels.
- #21 left column: kept but width-optional (hidden by default ≤90),
  with a new relationships sibling panel and a Ctrl-O navigation/focus
  mode (peek-reveal, expand-on-focus overlay, scroll).
- #23 long input: single-logical-line horizontal scroll plus a 2-row
  display when tall, preserving the ADR-0027 indicator reserve.

A pre-build /runda DA pass drove key corrections: Ctrl-B→Ctrl-O (Ctrl-B
is the tmux prefix), an additive SchemaCache.relationship_details field
(retyping would break completion), full nav-mode key disposition +
modal gate, and Tier-2 snapshot coverage. Reconciles requirements
S1 (evolved), S2 (overridden — separate relationships panel), and
S4 (corrected — the stale "keyboard-toggleable" hint claim is struck;
no toggle added).

Updates docs/adr/README.md index and docs/requirements.md S1/S2/S4.
2026-06-10 16:57:46 +00:00
claude@clouddev1 f88018b4be docs: session handoff 62 — C4 m:n convenience command + issue #19 2026-06-10 14:28:50 +00:00
claude@clouddev1 8bd43ccadf feat: create m:n relationship convenience command (C4, ADR-0045)
`create m:n relationship from <T1> to <T2> [as <name>]` generates a
junction table with one FK column per parent PK column ({table}_{pkcol},
typed via fk_target_type), a compound PK over them, and two CASCADE 1:n
relationships -- all in one do_create_table call = one undo step.
Auto-named {T1}_{T2} (optional `as`), both modes, compound-parent PKs
supported (ADR-0043). Self-referential m:n / PK-less parent / internal
junction name / name collision all refused.

Wired across every surface: grammar (separate CREATE_M2N node), worker
executor, runtime dispatch, completion ("m:n" composite), hints,
highlighting, help + usage catalog + disambiguator, and the advanced-mode
DSL->SQL teaching echo (render_create_m2n, round-trips as valid SQL).

Generalized/fixed framework assumptions the build + two /runda passes
surfaced (all behaviour-preserving for existing commands):
- simple-mode dispatch committed simple.first() unconditionally -> tries
  candidates, so `create table` no longer shadows `create m:n`.
- the completion continuation-merge was advanced-only -> runs in simple
  mode too when an entry word has >1 DSL form (gated simple_count>1).
- do_create_table now rejects internal `__rdbms_*` names (closes a
  pre-existing hole on the DSL create-table path too, not just m:n).
- usage disambiguator now recognizes the `m:n` opener.

Tests: 14 integration (tests/it/m2n.rs), 7 typing-surface matrix, echo /
highlight / usage / internal-name units. Closes C4.
2237 pass / 0 fail / 1 ignored. Clippy clean.
2026-06-10 14:26:33 +00:00
claude@clouddev1 e598008ecf docs: ADR-0045 m:n convenience command (C4); accepted
create m:n relationship from <T1> to <T2> [as <name>] generates a
junction table (compound PK over the two FK column sets, CASCADE FKs)
plus two 1:n relationships, in one do_create_table call = one undo
step. Forks user-confirmed; /runda DA pass verified the reuse against
code and the no-PK-tables-exist-in-advanced-mode fact (parent-PK guard
retained). Self-referential m:n refused; FK cols named {table}_{pkcol}.
2026-06-10 13:18:07 +00:00
claude@clouddev1 e44d2983ab test+docs: lock drop-PK-refused on advanced surface; document no-PK advanced mode (#19)
Dropping a PK column was already refused in both modes via the shared
do_drop_column guard; this adds end-to-end coverage on the advanced
ALTER surface (single-column + compound PK, asserting refusal for the
right reason) and documents the asymmetry that advanced-mode SQL can
create a PK-less table (SQLite's implicit rowid keys it) while simple
mode forbids it. See issue #19 comment for the full assessment.
2026-06-10 13:18:07 +00:00
claude@clouddev1 b8034682ab docs: session handoff 61 — X1 logging full sweep + T3 residuals closed 2026-06-10 12:24:01 +00:00
claude@clouddev1 5a33f2aeea fix(fk): compound-FK violation message names every column pair
ADR-0043 residual: a compound-FK violation's friendly error named only the
first child->parent column pair (the ADR-0019 facts model is single-column).
enrich_fk_violation now gathers all pairs of the matched relationship and
carries them comma-joined in the existing single-column facts slots, so the
headline reads e.g. "no parent row in `Region` has `country, code` = `7, 8`."
instead of naming just `country`.

Single-column behaviour is unchanged (a one-element join is the element
itself). No facts-model or catalog change -- the joined strings flow through
the existing `{parent_column}` / `{value}` placeholders.

Tests: enrichment facts (compound names every pair, single-column
regression) + translate rendering (headline names both columns). 2211 pass
/ 0 fail / 1 ignored. Clippy clean.
2026-06-10 11:59:14 +00:00
claude@clouddev1 6985a43f31 fix(fk): inline FK referencing a compound PK points at the table-level form
ADR-0043 D4 residual: an inline column-level FK (`<col> REFERENCES P(a,b)`)
is single-column by construction, so referencing a parent's compound PK
gave the generic arity error ("1 foreign-key column(s) on the child side,
but `P`'s key has 2..."). It now points the user at the table-level form:
"an inline column reference can only name one column ... Use the table-level
form instead: FOREIGN KEY (<columns>) REFERENCES P (a, b)".

- Adds `inline: bool` to SqlForeignKey, set by the grammar's single shared
  builder consume_fk_reference (true for the inline path, false for the
  table-level and ALTER paths).
- resolve_fk_parent_columns takes `inline` and tailors the arity-mismatch
  message when an inline FK meets a compound key.

Tests: parse-layer (inline=true / table-level=false) + end-to-end worker
refusal wording. 2209 pass / 0 fail / 1 ignored. Clippy clean.
2026-06-10 11:49:33 +00:00
claude@clouddev1 0a7612efe2 feat: comprehensive logging across parser, app, persistence, runtime (X1)
Completes the X1 full sweep started in a8ad0c6 (db.rs). Closes X1 -> [x].

- persistence/mod.rs: debug! on every yaml/CSV/history write -- the
  silent-failure-prone disk paths (write_schema, write_table_data incl.
  the empty->delete branch, append_history/_failure).
- runtime.rs: debug! on execute_command_typed dispatch (one per executed
  command, complements the db.rs executor logs).
- app.rs: debug! on submit (route + submission mode), dispatch_app_command,
  and the ADR-0044 diagram-vs-prose render-mode choice.
- dsl/parser.rs: trace! on parse begin/outcome at the parse_command_inner
  choke point -- trace, not debug, because the live overlay/completion
  re-parse per keystroke (hot path).
- logging.rs: documented level discipline (error/warn/info/debug/trace) so
  the convention survives across sessions.

Levels verified end-to-end through the real worker thread + logging::init.
~75 -> 135 tracing sites total. Tests: 2207 pass / 0 fail / 1 ignored.
Clippy clean.
2026-06-10 11:38:22 +00:00
claude@clouddev1 a8ad0c6cc3 feat(db): comprehensive logging across worker + executors (X1)
Instrument db.rs to the CLAUDE.md "log liberally" bar (X1). 26 -> 67
tracing sites:

- Entry-level debug! on all 34 do_* executors (DDL, DML, relationship,
  index, read paths), matching the existing do_sql_delete/do_run_select
  style -- so the route through delegating executors (e.g. add_column ->
  add_constrained_column_via_rebuild) is visible in the log sequence.
- Decision-point logs: rebuild_table primitive (begin/commit; FK-check
  failure and foreign_keys re-enable failure as warn), do_insert autofill
  summary, do_delete cascade summary, do_create_table FK resolution.
- Worker lifecycle (start/exit) raised debug! -> info! so it shows at the
  default level.

Levels per the X1 discipline: debug for per-command detail (off by
default, opt-in via RDBMS_PLAYGROUND_LOG=debug), info for lifecycle, warn
for fallbacks. Loops log summary counts, never per-row.

Tests: 2207 pass / 0 fail / 1 ignored (unchanged). Clippy clean.
2026-06-10 11:26:45 +00:00
claude@clouddev1 1152b0dc14 docs: session handoff 60 — Gitea migration cleanup + V1 relationship visualization (ADR-0044) 2026-06-10 10:40:48 +00:00
claude@clouddev1 0a343036d8 feat: compound-FK bus routing + complete V1 relationship visualization (ADR-0044)
Completes requirement V1. A compound (multi-column) FK now routes a
bus connector — each paired endpoint's stub merges into a shared
vertical channel that splits to the other side — plus an explicit
"(a, b) ▶ P.(x, y)" pairing line; the bus generalises the single-column
jog (reproducing it exactly, so prior snapshots are unchanged).
Self-referential FKs render as two same-named boxes.

- output_render.rs: gutter_seg routes all endpoint pairs via a
  junction() bus; pairing line for compound FKs; compound, self-ref,
  and compound-from-data (build_diagram_table glue) tests + snapshots
- compound_fk.rs: worker test that show_relationship carries both
  paired column lists into the diagram payload
- db.rs: document do_show_one's now-app-superseded relationship prose
  branch (retained as a worker-API/text fallback; could back a future
  non-visual display option, cf. ADR-0044 OOS-7)

Second /runda pass over the implementation: confirmed ADR-compliance,
UTF-8/byte-range safety, and edge-case routing. The ADR §3 last-resort
helper line was considered and rejected (vertical fallback + ratatui
truncation cover all realistic cases). ADR-0044 marked implemented;
requirements.md V1 -> [x].

Full suite 2207 pass / 0 fail / 1 ignored; clippy nursery clean.
2026-06-10 10:17:09 +00:00
claude@clouddev1 a0ee32393f feat: show table renders relationships as compact diagrams (ADR-0044)
show table <T> and add/drop relationship echoes now render the focal
structure box plus a Relationships section of compact stacked
connector diagrams (child-left/parent-right, n…1, actions); incidental
DDL echoes keep the prose References:/Referenced by: form. Selected by
command in handle_dsl_success via the "relationship-relevant" reach.

- output_render.rs: render_structure refactored into section helpers
  (box/prose/index/constraint), byte-identical output; new
  render_structure_with_diagrams + compact-box rendering
- app.rs: handle_dsl_success routes ShowTable/Add/DropRelationship to
  the diagram path, others to prose
- fixes: eager widths[1] index on compact (1-col) boxes; body-cell
  padding under title-widening (name wider than columns)

Tests: unit + snapshot + integration; add-relationship echo test
updated to the diagram form. Full suite 2203 pass / 0 fail / 1 ignored;
clippy clean. V1 still [/] (compound routing + self-ref remain).
2026-06-10 06:56:35 +00:00
claude@clouddev1 cad90ec4a5 feat: show relationship <name> renders a styled two-table diagram (ADR-0044)
The first wired slice of relationship visualization (V1). `show
relationship <name>` now renders the relationship as two full
structure boxes joined by a width-jogging connector (child-left /
parent-right, n…1 cardinality, on delete/update actions), styled
App-side, with a vertical-stack fallback for narrow terminals.

- db.rs: RelationshipDiagramData + show_relationship worker path
  (structured data: the relationship + both endpoint TableDescriptions)
- runtime.rs: named relationships route to the structured outcome
  (boxed); other show <kind> forms stay prose
- app.rs/event.rs/ui.rs: DslShowRelationshipSucceeded rendered App-side;
  new diagram OutputStyleClass variants; App::last_output_width from ui.rs
- output_render.rs: styled Seg layout engine (boxes, connector routing,
  side-by-side + vertical), composing the ADR-0016 box primitives

Tests: 4 unit + 4 integration; full suite 2201 pass / 0 fail / 1 ignored;
clippy nursery clean. requirements.md V1 stays [/] (show table diagrams,
compound routing, DDL-echo wiring remain).
2026-06-09 22:27:39 +00:00
claude@clouddev1 bb02dfb752 docs: ADR-0044 relationship visualization (V1); accepted
Two-table connector diagrams (Style A) for relationships, resolving
ADR-0016 OOS-1 and the open half of requirements.md V1. Reach is
'relationship-relevant' (show relationship / show table / relationship
DDL echoes; incidental echoes keep prose). App-side rendering, width-
adaptive side-by-side vs vertical, compound-FK pair routing, bold box
title rows. Revised after a /runda DA pass corrected three inverted-
architecture claims (App-side rendering, untracked output width,
prose-in-worker show-relationship).

Index updated per ADR-0000.
2026-06-09 21:47:35 +00:00
claude@clouddev1 b17148b467 docs: scrub GitHub-specifics after Gitea migration; add tea issue conventions
- Cargo.toml: repository -> git.lazyeval.net/oli/rdbms-playground
- requirements.md: backlog now tracked as Gitea issues
- ADR-0001 Amendment 1: distribution channel reopened post-migration
  (Decision text preserved per supersede-don't-rewrite)
- CLAUDE.md: issue-tracking working method + Gitea/tea operational section
2026-06-09 20:07:40 +00:00
claude@clouddev1 e9b7f58fbc docs: session handoff 59 — tracking reconciliation + V5/H3/V5a sweep + T3 compound-PK FK (ADR-0043) 2026-06-09 18:45:58 +00:00
claude@clouddev1 4752ba29a0 feat: compound-PK foreign-key references — grammar + tests (ADR-0043)
Multi-column FK parsing on both surfaces: DSL from P.(a, b) to
C.(x, y) (parenthesized endpoint; single bare form unchanged) and
SQL FOREIGN KEY (a, b) REFERENCES P(x, y) incl. bare-reference
auto-expand. consume_fk_reference + the table-level/ALTER FK
parsers collect column lists; the from P. completion now offers
( (snapshots updated). 12 integration tests in
tests/it/compound_fk.rs cover parse (both surfaces), engine-enforced
FK, arity + partial-PK + per-pair-type-mismatch refusal,
--create-fk per-column, save->rebuild round-trip, undo (one step),
and single-column preservation. Mark T3 [x]; ADR-0043 implemented.
2026-06-09 18:44:37 +00:00
claude@clouddev1 b14f0199e9 refactor: relationship model to column lists for compound FK (ADR-0043)
Move the FK column fields String->Vec<String> through all six
layers (AddRelationship/SqlForeignKey AST, RelationshipSchema,
metadata, project.yaml, ReadForeignKey, RelationshipEnd). Metadata
stores comma-joined lists in the existing TEXT cells; project.yaml
endpoints now columns: [a, b] (house style). Executor logic is
multi-column ready: resolve_fk_parent_columns (full-PK F-A +
auto-expand F-D), per-pair type-compat, schema_to_ddl multi-column
emission, pragma FK read grouped by id, auto-name + --create-fk
per-column, multi-column teaching echo. Single-column behaviour
preserved (one-element vecs); all 2181 tests green. The grammar to
parse multi-column input lands next.
2026-06-09 18:25:40 +00:00
claude@clouddev1 b688592b4c docs: ADR-0043 implementation-readiness notes from /runda DA pass
DA pass found three change sites the first sketch missed
(teaching-echo renderers, --create-fk per-column creation, the
auto-name generator) and made explicit the rules the forks left
implicit: SQLite FK precondition (compound PK provides the unique
index), explicit parent cols must be the PK set (any order,
positional), arity/empty/inline-rejection wording, single-in-parens
accepted, --create-fk per-column typed to fk_target_type. Expanded
the test plan to cover enforcement, auto-expand, undo, round-trip.
Fixed a stale 'legacy yaml loads' test line (no back-compat).
2026-06-09 17:11:01 +00:00
claude@clouddev1 274e2b17b7 docs: ADR-0043 compound-PK foreign-key references (T3); accepted
Audit found single-column FK woven through ~15-20 sites; earns an
ADR. Decision: reference the parent's full compound PK, matched
positionally to an equal-length child list, per-pair type compat.
DSL `from P.(a,b) to C.(x,y)`; SQL `FOREIGN KEY (x,y) REFERENCES
P(a,b)` with bare-FK auto-expansion. Storage follows the existing
primary_key: [...] list convention (yaml columns: [a,b], uniform
JSON in unchanged metadata TEXT cols); back-compat not required,
so no migration. Also marks T3's verified scope.
2026-06-09 17:01:38 +00:00
claude@clouddev1 1d898adf00 feat: V5a show relationship/index <name> detail views
Fold the singular per-item forms into Command::ShowList { kind,
name: Option<String> } (name: Some = one item). Two grammar
branches reuse the relationship/index completion sources; worker
do_show_one renders a labelled detail block or a friendly
"No ... named X." line, reusing the V5 render path. Help +
parse-usage entries, two ADR-0042 near-miss rows, 5 integration
tests. Mark V5a [x] — V5's [<name>] clause now complete.
2026-06-07 14:04:00 +00:00
claude@clouddev1 757711f2bf feat: H3 help <command> per-command detail + general reference
HELP node takes an optional single-word topic (BarePath);
AppCommand::Help { topic }. note_help_topic renders the help
block(s) of every command sharing that entry word (so `help
create` covers both create forms), plus `help types` and a
friendly "no help for X" pointer for unknown topics. Full help
gains a detail-hint footer. Catalogued help.detail_hint /
help.unknown_topic; parse-error matrix updated (help now takes a
topic, so the near-miss is the multi-word case). 9 integration
tests in tests/it/help_command.rs. Mark H3 [x].
2026-06-07 13:32:18 +00:00
claude@clouddev1 8dec784080 feat: V5 show tables / relationships / indexes list commands
Add the list-all show family as one Command::ShowList { kind }
variant. A read-only worker show_list formats count-headed lists
(reusing do_list_tables / read_all_relationships /
read_table_indexes, so it never drifts from the items panel);
internal __rdbms_* tables excluded. Help + parse-usage entries
added; 10 integration tests in tests/it/show_list.rs.

Mark V5 [x]. Split the singular show relationship/index <name>
detail forms (the [<name>] half) into a new tracked V5a [ ] item
rather than leaving them as an untracked footnote.
2026-06-07 13:20:52 +00:00
claude@clouddev1 28e75961aa docs: reconcile requirements tracking with verified code state
Audit of all 35 [ ] items vs source found ~46% mis-marked. Add a
[/] partial marker; promote 7 shipped-but-open items to [x]
(S1/S4/S5/I1a/I3/I4/C1) and 9 substantially-built ones to [/]
with gap notes (S3/A1/V1/V2/V5/T3/H3/DOC1/X1). Fix CLAUDE.md's
false "Tier 4 is wired" claim — no PTY tests exist.
2026-06-07 12:31:16 +00:00
claude@clouddev1 ca158e8b25 docs: session handoff 58 — H1a done via ADR-0042 systematic pass 2026-06-06 12:29:47 +00:00
claude@clouddev1 c305dc7282 docs: mark H1a done via the ADR-0042 systematic pass
requirements.md H1a → [x]: the per-command near-miss matrix (entry words,
missing clauses, committed multi-forms, both modes) plus the gap fixes
(G1 `1:n relationship`, G2 select projection gloss, G3 mode-aware usage
showing all valid forms, G4 `with` CTE template, CROSS JOIN ON teaching
message) close the systematic pass. The advanced-SQL items the survey
flagged (INSERT…SELECT count, RETURNING scope) were verified already
present. One low-priority residual is deferred by decision (submit-time
expression first-set at non-projection positions).

ADR-0042: record the pre-existing `SELECT *` arity caveat (INSERT…SELECT
with a star projection isn't expanded for pre-flight arity; engine
catches it at execution — adjacent to ADR-0019 §OOS-2).
2026-06-06 07:44:55 +00:00
claude@clouddev1 d6e229f0f5 feat: H1a CROSS JOIN ON teaching message; advanced-SQL gaps re-verified (ADR-0042)
Empirically re-checking ADR §3's advanced-SQL "gaps" reversed two of
three — the code survey that produced the list was wrong:
- INSERT…SELECT column-count: already handled (verdict=Error, "the
  column list names N column(s) but M value(s) are given";
  insert_select_arity_mismatch_fires).
- RETURNING scope: already handled (completion offers the table's
  columns; `returning <unknown>` → unknown_column diagnostic).

The one genuine residual is fixed: `select … cross join b on …`
rejected the ON with a bare "expected end of input". Add
parse.cross_join_no_on — "a CROSS JOIN has no ON clause — it pairs
every row; for a join condition use `JOIN … ON`, or filter with
`WHERE`" — rendered when the failing token is `on` and the most
recent consumed join is a CROSS join (a precise signature: every
other join requires `on`, so `on` is expected there, not a failure).
Render-only in format_walker_error; two misfire guards locked (plain
join still asks for ON; a stray `on` with no join does not fire).

ADR-0042 §3 corrected + Implementation-outcome records the advanced-SQL
re-check and the user-confirmed low-priority residual (submit-time
expression first-set at non-projection positions, where typing-time
completion already offers the right candidates).

Full suite green (lib 1578 / it 388 / typing_surface_matrix 192); clippy clean.
2026-06-05 19:02:11 +00:00
claude@clouddev1 1d4923b15b fix: H1a G3 advanced usage shows all valid forms; complete near-miss matrix (ADR-0042)
The /runda DA pass found G3 over-corrected: advanced-mode `create`/`drop`
showed SQL forms only, hiding the DSL fallback forms that are valid input
in advanced mode (verified: `create table Foo with pk`, `drop column …`
parse and dispatch). Per the user decision, the advanced usage block now
shows every form valid in the mode, SQL-primary first, then the DSL
fallback forms — a usage hint must never hide working input. Simple mode
unchanged (DSL forms only).

Matrix completion (closing the residual coverage tail):
- arg-less app commands (help/rebuild/new/load/undo/redo/export/import)
  audited + locked — all reject trailing junk with "expected end of
  input" + usage.
- committed multi-forms (add index/constraint/1:n relationship, drop
  index/constraint/relationship, show table, change column, create index,
  alter table add/drop) audited + locked in
  near_miss_matrix_committed_multiforms — each renders its own
  form-specific missing-keyword message + usage.

Also from the DA pass:
- G2 distinct+all detector empirically verified unique to projection
  start (no misfire at count( / union / union all / select distinct).
- stale `chumsky` comment removed (app.rs import handler).
- ADR-0042 Implementation-outcome section records G1–G4, the
  user-confirmed G3 decision, and the now-complete matrix coverage.

Full suite green (lib 1578 / it 387 / typing_surface_matrix 192); clippy clean.
2026-06-05 18:46:57 +00:00
claude@clouddev1 649fdcb38e feat: H1a parse-error gaps G2–G4 + advanced near-miss matrix (ADR-0042)
Close the three remaining ADR-0042 triage gaps, each test-first, and
lock the advanced-mode near-miss matrix.

G2 — bare `select` dumped the 14-item expression first-set. Collapse
it to "a projection: `*`, a column, or an expression" in the error
message only (parser::format_walker_error), detected by the joint
`distinct`+`all` quantifier signature unique to a projection start.
Render-only: completion/hints still expand the full set (typing-surface
matrix unchanged).

G3 — the usage block was mode-blind: advanced `create table` showed the
DSL `create table … with pk …` template. usage_key(s)_for_input gain
mode-aware `_in_mode` variants selecting candidates by CommandCategory;
render_usage_block and the typing-time ambient usage thread the
submission mode. Advanced `create` now shows both SQL forms. A fallback
covers shared SQL nodes (insert/update/delete) that declare no
usage_ids of their own — without it they regressed to the
available-commands fallback (caught by the new advanced matrix).

G4 — `with` borrowed `select`'s usage template; give it its own
parse.usage.with CTE template.

Tests: new near_miss_matrix_advanced_mode (12 SQL-surface cases incl.
the available-commands regression guard) + per-gap tests; removed the
temporary baseline_dump. Full suite green (lib 1578 / it 386 /
typing_surface_matrix 192); clippy clean.
2026-06-05 14:57:20 +00:00
claude@clouddev1 10f8c2a95c test: H1a near-miss matrix + friendlier add 1:n relationship label (ADR-0042)
Start the ADR-0042 §1 near-miss matrix: a table-driven
near_miss_matrix_simple_mode locking 26 simple-mode parse-error
renderings (every DSL entry word's bare/missing-clause cases plus the
mode arg-errors and the "this is SQL" rail), and an #[ignore]
baseline_dump capturing the full rendering for ongoing triage.

G1 fix: the bare `1` cardinality literal that opens `add 1:n
relationship …` rendered cryptically in expected-sets. Render it as
`1:n relationship` in error wording only (format_expectation) —
completion/hints still read the raw Expectation::Literal("1"), so the
candidate surface is unchanged. Updated the one anchor test.

Full suite green (lib 1578 / it 382 / typing_surface_matrix 192).
2026-06-05 08:04:24 +00:00
claude@clouddev1 0e6f767848 docs: ADR-0042 — continue H1a parse-error pedagogy on the grammar tree
ADR-0020/0021 specified a chumsky-based H1a; ADR-0024 replaced chumsky
with the scannerless walker, leaving both obsolete. Mark them superseded
(kept as institutional memory) and add ADR-0042, which restates H1a
against the architecture as built.

ADR-0042 records that H1a is substantially shipped already — per-command
usage block, available-commands fallback, source-derived ident slot
labels, curated parse.custom.* near-miss messages, and schema-aware
[ERR] diagnostics — and defines the remaining work: a verified
per-command near-miss matrix (the definition of done), friendlier
literal expectation labels that add role context while keeping the
exact literal visible, and advanced-mode SQL parse parity (RETURNING
scope, CROSS JOIN ON, INSERT…SELECT count), kept distinct from
ADR-0019 §OOS-2 engine-error sanitisation.

- docs/adr/0020,0021: superseded notes + README entries
- docs/adr/0042: new ADR
- docs/adr/README.md: index upkeep (ADR-0000 rule)
2026-06-03 14:05:09 +00:00
claude@clouddev1 a8d0138d8b docs: session handoff 57 — H1 verified done, target/ 38 GB → 1.6 GB, tests consolidated
Captures the post-handoff-56 arc: H1 (ADR-0019) verified already shipped
(not "partial"); build-hygiene fixes (incremental off, line-tables debug,
cargo-sweep) cutting target/ from 38 GB to ~1.6 GB; and consolidating 25
integration crates into one `it` binary (disk win, not the predicted
speed win). Flags the new test layout (add tests under tests/it/ + a mod
line) and points the next session at H1a (ADR-0021) as the queued job.
2026-06-02 22:17:06 +00:00
claude@clouddev1 9efae59c3c test: consolidate 25 integration crates into one it binary
Each top-level tests/*.rs was its own crate → its own binary, each
statically linking the bundled engine + every dep. 26 of them, so an
edit to the lib relinked all 26. Moved the 25 standalone files into
tests/it/ under one tests/it/main.rs (the pattern typing_surface
already uses); cargo auto-detects it as the `it` target. End state: 2
integration-test binaries instead of 26.

Result: target/debug/deps 1.5 GB → 629 MB (-58%). Build time barely
moved (clean 22.9s→22.4s, lib-edit relink 13.3s→12.4s) — wall-clock is
dominated by compiling, not linking, so this is a disk win, not a speed
win (see docs/plans/20260602-test-consolidation.md). Tests unchanged at
2151/0/1; clippy clean; no fixups needed. typing_surface_matrix stays
its own already-consolidated binary.

Tradeoff: the 25 files now share one crate (a compile error fails the
whole `it` binary; module-scoped namespaces, no clashes) — negligible
for a solo project.
2026-06-02 22:13:03 +00:00
claude@clouddev1 42f95533ac chore: bound target/ growth — incremental off, line-tables debug
target/ had reached 38 GB, dominated by a 16 GB incremental cache
(~28 compilation units × every historical config, never evicted) and
~25 separate integration-test binaries each statically embedding the
bundled engine + full debug info.

[profile.dev] (inherited by the test profile):
- incremental = false: the cache earns little in a full-suite workflow
  and never self-evicts; off, target/ stays bounded.
- debug = "line-tables-only": keeps file:line in panics/backtraces (we
  debug via tracing logs) at a fraction of debug=2's size.

Net: a clean full build dropped from 38 GB to ~1.6 GB. Document the
rationale plus the cargo-sweep workflow (the GC cargo lacks) under a
new CLAUDE.md "Build hygiene" section; also drop the now-shipped H1
from CLAUDE's deferred list (H1a remains).
2026-06-02 20:07:54 +00:00
claude@clouddev1 be7b078878 docs: mark H1 done — friendly DB-error layer is shipped
Verification found H1 (ADR-0019) fully implemented and tested: the
friendly::translate_error chokepoint is wired on the live failure path
(runtime + app + DbError::friendly_message), covers all five error
categories (UNIQUE, FOREIGN KEY both sides, NOT NULL, CHECK,
type-mismatch) with operation×kind×verbosity wording, the messages
verbosity command, and §6 row-pinpointing via runtime-resolved facts —
backed by 44 friendly unit tests + 12 full-stack friendly_enrichment
integration tests. The "partial / FK-only" notes were stale.

Mark requirements H1 done; fix the obsolete "diagnostic_table is
always None" comment in translate.rs (pinpointing landed in 431645a).
Remaining ADR-0019 scope (§9 i18n sweep, §OOS-2 advanced-SQL
sanitization, §OOS-3 messages persistence) stays deferred.
2026-06-02 20:07:45 +00:00
claude@clouddev1 56d9671488 docs: session handoff 56 — serde_norway migration clears RUSTSEC-2025-0067/0068 2026-06-02 14:34:39 +00:00
claude@clouddev1 9e2372b039 fix: migrate off unsound serde_yml to serde_norway
serde_yml (RUSTSEC-2025-0068) and its libyml backend
(RUSTSEC-2025-0067) are archived, unsound, and unmaintained with no
patched version. Swap to serde_norway, the maintained serde_yaml fork
on unsafe-libyaml-norway — a drop-in for our from_str / to_string /
Value usage across persistence, undo, and the catalog parser.

Clears both advisories (cargo audit / osv-scanner / grype all clean;
serde_yml + libyml gone from the tree). No behaviour change; full
suite 2151/0/1.
2026-06-02 14:34:34 +00:00
claude@clouddev1 c9a92c9c20 docs: session handoff 55 — #11 resolved, ADR-0041 + arboard dep 2026-06-02 14:23:26 +00:00
claude@clouddev1 d0c8f9d5d2 feat: copy the output panel to the system clipboard (#11)
New app-level `copy` / `copy all` / `copy last` command (ADR-0041).
Delivery is OSC 52 *and* a best-effort native write (arboard), always
both — OSC 52 acceptance is undetectable, so a true fallback can't be
built. Payload is the panel's plain text exactly as rendered (tags,
✓/✗, box-drawing), drift-locked to render_output_line. arboard added
--no-default-features (X11-only; OSC 52 covers Wayland).

Amends ADR-0003's command registry; requirements V6.
2026-06-02 14:23:21 +00:00
claude@clouddev1 1ea376be26 docs: session handoff 54 — #10/#14 resolved, ADR-0037 Am1 + ADR-0015 Am1
#10 (output [error]/[system] tag-colour collision) and #14 (per-project
input-mode persist & restore) closed. Two ADR amendments authored.
Records the two /runda saves on #14 (persist semantics re-decided by the
user; missing integration test added red-first) and a detailed pickup
brief for #11 (clipboard — new dependency, security review + command
surface to escalate).
2026-06-02 08:11:01 +00:00