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:
@@ -0,0 +1,145 @@
|
||||
# Session handoff — 2026-06-11 (66)
|
||||
|
||||
Sixty-sixth handover. Continues from handoff-65 (ADR-0048 `seed`
|
||||
Phase 1). This session built **ADR-0048 Phase 2** end to end: the
|
||||
**`set` override clause** (D2) and the **`<table>.<column>`
|
||||
column-fill** form (D1 form 2) — the two surfaces Phase 1 deliberately
|
||||
deferred. Designed-then-DA-vetted (a `/runda` pass that caught a real
|
||||
ADR-vs-grammar conflict), then built test-first.
|
||||
|
||||
## §1. State at handoff
|
||||
|
||||
**Branch:** `main`. All Phase-2 work is in the working tree;
|
||||
**commits are pending the user's approval** (see §6). Unpushed is the
|
||||
normal working state.
|
||||
|
||||
**Tests: 2400 passing / 0 failing / 0 skipped / 1 ignored** (the
|
||||
long-standing `friendly` doctest). **Clippy clean** (nursery, all
|
||||
targets). +42 over handoff-65's 2358.
|
||||
|
||||
## §2. What landed (read ADR-0048 — Status + D1/D2/D9/D13)
|
||||
|
||||
`seed <T>[.<col>] [count] [set <overrides>] [--seed <n>]`.
|
||||
|
||||
- **`set` override clause (D2):** four forms, comma-separated —
|
||||
`status = 'active'` (fixed), `role in ('a','b')` (pick-list),
|
||||
`work_addr as email` (named generator), `price between 10 and 100`
|
||||
(range; numeric **and quoted dates**). Type-aware; an override
|
||||
**drops its column from the generic-fill advisory** (D13). Value
|
||||
slots reuse `update`'s typed `current_column_value` (quoting
|
||||
enforced structurally — a bare word is rejected).
|
||||
- **Column-fill (D1 form 2):** `seed users.email [set …]` fills one
|
||||
column across **existing** rows (an UPDATE). Refuses PK / autogen
|
||||
(`serial`/`shortid`/`blob`) targets; **empty table → friendly
|
||||
no-op**; FK target samples the parent; UNIQUE/identifier target gets
|
||||
collision-free values; **one undo step**; `set` may only adjust the
|
||||
filled column; a row count is refused.
|
||||
- **Named-generator vocabulary (D9):** `src/seed/vocabulary.rs` —
|
||||
`KNOWN_GENERATORS` + `generator_for_name` + `is_known_generator_prefix`,
|
||||
the single source of truth for completion, validity, and the executor.
|
||||
- **Range generator:** `Generator::Range { low, high }` in
|
||||
`src/seed/generators.rs`, interpreted per destination type;
|
||||
`range_bounds_reason` validates compatibility before generation.
|
||||
- **Ambient wiring:** completion (generator names after `as`, the
|
||||
`set <col>` and `.col` column slots, the `set` keyword); highlight
|
||||
(new `HighlightClass::Function` → existing `tok_function`); validity
|
||||
(new `IdentSource::Generators` — unknown generator flagged `[ERR]`;
|
||||
unknown column in `set`/`.col` flagged via the existing Columns
|
||||
path); help (`help.data.seed`); parse-error pedagogy near-miss rows;
|
||||
the D13 advisory's **Phase-2/3 wording** (points at `set` and the
|
||||
column-fill repair). Both modes (D5).
|
||||
|
||||
## §3. The ADR amendment (a real DA find)
|
||||
|
||||
The pre-build `/runda` pass found that **ADR-0048 D2's "dates stay
|
||||
unquoted" was impossible** — this DSL has **no date-literal token**
|
||||
(`Value` is `Number`/`Text`; dates are quoted strings validated by
|
||||
`bind_date`). Escalated to the user, who chose **quoted dates +
|
||||
amend the ADR** (the grammar-consistent option). D2 now carries a
|
||||
dated amendment; the range form uses `between '2023-01-01' and
|
||||
'2024-12-31'`. This was the only divergence from the ADR text; numbers
|
||||
remain unquoted.
|
||||
|
||||
## §4. Where the code lives
|
||||
|
||||
- **`src/dsl/command.rs`** — `Command::Seed` gains `target_column:
|
||||
Option<String>` + `overrides: Vec<SeedOverride>`; new `SeedOverride`
|
||||
/ `SeedOverrideKind`.
|
||||
- **`src/dsl/grammar/data.rs`** — `SEED_SET_CLAUSE` + `SEED_DOT_COLUMN`
|
||||
grammar; `SEED_GENERATOR` slot (`IdentSource::Generators`,
|
||||
`HighlightClass::Function`); `build_seed` + the override fold
|
||||
(`build_seed_overrides` / `parse_seed_override_tail`).
|
||||
- **`src/dsl/grammar/mod.rs`** — `IdentSource::Generators` +
|
||||
`HighlightClass::Function`.
|
||||
- **`src/db.rs`** — `apply_seed_overrides` / `seed_override_plan` /
|
||||
`seed_override_literal`; `do_seed_column_fill`; `do_seed` +
|
||||
`Database::seed` + worker wiring threaded with the new params.
|
||||
- **`src/seed/`** — `vocabulary.rs` (new); `generators.rs` (range
|
||||
generator + `range_bounds_reason`); `mod.rs` (`Generator::Range`).
|
||||
- **`src/completion.rs`** — generator candidates after `as`; generator
|
||||
validity. **`src/input_render.rs`** — `"generator"` invalid-ident
|
||||
kind. **`src/theme.rs`** — `Function → tok_function`.
|
||||
- **Catalog** — `help.data.seed`, `parse.usage.seed`,
|
||||
`seed.advisory_generic` (Phase-2/3 wording) in `en-US.yaml`;
|
||||
`keys.rs` placeholders updated.
|
||||
- **Tests** — `tests/it/seed.rs` (+~30: builder fold, executor
|
||||
set/column-fill, undo, advanced mode), `src/seed/{vocabulary,
|
||||
generators}.rs` (range + vocabulary units), `src/completion.rs`
|
||||
(generator + column validity), `src/dsl/walker/highlight.rs`,
|
||||
`tests/typing_surface/mod.rs` (completion slots),
|
||||
`tests/it/parse_error_pedagogy.rs` (near-miss rows).
|
||||
|
||||
## §5. Two implementation refinements vs. the ADR (both met the contract)
|
||||
|
||||
- **Quoted dates** (the D2 amendment, §3).
|
||||
- **Value slots reuse `current_column_value`** (the `update … set`
|
||||
typed slot) rather than the raw ADR-0026 expression operand — no
|
||||
spurious column-ref match, typed narrowing, consistent with
|
||||
`update`. The user-facing contract (quoted literals, type-aware) is
|
||||
fully met.
|
||||
|
||||
The `seed_take_value` / `seed_set_error` builder paths are
|
||||
drift-guards (the typed slots only ever match value literals, so a bare
|
||||
word is rejected at the grammar level) — they use the generic
|
||||
`parse.error_wrapper`, mirroring `expr::build_expr`.
|
||||
|
||||
## §6. How to take over / next steps
|
||||
|
||||
1. Read handoffs 64 → 65 → 66, `CLAUDE.md`, `docs/requirements.md`,
|
||||
`docs/adr/0048-…md` (Status block + D1/D2/D9/D13 + the amendment).
|
||||
2. **Seed is feature-complete (SD1 + SD2).** `requirements.md`: **SD1
|
||||
`[x]`, SD2 `[x]`**. The only open A1 gap is `hint`/**H2** (own ADR).
|
||||
3. **Commits pending approval.** Suggested split:
|
||||
- `feat(seed): set override clause + column-fill (ADR-0048 Phase 2)`
|
||||
— all `src/` + `tests/` changes.
|
||||
- `docs: ADR-0048 Phase 2 implemented + handoff 66` — ADR / README /
|
||||
requirements / this file.
|
||||
4. Next options (user's call): **H2 `hint`** (closes A1); **TT5 CI**;
|
||||
the larger **V4 journal** / **tutorial** ADRs; or Tier-4 PTY (TT4).
|
||||
5. Consider a `cargo sweep` at this milestone (`target/` grows).
|
||||
|
||||
## §7. Post-implementation `/runda` pass (done this session)
|
||||
|
||||
A DA pass over the completed code found **no correctness bugs and no
|
||||
dropped requirements**; all D1–D18 acceptance criteria verified met,
|
||||
tests confirmed to catch regressions. One **design fork** was surfaced
|
||||
and **resolved by the user**:
|
||||
|
||||
- **Bounded override × UNIQUE column** — a fixed value / too-short
|
||||
pick-list on a single-column-UNIQUE target used to silently cap the
|
||||
run (e.g. `seed users 100 set email = 'x'` → 1 row). Now a **friendly
|
||||
error** up front (`seed_override_capacity_guard`, `src/db.rs`), for
|
||||
both whole-row and column-fill; generators/ranges stay cap-based
|
||||
(unbounded sources). ADR-0048 D2 documents it; two tests pin it.
|
||||
|
||||
Remaining **non-blocking** edges (noted, not bugs):
|
||||
|
||||
- Overriding an **FK column** with a literal: the override wins (D2); a
|
||||
non-parent value fails safely through the FK-error layer.
|
||||
- **Column-fill of one column of a *compound* FK** samples that column
|
||||
independently → an invalid tuple fails safely (UPDATE rejected,
|
||||
rollback), never corrupts. Single-column FKs / non-FK columns are
|
||||
exact.
|
||||
- The generator slot uses the **default candidate-ladder hint** (offers
|
||||
the vocabulary), not a dedicated prose intro — discoverability is met
|
||||
by completion; a prose intro is optional polish.
|
||||
Reference in New Issue
Block a user