1afcf4ed29
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.
158 lines
8.1 KiB
Markdown
158 lines
8.1 KiB
Markdown
# 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".
|