Files
rdbms-playground/docs/handoff/20260515-handoff-14.md
T
2026-05-15 22:48:09 +00:00

244 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Session handoff — 2026-05-15 (14)
Fourteenth handover. This session cleared the remaining
handoff-12 backlog: every §2.1 carry-forward and the §2.2
deferred items. Eight focused commits, each a deliberate
decision the user signed off on.
**Headline: the handoff-12 §2 catalogue is now empty of
actionable items.** What remains are two flagged observations
(§3) the user should rule on, plus the standing ADR roadmap.
## State at handoff
**Branch:** `main`. Working tree clean. `origin/main` is at
`42cf851` (handoff-13); local HEAD is **8 commits ahead** — this
session's work, unpushed (the user pushes asynchronously).
Commits since handoff-13:
```
50b7825 Remove dead parse.token.* catalog entries
bcc5ad2 Matrix: pin natural candidate ordering
f1ff597 Hint: pedagogical Form-A pointer at Form B's first value slot
911a537 Walker: node-attached HintMode via Node::Hinted
9bbb96e Walker: memoize DynamicSubgrammar resolution to bound the Box::leak
90e3f5d Insert grammar: Form C type-awareness via lookahead
f46606b Runtime: schema-aware replay parsing
03dd900 Help: consume CommandNode.help_id — REGISTRY-driven in-app help
```
**Tests:** **1006 passing, 0 failing, 1 ignored** (up from 989).
The ignored test is the long-standing `` ```ignore `` doc-test
in `src/friendly/mod.rs`.
**Clippy:** clean with `nursery` lints + `-D warnings`.
## §1. What shipped — handoff-12 backlog cleared
### Dead `parse.token.*` catalog entries removed (50b7825)
The 5 structural-class + 3 lex-error entries handoff-12 §2.1
listed as unreachable are gone (catalog YAML + `keys.rs`).
### Ranker / natural candidate ordering (bcc5ad2)
The user's actual ranker need — `to` before `table` so
`add column to table T` reads in order; keywords before schema
identifiers — **already worked** via declaration-order
preservation + keywords-first sectioning in
`candidates_at_cursor`. Nothing pinned it; 8 matrix tests in
`tests/typing_surface/candidate_ordering.rs` now do. See §3 for
the `Ranker` *type* itself.
### serial/shortid pedagogical Form-A hint (f1ff597)
handoff-12 §2.2: at the first value slot of `insert into T
values (…)` for a table with auto-generated columns, the hint
now appends "(`id` auto-generated — skipped here; list columns
explicitly … to set it)". `hint_resolution_at_input` derives
the skipped columns from the post-walk `WalkContext` (Form B =
no `user_listed_columns` + table has serial/shortid columns);
the note fires only at the first slot. New
`HintResolution::form_b_autogen_skipped`, catalog key
`hint.value_slot_autogen_skipped`.
### Node-attached HintMode (911a537)
handoff-12 §2.1: the hint resolver's signature-matching (does
the expected set contain all five literal forms? an
`Ident{NewName}`?) is replaced by a grammar-declared
annotation. New `Node::Hinted { mode, inner }` wrapper; the
walker records the mode in `WalkContext::pending_hint_mode` on
entry and clears it on **any successful match** (the cursor
moved past the slot — this also undoes the leak where a failed
`Hinted` branch of a `Choice` would strand a stale mode). The
resolver reads `pending_hint_mode` directly.
Mechanism note: handoff-12 sketched threading `HintMode` through
the `Expectation` enum. ADR-0024 §HintMode only says "nodes
carry `HintMode`, the walker propagates it" — mechanism-
agnostic. The `WalkContext::pending_hint_mode` route (mirroring
the existing `pending_value_type`) was chosen as lower-risk; the
user was told and did not object.
### DynamicSubgrammar memoization (9bbb96e)
handoff-12 §2.1's `Box::leak`-per-walk. The handoff's arena
sketch was unworkable (it needs a lifetime-generic `Node` — a
major refactor). Instead `resolve_dynamic` memoizes factory
output on the schema state the factory reads (keyed by factory
fn-pointer + ctx fields). Each distinct value-list shape leaks
**once** — total leak bounded by distinct (schema × form)
combinations, not keystroke count. `TableColumn` gained `Hash`.
### Form C type-awareness (90e3f5d)
handoff-12 §2.2. Form C (`insert into T (vals)`) shared the `(`
opener with Form A, so its values weren't typed. The
explicit-`Choice`-branch split is impossible (committed-choice
semantics commit after `(` matches), so a new
`Node::Lookahead(fn(&WalkContext, &str, usize) -> Node)`
variant peeks the source: a value-literal first token routes
the paren through the typed `column_value_list` (Form B
dispatch contract); an identifier or empty paren routes to a
Form A column-name list. Form C values are now type- and
count-checked at parse time. `insert into T (` cleanly shows
Form A column candidates instead of mixed Form-A/C suggestions.
### Schema-aware replay (f46606b)
handoff-12 §2.1: `run_replay` parsed schemalessly. It now
re-snapshots the schema per line (extracted `build_schema_cache`,
shared with the interactive path) and parses with
`parse_command_with_schema` — typed-slot rejections fire at
replay parse time, matching interactive. New integration test
`replay_rejects_typed_slot_violation_at_parse_time`.
### help_id consumption (03dd900)
handoff-12 §2.1: every `CommandNode` declared an unused
`help_id`. `note_help` now iterates the command `REGISTRY` and
translates each `help_id` — a new command appears in `help`
automatically. 20 per-command catalog entries + 3 framing
entries; `help.in_app_body` removed. `CommandNode.help_id` lost
its `#[allow(dead_code)]`.
## §2. Bug found this session
**`libyml` 0.0.5 scanner panic on long space runs in
double-quoted YAML scalars.** While authoring the help entries,
a space-aligned double-quoted catalog string
(`"quit — exit"`) panicked the YAML scanner with
"String join would overflow memory bounds". Block scalars
(`|-`) are unaffected — that's why the old block-scalar help
worked. Bisected and worked around: all per-command help
entries use `|-`. **If you author new catalog entries, avoid
long internal space runs in double-quoted (`"…"`) values — use
a block scalar or keep runs short.** A catalog comment in
`en-US.yaml` records this.
## §3. CRITICAL: two flagged items needing a user decision
**3.1 The `Ranker` type is vestigial.** `completion::Ranker` /
`candidates_at_cursor_with` have no production caller passing a
non-identity ranker. The user's stated ranker need (candidate
ordering) is met by declaration-order preservation, not the
ranker layer. So `Ranker`, `identity_ranker`, and the
`candidates_at_cursor_with` variant are unused scaffolding. Per
CLAUDE.md "don't remove without confirmation" they were left
in. **Decide: remove them, or keep for a future frequency-
ranking feature?** (handoff-12 §2.1 listed the ranker as
"scaffolding-only … future work" — this is the same item, now
confirmed genuinely unused.)
**3.2 `CommandNode.hint_mode` is now genuinely dead.** The
per-command `hint_mode: Option<HintMode>` field predates the
node-attached HintMode work; HintMode is now per-*node*
(`Node::Hinted`), never per-command. The field is still
`#[allow(dead_code)]` and read by nothing. Removing it is a
safe mechanical edit across the 20 `CommandNode` declarations.
**Decide: remove it, or keep?** Not done this session (20-site
edit, separate from the HintMode mechanism change).
## §4. Open items — standing roadmap (unchanged)
handoff-12 §2's actionable backlog is cleared. What remains is
the ADR roadmap in `CLAUDE.md` "Things deliberately deferred"
(complex WHERE expressions, SQL advanced mode, indexes, m:n
convenience, snapshot/replay/undo, tutorial system, etc.) and
handoff-13's two accepted items:
- **Partial entry words classify as `DefiniteErrorAt`**
(handoff-13 §3) — the user accepted this; the matrix test
`app_commands::partial_entry_word_classifies_as_definite_error_but_completes`
documents it.
- **Matrix scope** (handoff-13 §4) — cursor coverage is
"meaningful transitions" not every byte offset; assertion (5)
is parse-layer not a live dispatch differential. User
accepted both.
## §5. Architectural delta (vs. handoff-13)
### New `Node` variants
- `Node::Hinted { mode: HintMode, inner: &'static Node }` —
node-attached hint-mode annotation.
- `Node::Lookahead(fn(&WalkContext, &str, usize) -> Node)` —
source-aware dynamic subgrammar (Form A/C discrimination).
### New `WalkContext` field
- `pending_hint_mode: Option<HintMode>` — set on `Hinted`
entry, cleared on any match.
### Walker driver
- `walk_node` split into a wrapper (clears `pending_hint_mode`
on match) + `walk_node_inner` (the dispatch).
- `resolve_dynamic` + `DYNAMIC_CACHE` — memoized
`DynamicSubgrammar` resolution.
- `Node::Lookahead` arm — not memoized (source-dependent),
returns a small node.
### New API surface
- `input_render::classify_input_with_schema` (added handoff-13,
noted here for completeness).
- `HintResolution::form_b_autogen_skipped: Vec<String>`.
- `runtime::build_schema_cache` (extracted from
`refresh_schema_cache`).
### Catalog
- Removed: `parse.token.*` (×8), `help.in_app_body`.
- Added: `hint.value_slot_autogen_skipped`,
`parse.custom.insert_form_a_missing_values` (handoff-13),
`help.intro` / `help.dsl_section` / `help.types_reference`,
`help.{app,ddl,data}.*` (×20).
## §6. How to take over
1. **Read this file, then handoff-13, then 12** for the chain.
2. **Read `CLAUDE.md`** — the working-style rules. This session
escalated every ambiguous fork (HintMode mechanism, the
`Box::leak` arena's true cost, the Form C restructure twice)
rather than deciding unilaterally.
3. **Run `cargo test`** — 1006 passing, 0 failing, 1 ignored.
4. **Run `cargo clippy --all-targets -- -D warnings`** — clean.
5. **Resolve §3** — the two flagged dead-code items — with the
user.
6. Then the standing ADR roadmap (§4) is the next structural
work; pick per the user's priorities.
### Note on the typing-surface matrix
`tests/typing_surface/` (now 144 cells) is the regression net
for everything walker/hint/completion. After any grammar or
walker change: a failing matrix cell with *correct* new
behaviour → update its snapshot
(`INSTA_UPDATE=always cargo test --test typing_surface_matrix
<family>`); a failing cell with *wrong* behaviour → the cell
earned its keep. The Form C type-awareness work this session
was guarded entirely by it.