From 5fa3460ff60ab39ff84b19a76c71b1ed6b074c7c Mon Sep 17 00:00:00 2001 From: "claude@clouddev1" Date: Fri, 15 May 2026 22:48:09 +0000 Subject: [PATCH] =?UTF-8?q?add=20handoff-14:=20handoff-12=20=C2=A72=20back?= =?UTF-8?q?log=20cleared=20(8=20items)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/handoff/20260515-handoff-14.md | 243 ++++++++++++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 docs/handoff/20260515-handoff-14.md diff --git a/docs/handoff/20260515-handoff-14.md b/docs/handoff/20260515-handoff-14.md new file mode 100644 index 0000000..8f4247c --- /dev/null +++ b/docs/handoff/20260515-handoff-14.md @@ -0,0 +1,243 @@ +# 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` 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` — 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`. +- `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 +`); a failing cell with *wrong* behaviour → the cell +earned its keep. The Form C type-awareness work this session +was guarded entirely by it.