ADR-0022 stage 8 follow-up r2: completion UX fixes from real testing

Two concrete behaviour changes from the user's second testing
round:

1. **Single vs multi commit paths.** Previously every Tab,
   even single-candidate, created a memo so Esc/Backspace could
   undo. The downside: with one candidate, repeated Tab "cycled"
   through the same item invisibly — looked stuck. Now:
   - Single candidate → insert with trailing space, no memo.
     The user can keep typing or hit Tab again to fresh-complete
     at the new cursor. (Trade-off: Esc/Backspace no longer
     whole-span undo for unique completions; the user accepted
     this for the chained-Tab fluency.)
   - Multi candidate → insert WITHOUT trailing space, create
     memo for cycling. The natural commit gesture is space —
     pressing it clears the memo and inserts the space normally,
     producing "<chosen> " ready for the next position.
   The "stuck on unique" symptom goes away, and the missing
   trailing space on multi-Tab signals "you're picking; press
   space when you're done" without needing modal affordances.

2. **Keyword candidates in grammar order.** Dropped the
   alphabetical sort in `describe_expected` in favour of
   chumsky's native source-order traversal of `or_not`/`choice`
   chains — empirically this matches the canonical command
   shape. Result: `add column ` now offers `to` before
   `table` (as `add column [to] [table] <Table>:…` reads),
   not `table` before `to` which previously suggested the
   nonsensical `add column table to ...`. Identifiers still
   alphabetised within their group; entry-keyword fallback
   for the no-prefix case stays alphabetical (no source order
   when 10 separate command branches).

Tests: 750 passing, 0 failing, 1 ignored (747 baseline →
+3 net: replaced single-candidate Esc/Backspace tests with
new multi-candidate variants; added the unique-Tab-chains-
naturally case that drove the round-2 fix; kept the
keywords-in-grammar-order test updated to assert
`to`/`table`/identifiers ordering).
This commit is contained in:
claude@clouddev1
2026-05-11 22:27:54 +00:00
parent bd1cce672d
commit f94a999e66
3 changed files with 189 additions and 109 deletions
+8 -2
View File
@@ -765,8 +765,14 @@ fn describe_expected(expected: &[RichPattern<'_, Token>]) -> Vec<String> {
})
.map(describe_pattern)
.collect();
items.sort();
items.dedup();
// Dedup preserving first occurrence (which reflects
// chumsky's traversal order — typically source order for
// `or_not` / `choice` chains). Empirically this gives a
// grammar-natural ordering: `to` before `table` in
// `add column [to] [table] …`, which alphabetical
// (table, to) would invert.
let mut seen = std::collections::HashSet::new();
items.retain(|s| seen.insert(s.clone()));
items
}