feat: ADR-0035 4i(d) — merge shared-entry-word completions
In advanced mode an entry word like `create`/`drop` has several candidate nodes (the SQL forms + the DSL fallback), but the walker commits to one, so completion offered only that node's continuations — `drop ` showed just `table`, and `drop rel` dead-ended at an empty list even though the DSL drops parse via fallback. At the entry-word boundary (advanced mode), walk every candidate, keep the viable (Incomplete) ones, and union their next-keyword continuations: `drop ` → table·index·column·relationship·constraint; `drop rel` → relationship; `create ` → table·unique·index. Deeper positions keep the committed walk untouched (no change to insert/update/delete/select). Each continuation is classified by producing category (Both/Advanced/ Simple) and block-ordered Both → Advanced → Simple, so they read as contiguous groups (the foundation for the 4i(e) colour, landing next). CompletionProbe carries a parallel expected_modes; the parse path is unchanged (the merge is completion-only). Tests: completion merge + partial + block-order cases; the two tests that encoded the old single-node behaviour updated. Full suite 1911 passing / 0 failing / 1 ignored; clippy clean.
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
# Plan: ADR-0035 Phase 4, sub-phase 4i — verification sweep (completes Phase 4)
|
||||
|
||||
The closing sub-phase. Canonical scope: **ADR-0035 §13 4i**. Items:
|
||||
|
||||
- **(a)** Refresh the `CREATE TABLE` help/usage skeleton for the 4a.2
|
||||
`DEFAULT`/`CHECK`/composite-`UNIQUE`, 4a.3 table-`CHECK`, and 4b FK
|
||||
forms (the only help/usage debt — 4d/4e/4f/4g/4h carry their own).
|
||||
- **(b)** `describe` display of table-level constraints (composite
|
||||
`UNIQUE` + table `CHECK`, incl. **named** CHECKs from 4g).
|
||||
- **(c)** 4b self-ref FK pre-submit indicator: stop false-flagging a
|
||||
`references <self>` parent as unknown.
|
||||
- **(d)** shared-entry-word completion merge.
|
||||
- **(e)** visually distinguish simple- vs advanced-mode completions.
|
||||
- **staples:** typing-surface + matrix coverage, engine-neutral error
|
||||
pass, undo-parity (one step per statement).
|
||||
|
||||
**User-chosen sequencing (2026-05-26):** the **(d)/(e) design conversation
|
||||
first**, then build. (d)/(e) are designed (below); (a)/(b)/(c) + staples
|
||||
follow.
|
||||
|
||||
## 1. Baseline
|
||||
|
||||
- HEAD `ca64434`; **1909 passing / 0 failing / 0 skipped / 1 ignored**;
|
||||
clippy clean.
|
||||
|
||||
## 2. (d) + (e) — settled design (user-confirmed 2026-05-26)
|
||||
|
||||
### (d) Shared-entry-word completion merge
|
||||
|
||||
**Bug:** in advanced mode the walker's `decide()` (`walker/mod.rs`)
|
||||
commits **one** candidate node for a shared entry word, so only that
|
||||
node's continuations reach completion — `drop ` offers only `table`, and
|
||||
`drop rel` returns empty, even though the DSL drops parse via fallback.
|
||||
|
||||
**Fix:** in `completion_probe_in_mode`, for an **advanced-mode** shared
|
||||
entry word (the entry word resolves to **>1 candidate**), walk **each**
|
||||
candidate node speculatively (the existing `scratch`/`walk_one_command`
|
||||
machinery on a fresh context), extract each one's expected continuations
|
||||
(the same `WalkOutcome`→`expected` match the single-walk path uses), and
|
||||
**union** them. Simple mode is unchanged (its single DSL node already
|
||||
offers all DSL continuations; SQL isn't offered). A candidate that
|
||||
mismatches the current input contributes an empty set, so as the input
|
||||
disambiguates (`drop table …`) the union naturally narrows to the
|
||||
surviving candidate.
|
||||
|
||||
### (e) Visual simple-vs-advanced distinction
|
||||
|
||||
Each merged continuation is classified by **which categories produced
|
||||
it** — a new `ModeClass`:
|
||||
|
||||
- `Both` — produced by ≥1 `Advanced` **and** ≥1 `Simple` candidate (a
|
||||
continuation valid either way, e.g. `drop table`).
|
||||
- `Advanced` — only `Advanced` candidates (SQL-only, e.g. `create index`).
|
||||
- `Simple` — only `Simple` candidates (DSL-only, e.g. `drop relationship`).
|
||||
|
||||
**Colour + order apply only when the candidate list is *mixed*** (>1
|
||||
distinct `ModeClass`) — the only place the signal is informative; a
|
||||
single-mode list (deep inside any command) keeps today's token-kind
|
||||
colours, no mode tint (avoids redundant noise duplicating the mode
|
||||
indicator). When mixed:
|
||||
|
||||
- **Colour:** `Both` → today's token-kind colour (neutral); `Advanced` →
|
||||
`theme.mode_advanced` (orange); `Simple` → `theme.mode_simple` (cyan).
|
||||
These two mode colours already exist (used by the mode indicator).
|
||||
- **Order (user refinement):** group the continuations into contiguous
|
||||
colour **blocks** in the order **`Both` → `Advanced` → `Simple`**, so
|
||||
`Advanced` sits between the other two and each colour reads as one block
|
||||
rather than interleaving.
|
||||
|
||||
## 3. Architecture & change list (d/e)
|
||||
|
||||
- **`src/dsl/walker/outcome.rs`** (or `CompletionProbe`): add a parallel
|
||||
`expected_modes: Vec<ModeClass>` (same length/order as `expected`),
|
||||
defaulting to all `Both` (so the single-walk path is neutral). New
|
||||
`ModeClass` enum (likely in `completion.rs`, re-exported).
|
||||
- **`src/dsl/walker/mod.rs`** `completion_probe_in_mode`: factor the
|
||||
expected-extraction (lines 333-356) into a helper; add the advanced-mode
|
||||
multi-candidate branch that walks each candidate (mode `Advanced`),
|
||||
classifies each expectation by the producing category, and fills
|
||||
`expected` + `expected_modes`.
|
||||
- **`src/completion.rs`**: `Candidate` gains `mode: ModeClass`; the
|
||||
keyword-building (`Expectation::Word`) carries the parallel `ModeClass`
|
||||
through prefix filtering; when the keyword set is mixed, **block-order**
|
||||
by `ModeClass` (Both→Advanced→Simple) within the keyword group;
|
||||
non-keyword kinds and single-mode lists are all `Both`.
|
||||
- **`src/ui.rs`** `render_candidate_line` (≈907): when the candidate list
|
||||
contains >1 `ModeClass`, colour each by its `ModeClass`
|
||||
(Both=kind-colour, Advanced=`mode_advanced`, Simple=`mode_simple`);
|
||||
otherwise unchanged.
|
||||
- **Tests:** `tests/typing_surface/` — `drop ` (advanced) offers
|
||||
`table·index·column·relationship·constraint`; `drop rel` →
|
||||
`relationship`; `create ` → `table` (Both) + `index` (Advanced);
|
||||
block-order assertion (Both then Advanced then Simple); simple mode
|
||||
unchanged. A `ui.rs` snapshot for the mixed-mode coloured hint line.
|
||||
|
||||
## 4. (a)/(b)/(c) — outline (build after d/e)
|
||||
|
||||
- **(a)** Extend the `sql_create_table` help/usage strings
|
||||
(`friendly/strings/en-US.yaml`) for `DEFAULT`/`CHECK`/composite-`UNIQUE`
|
||||
(4a.2), table-`CHECK` (4a.3), and inline + table-level `FOREIGN KEY`
|
||||
(4b). Catalog-lockstep + vocab-audit guard wording.
|
||||
- **(b)** `describe` (`do_describe_table` / the structure renderer): show
|
||||
table-level composite `UNIQUE` and table `CHECK` constraints (named
|
||||
CHECKs show their name). Tier-2 snapshot + Tier-3 describe assertions.
|
||||
- **(c)** The pre-submit schema-existence diagnostic: treat a FK parent
|
||||
equal to the in-statement `CREATE TABLE` target as valid (self-ref), so
|
||||
the `[ERR]`/`[WRN]` indicator stops lying. Tier-1/typing-surface test.
|
||||
|
||||
## 5. Phase 2/3 — candidates & selection (d/e)
|
||||
|
||||
Settled via the design conversation (§2). The merge alternative
|
||||
("modify `decide`/`walk` to merge in the core parser") was **rejected** —
|
||||
it would change the shared parser used everywhere; doing the merge in the
|
||||
completion-only `completion_probe_in_mode` is lower-risk. The colour
|
||||
alternatives (always-by-mode; marker tag; defer) were presented to the
|
||||
user, who chose **mode-colour-when-mixed + block ordering**.
|
||||
|
||||
## 6. Devil's Advocate review of this plan
|
||||
|
||||
- **Forks escalated?** The (e) visual treatment was put to the user with
|
||||
four options + previews; they chose option 1 with the block-ordering
|
||||
refinement. (d)'s behaviour is ADR/handoff-specified. ✓
|
||||
- **Core-parser risk?** The merge lives in `completion_probe_in_mode`
|
||||
(completion-only), not `walk`/`decide` — the parse path is untouched, so
|
||||
no risk to execution/dispatch. ✓
|
||||
- **Simple mode unaffected?** The merge branch is advanced-only;
|
||||
simple-mode completion keeps the single-DSL-node path. A test pins it. ✓
|
||||
- **Noise?** Colour/order apply only when the list is genuinely mixed;
|
||||
single-mode lists are visually unchanged. ✓
|
||||
- **Perf?** Completion walks each candidate per keystroke — candidates per
|
||||
entry word are few (≤ ~3), and completion is already a per-keystroke
|
||||
walk; negligible. ✓
|
||||
- **Ordering vs existing kind-order?** Block-ordering applies *within* the
|
||||
keyword group (where shared-entry continuations live); the
|
||||
identifiers-first kind ordering is preserved. ✓
|
||||
|
||||
## 7. Implementation sequence (test-first)
|
||||
|
||||
1. **(d) merge** — `ModeClass` + `expected_modes`; the advanced-mode
|
||||
multi-candidate walk + union in `completion_probe_in_mode`; thread
|
||||
through `completion.rs` (functional merge, classes computed but not yet
|
||||
coloured). Typing-surface tests (merge + simple-mode-unchanged) → green.
|
||||
2. **(e) order + colour** — block-ordering when mixed; `render_candidate_line`
|
||||
colours by `ModeClass`. Ordering test + a UI snapshot → green.
|
||||
3. **(c)** self-ref FK indicator → test-first.
|
||||
4. **(b)** describe table-level constraints → snapshot/e2e.
|
||||
5. **(a)** CREATE TABLE help/usage skeleton + catalog lockstep.
|
||||
6. **Staples** — typing-surface/matrix sweep, engine-neutral error pass,
|
||||
undo-parity spot-check.
|
||||
7. **Full sweep** + finished-slice `/runda` → commit proposal(s).
|
||||
|
||||
## 8. Exit gate
|
||||
|
||||
All §13 4i items done or explicitly deferred-with-user-confirmation; all
|
||||
tiers green, zero skips; no regression from 1909; clippy clean; written-DA
|
||||
/ `/runda` PASS; ADR-0035 §13 4i + README + requirements lockstep. **4i
|
||||
completes ADR-0035 Phase 4** — flip the ADR Status from "4i pending".
|
||||
Reference in New Issue
Block a user