docs: ADR-0048 Phase 2 implemented + handoff 66
- ADR-0048: status → Phase 1 + Phase 2 implemented; D2 amendment (quoted dates, no date-literal token) and the override × UNIQUE capacity-guard decision; phasing/Status blocks marked done. - README index: 0048 entry updated (Phase 2 shipped, 2400 tests). - requirements.md: SD2 → [x] (the override-hooks core + column-fill). - handoff 66: this session's Phase 2 build + the two /runda passes.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
## Status
|
||||
|
||||
**Accepted (2026-06-11); Phase 1 implemented (2026-06-11).** Design
|
||||
**Accepted (2026-06-11); Phase 1 + Phase 2 implemented (2026-06-11).** Design
|
||||
settled with the user across an extended fork dialogue (every decision
|
||||
below was escalated and user-chosen), then hardened by a pre-build
|
||||
`/runda` Devil's-Advocate pass that found six blockers — undo
|
||||
@@ -26,11 +26,39 @@ ADR decisions (D5/D15/D16/D17 + atomicity + zero-count), all closed.
|
||||
|
||||
**Implemented in Phase 1:** the whole-row `seed <table> [count]
|
||||
[--seed <n>]` form and every D1–D18 decision *except* the two
|
||||
deferred-to-Phase-2 surfaces below. **Deferred to Phase 2** (designed
|
||||
here, not yet built): the **`set` override clause** (D2) and the
|
||||
**`<table>.<column>` column-fill** form (D1 form 2). Further SD2
|
||||
increments (custom user generators, NULL injection, multi-locale,
|
||||
recursive parent auto-seed) remain out of scope (see Out of scope).
|
||||
Phase-2 surfaces.
|
||||
|
||||
**Phase 2 implemented (2026-06-11):** both remaining surfaces — the
|
||||
**`set` override clause** (D2: fixed value / pick-list / named
|
||||
generator / range, quoted literals, type-aware) and the
|
||||
**`<table>.<column>` column-fill** form (D1 form 2: an UPDATE over
|
||||
existing rows, refusing PK/autogen targets, empty-table no-op, one undo
|
||||
step). The named-generator vocabulary (D9) lives in `src/seed`
|
||||
(`KNOWN_GENERATORS` / `generator_for_name`); a new range `Generator`
|
||||
(`src/seed/generators.rs`) backs `between`; the override clause is
|
||||
folded from the flat matched path (`build_seed_overrides`,
|
||||
`src/dsl/grammar/data.rs`) and applied to the per-column plan
|
||||
(`apply_seed_overrides`, `src/db.rs`), with column-fill in
|
||||
`do_seed_column_fill`. Full ambient wiring: completion (the generator
|
||||
vocabulary after `as`, the `set`/`.col` column slots), highlighting
|
||||
(`HighlightClass::Function` → `tok_function`, the generator slot), the
|
||||
validity indicator (`IdentSource::Generators` — an unknown name flagged
|
||||
`[ERR]`), help, and parse-error pedagogy rows. The D13 advisory now
|
||||
carries its Phase-2/3 wording (points at `set` and the column-fill
|
||||
repair). A post-implementation `/runda` pass then added one
|
||||
user-chosen refinement: a **bounded override on a UNIQUE column** (a
|
||||
fixed value / too-short pick-list) is now a **friendly error** rather
|
||||
than a silent uniqueness cap (see D2). **2400 tests pass / 0 fail / 0
|
||||
skip; clippy clean.** Two
|
||||
implementation refinements vs. this ADR's wording, both met the
|
||||
user-facing contract: dates in the range form are **quoted** (the D2
|
||||
amendment, above — no date-literal token exists); and the `set` value
|
||||
slots reuse `update`'s typed `current_column_value` (no spurious
|
||||
column-ref match) rather than the raw expression operand.
|
||||
|
||||
Further SD2 increments (custom user generators, NULL injection,
|
||||
multi-locale, recursive parent auto-seed) remain out of scope (see Out
|
||||
of scope).
|
||||
|
||||
Closes `requirements.md` **SD1** and delivers the core of **SD2**
|
||||
(per-type generators, determinism, the `fake`-backed catalogue). It
|
||||
@@ -158,15 +186,37 @@ is nothing new to learn:
|
||||
| Fixed value | `set status = 'pending'` | every row gets the constant |
|
||||
| Pick-from-list | `set role in ('admin', 'editor', 'viewer')` | uniform random choice from the list |
|
||||
| Explicit generator | `set work_addr as email` | force a named generator (D9) |
|
||||
| Range | `set price between 10 and 100` | uniform in range; **also dates** — `set signup between 2023-01-01 and 2024-12-31` |
|
||||
| Range | `set price between 10 and 100` | uniform in range; **also dates** — `set signup between '2023-01-01' and '2024-12-31'` |
|
||||
|
||||
Multiple clauses combine: `seed users 20 set role in ('admin',
|
||||
'user'), status = 'active', signup between 2023-01-01 and 2024-12-31`.
|
||||
'user'), status = 'active', signup between '2023-01-01' and
|
||||
'2024-12-31'`.
|
||||
|
||||
**Override × UNIQUE capacity (post-implementation `/runda`, user-chosen:
|
||||
"friendly error").** A *bounded* override — a fixed value, or a
|
||||
pick-list — on a **single-column-UNIQUE** target (a `UNIQUE` column or a
|
||||
single-column PK) that offers fewer **distinct** values than the row
|
||||
count cannot fill the run; rather than let the D10 uniqueness machinery
|
||||
silently cap it (e.g. `seed users 100 set email = 'x'` → 1 row), seed
|
||||
**refuses up front** with a friendly error pointing at the fixes (use a
|
||||
generator, or a longer list). Generators and ranges are treated as
|
||||
effectively unbounded sources — if one genuinely exhausts, the D14
|
||||
distinct-combination cap still applies. Compound uniqueness is exempt
|
||||
(the *other* key columns can still vary).
|
||||
|
||||
**Quoting (fork, user-chosen: "quoted, grammar-consistent").** Text
|
||||
values and list items are **quoted string literals** (`'admin'`),
|
||||
exactly as everywhere else in the DSL — numbers and dates stay
|
||||
unquoted. This reuses the ADR-0026 expression grammar **unchanged**:
|
||||
exactly as everywhere else in the DSL — only **numbers** stay
|
||||
unquoted. **Amendment (2026-06-11, Phase 2 build):** the original
|
||||
wording said "numbers *and dates* stay unquoted", but this DSL has
|
||||
**no date-literal token** — `Value` is `Number`/`Text` only, and a
|
||||
date is a **quoted string** validated by `bind_date` (`'2023-01-01'`)
|
||||
everywhere else (insert / update / `where`). An unquoted `2023-01-01`
|
||||
lexes as `2023`,`-`,`01`,… and cannot parse. So **dates in the range
|
||||
form are quoted** (`between '2023-01-01' and '2024-12-31'`) — which is
|
||||
in fact *more* faithful to this decision's own "quoted,
|
||||
grammar-consistent" principle. Numbers remain unquoted (`NumberLit`).
|
||||
This reuses the ADR-0026 expression grammar **unchanged**:
|
||||
the DA pass confirmed that the `in (...)` form's operands are typed
|
||||
value slots, so a *bare* `admin` would parse as a **column reference**
|
||||
(→ "unknown column"), not a string. Quoting is therefore not a style
|
||||
@@ -521,23 +571,26 @@ ADR-0045 showed "claimed verified" is not verified):
|
||||
Design is whole; the **implementation** is phased into reviewable,
|
||||
test-first commits:
|
||||
|
||||
1. **Core whole-row seed** — grammar/AST/executor; type-based
|
||||
generation + the `fake`-backed name heuristics (D7/D8/D11);
|
||||
identifier uniqueness (D10) + constraint uniqueness; FK sampling
|
||||
(joint tuples) + empty-parent error + junction distinct-combos
|
||||
(D14); `--seed` determinism (D4); default count + cap + zero-no-op
|
||||
(D6/D1); required-column block guard (D1); **undo batch (D15)**;
|
||||
**replay-as-data-write classification (D16)**; **CHECK derive /
|
||||
friendly-fail (D17)**; **capped auto-show (D18)**; the enum/CHECK
|
||||
advisory in its **Phase-1 wording** (D12/D13); full ambient wiring;
|
||||
both modes.
|
||||
2. **The `set` override clause** (D2) — value / list / generator /
|
||||
range, type-aware, with completion + highlight + validity for the
|
||||
generator-name slot.
|
||||
3. **Column-fill mode** (`seed <table>.<column>`, D1 form 2) — the
|
||||
UPDATE path.
|
||||
1. **Core whole-row seed** *(done, Phase 1)* — grammar/AST/executor;
|
||||
type-based generation + the `fake`-backed name heuristics
|
||||
(D7/D8/D11); identifier uniqueness (D10) + constraint uniqueness; FK
|
||||
sampling (joint tuples) + empty-parent error + junction
|
||||
distinct-combos (D14); `--seed` determinism (D4); default count + cap
|
||||
+ zero-no-op (D6/D1); required-column block guard (D1); **undo batch
|
||||
(D15)**; **replay-as-data-write classification (D16)**; **CHECK
|
||||
derive / friendly-fail (D17)**; **capped auto-show (D18)**; the
|
||||
enum/CHECK advisory in its **Phase-1 wording** (D12/D13); full
|
||||
ambient wiring; both modes.
|
||||
2. **The `set` override clause** (D2) *(done, Phase 2)* — value / list /
|
||||
generator / range, type-aware, with completion + highlight +
|
||||
validity for the generator-name slot.
|
||||
3. **Column-fill mode** (`seed <table>.<column>`, D1 form 2) *(done,
|
||||
Phase 2)* — the UPDATE path.
|
||||
|
||||
Each phase is independently green before the next.
|
||||
Each phase is independently green before the next. (Phases 2 and 3
|
||||
landed together — they share the `set`-override executor machinery, so
|
||||
splitting them risked a state where `set` parsed but column-fill
|
||||
silently no-op'd.)
|
||||
|
||||
## Testing (ADR-0008 tiers 1–3; test-first)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user