feat(seed): set override clause + column-fill (ADR-0048 Phase 2)

Build the two SD2 surfaces Phase 1 deferred:

- `set` override clause (D2): comma-separated per-column pins —
  `= 'v'` (fixed), `in ('a','b')` (pick-list), `as <generator>`
  (named), `between x and y` (range; numeric and quoted dates).
  Type-aware via the typed `current_column_value` slot; an override
  drops its column from the generic-fill advisory (D13). Folded from
  the flat matched path (build_seed_overrides) and applied to the
  per-column plan (apply_seed_overrides).
- `<table>.<column>` column-fill (D1 form 2): an UPDATE over existing
  rows. Refuses PK/autogen targets, empty-table no-op, FK-samples the
  parent, collision-free for UNIQUE/identifier targets, one undo step;
  `set` may only adjust the filled column.

Supporting work: KNOWN_GENERATORS vocabulary + generator_for_name
(src/seed/vocabulary.rs, D9); a range Generator + range_bounds_reason;
IdentSource::Generators and HighlightClass::Function; completion of the
generator vocabulary after `as` and the set/.col column slots; the
typing-time validity indicator for an unknown generator; help,
parse-error pedagogy rows, and the D13 advisory's Phase-2/3 wording.

A bounded override (fixed value / too-short pick-list) on a
single-column-UNIQUE target is a friendly error rather than a silent
uniqueness cap (post-implementation /runda finding, user-chosen).

Dates in the range form are quoted (no date-literal token exists);
ADR-0048 D2 amended accordingly. Both modes (D5); reproducible (D4).
This commit is contained in:
claude@clouddev1
2026-06-12 09:44:30 +00:00
parent 78c38e8b33
commit a12facc784
20 changed files with 1913 additions and 65 deletions
+28
View File
@@ -477,4 +477,32 @@ fn seed_completion_and_validity() {
flag_cands.iter().any(|c| c.contains("seed")),
"`--seed` should be offered as a candidate, got {flag_cands:?}"
);
// Phase 2 (ADR-0048 D2): the `set` clause is offered after the count.
assert!(
flag_cands.iter().any(|c| c == "set"),
"`set` should be offered after the count, got {flag_cands:?}"
);
// `set ` offers the active table's columns (narrowed to Customers).
let set_cands = completion_candidate_texts(&assess_at_end("seed Customers set ", &schema));
assert!(
set_cands.iter().any(|c| c == "Name") && set_cands.iter().any(|c| c == "Email"),
"`set ` should complete this table's columns, got {set_cands:?}"
);
// `set <col> as ` offers the curated generator vocabulary (D9).
let gen_cands =
completion_candidate_texts(&assess_at_end("seed Customers set Email as ", &schema));
assert!(
gen_cands.iter().any(|c| c == "email") && gen_cands.iter().any(|c| c == "product"),
"`as ` should complete generator names, got {gen_cands:?}"
);
// Column-fill (D1 form 2): `seed Customers.` offers the columns.
let fill_cands = completion_candidate_texts(&assess_at_end("seed Customers.", &schema));
assert!(
fill_cands.iter().any(|c| c == "Name"),
"`seed Customers.` should complete column names, got {fill_cands:?}"
);
}