30b2677bf3
- 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.
146 lines
7.4 KiB
Markdown
146 lines
7.4 KiB
Markdown
# 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.
|