Handoff doc for end of 2026-05-09 (#6)
Documents this session's work and the recommended next move:
## Session totals
- 11 commits since handoff-5
- 534 → 610 tests passing (+76)
- Release binary 7.2 → 7.8 MB
## What landed
- All four non-CI items from handoff-5's Independent Work
list: B2 (int→bool tests), B1 (help update), A2 (engine-
vocabulary audit), A3 (replay command)
- ADR-0019 fully implemented end-to-end:
- Friendly-error layer + i18n catalog (~170 entries
across 16 categories)
- §6 runtime row-pinpoint enrichment with
schema-resolved facts
- §9 migration sweep — every user-visible literal in
src/ now flows through the catalog (caught a ui.rs
gap during the post-sweep manual sanity check, folded
it in as sweep 3/3)
## Recommended next move
Parser-as-source-of-truth ADR + H1a implementation. The
friendly-error layer made engine errors much better;
parse-error wording is now the visibly-weakest user
surface. User explicitly surfaced the gap during manual
testing this session ("typing `create` should illustrate
the expectation"). Bounded scope, high pedagogical value,
unblocks I3/I4 in passing.
A1 (CI workflow) noted as the easy alternative for a
quick win first.
## Sharp edges captured
- New i18n workflow: catalog + keys.rs + t!() at every
use site, validator catches drift
- TranslateContext is owned (no lifetime); App combines
runtime FailureContext with verbosity
- Anchor phrases load-bearing per ADR-0019 §10
- `running: ` prefix coupled to caret-padding math
- main.rs initialises catalog before args parsing
- Several alignment-coupled strings deliberately left out
of the catalog (echo prefix tags, mode labels)
This commit is contained in:
@@ -0,0 +1,592 @@
|
||||
# Session handoff — 2026-05-09 (6)
|
||||
|
||||
Sixth handover. The previous session (handoff-5) shipped
|
||||
ADR-0017, ADR-0018, the parser tiny-win, and the cleanup
|
||||
queue. This session worked through every item on
|
||||
handoff-5's "Independent work" list (B2, B1, A2, A3 — A1
|
||||
deferred at user request), then designed and **fully
|
||||
implemented ADR-0019** (friendly error layer + i18n
|
||||
catalog), including the schema-aware row-pinpoint enrichment
|
||||
and the catalog migration sweep. The next agent picks up a
|
||||
clean baseline with only one substantial recommended next
|
||||
move.
|
||||
|
||||
## State at handoff
|
||||
|
||||
**Branch:** `main`. Working tree clean. **1 commit ahead of
|
||||
`origin/main`** (just the latest §9 sweep — earlier commits
|
||||
were pushed between turns). Push remains the user's call.
|
||||
|
||||
Commits since handoff-5:
|
||||
|
||||
```
|
||||
a6fd26d ADR-0019 §9 sweep (3/3): ui.rs prose strings (caught in
|
||||
manual sanity)
|
||||
720511e ADR-0019 §9 sweep (2/2): help blocks + modals + system notes
|
||||
aff528a ADR-0019 §9 sweep (1/2): replay/client_side/ok/mode/
|
||||
messages/project/parse
|
||||
431645a ADR-0019 §6: runtime enrichment + row pinpointing
|
||||
eac7e5b ADR-0019 implementation: friendly error layer + i18n catalog
|
||||
d4801ea ADR-0019: pluralisation is a translator concern, not
|
||||
deferred work
|
||||
2a8618c ADR-0019: friendly error layer (H1) and i18n message catalog
|
||||
c4ee264 replay: new `replay <path>` command (A3, U4)
|
||||
b8102dc tests: ADR-0002 engine-vocabulary audit (A2)
|
||||
3dbaedc help: surface ADR-0017/0018 auto-fill semantics (B1)
|
||||
0d7a7bc db: end-to-end tests for change_column int -> bool (B2)
|
||||
```
|
||||
|
||||
**Tests:** **610 passing, 0 failing, 1 ignored** (up from
|
||||
534 at handoff-5's baseline; +76 over this session).
|
||||
The ignored test is unchanged from handoff-5 — not new
|
||||
debt. Per-phase counts:
|
||||
|
||||
- B2 (int→bool tests): +2 (534 → 536)
|
||||
- B1 (help text test): +1 (536 → 537)
|
||||
- A2 (engine-vocabulary audit): +4 (537 → 541)
|
||||
- A3 (replay command): +20 (541 → 561)
|
||||
- ADR-0019 H1 implementation: +39 (561 → 600)
|
||||
- §6 runtime enrichment: +8 integration tests + 2 fixups
|
||||
(600 → 610)
|
||||
- §9 migration sweep: 0 net (pure refactor)
|
||||
|
||||
**Clippy:** clean with `nursery` lints enabled.
|
||||
|
||||
**Release build:** ~7.8 MB single binary (up ~600 KB from
|
||||
handoff-5's 7.2 MB; the increase is the friendly module +
|
||||
serde_yml + the embedded en-US catalog).
|
||||
|
||||
## What's implemented (delta vs. handoff-5)
|
||||
|
||||
### Independent work from handoff-5 §"Independent work"
|
||||
|
||||
All four non-CI items shipped:
|
||||
|
||||
- **B2** — End-to-end tests for `change column int → bool`
|
||||
(the `(Int, Bool)` matrix entry at the db.rs level, not
|
||||
just the per-cell unit tests).
|
||||
- **B1** — In-app `help` updated to surface ADR-0017's flag
|
||||
semantics and ADR-0018's auto-fill behaviour. New
|
||||
regression test pins the wording so future help-text
|
||||
edits can't silently drop the pedagogical lines.
|
||||
- **A2** — ADR-0002 engine-vocabulary audit confirmed the
|
||||
codebase is already clean (no `SQLite` / `STRICT` /
|
||||
`PRAGMA` / `rusqlite` in user-reachable strings).
|
||||
`tests/engine_vocabulary_audit.rs` pins this so a
|
||||
regression fails loudly.
|
||||
- **A3** — New `replay <path>` DSL command. Parser
|
||||
grammar, `Action::Replay`, runtime `run_replay`,
|
||||
per-line failure reporting, file-relative-to-project
|
||||
resolution, nested-replay refusal, history.log
|
||||
invariant (sub-commands persisted but the replay
|
||||
invocation itself is not). 9 integration tests.
|
||||
|
||||
**A1 (CI workflow) remains open** — explicitly postponed
|
||||
at the start of this session.
|
||||
|
||||
### ADR-0019 (friendly error layer + i18n) — **fully implemented**
|
||||
|
||||
The session's biggest piece. Started as a deferred handoff-5
|
||||
"pending work" item; now the entire ADR is shipped, including
|
||||
the originally-deferred §6 (row pinpointing) and §9
|
||||
(migration sweep).
|
||||
|
||||
What the ADR provides:
|
||||
|
||||
- **Single chokepoint for user-visible message wording.**
|
||||
Every literal that reaches the user goes through the i18n
|
||||
catalog (`src/friendly/strings/en-US.yaml`) via the
|
||||
`t!()` macro. ~170 entries across 16 categories
|
||||
(`error.*`, `client_side.*`, `replay.*`, `ok.*`,
|
||||
`mode.*`, `messages.*`, `project.*`, `parse.*`,
|
||||
`help.*`, `dsl.*`, `advanced_mode.*`, `fatal.*`,
|
||||
`modal.*`, `save.*`, `status.*`, `panel.*`,
|
||||
`shortcut.*`).
|
||||
|
||||
- **`friendly` module** owns the structured translator:
|
||||
- `format.rs` — catalog loader (YAML embedded via
|
||||
`include_str!` + `serde_yml`), `{name}` substitution
|
||||
rejecting format specifiers per ADR-0019 §8.4.
|
||||
- `keys.rs` — the canonical
|
||||
`KEYS_AND_PLACEHOLDERS` list every translation site
|
||||
references; a unit test validates every key exists,
|
||||
placeholders match, no specifiers, no engine
|
||||
vocabulary, no orphan YAML entries.
|
||||
- `error.rs` — `FriendlyError { headline, hint,
|
||||
diagnostic_table }` payload + renderer composing the
|
||||
three blocks per ADR-0019 §7.
|
||||
- `translate.rs` — `translate(&DbError, &TranslateContext)
|
||||
→ FriendlyError` classifies UNIQUE / FK / NOT NULL /
|
||||
CHECK / type-mismatch / not_found / already_exists /
|
||||
generic / invalid_value with operation-tailored
|
||||
wording per §4. Verbose vs short via the `Verbosity`
|
||||
enum.
|
||||
|
||||
- **Runtime-side row pinpoint + schema enrichment**
|
||||
(ADR-0019 §6). When an INSERT/UPDATE/DELETE fails, the
|
||||
runtime calls `enrich_dsl_failure(database, command,
|
||||
error)` which:
|
||||
- Parses the engine message to identify the
|
||||
table/column.
|
||||
- For UNIQUE: looks up the user's attempted value from
|
||||
the Command (with schema-aware fallback for
|
||||
natural-order multi-value INSERT — including the
|
||||
serial/shortid auto-skip rule), pinpoints the
|
||||
existing conflicting row(s) via
|
||||
`Database::find_rows_matching` and renders as a
|
||||
`DiagnosticTable`.
|
||||
- For FK INSERT/UPDATE: outbound relationship lookup
|
||||
resolves `parent_table`, `parent_column`, and the
|
||||
attempted `value`.
|
||||
- For FK DELETE: inbound relationship lookup resolves
|
||||
`child_table`.
|
||||
- For NOT NULL: table+column resolution; no value or
|
||||
pinpoint (the value is null by definition).
|
||||
|
||||
- **`messages (short|verbose)` app-level command**.
|
||||
In-session state on `App::messages_verbosity`, threaded
|
||||
through `TranslateContext`. Default `verbose`
|
||||
(pedagogical headline + hint + optional diagnostic
|
||||
table). `short` drops the hint. Persistence waits on a
|
||||
future settings ADR.
|
||||
|
||||
- **`AppEvent::DslFailed`** carries
|
||||
`(command, error: DbError, facts: FailureContext)` so
|
||||
the App can defer rendering and apply its current
|
||||
verbosity at display time.
|
||||
|
||||
- **Catalog validator** (`tests::keys_validate_against_catalog`)
|
||||
enforces six invariants at build time: every key
|
||||
declared, every placeholder used and declared, no
|
||||
format specifiers, no forbidden engine vocabulary, no
|
||||
orphan YAML entries.
|
||||
|
||||
- **`main.rs`** parses the catalog at the very top so a
|
||||
corrupted build artefact fails loudly there rather than
|
||||
at the first `t!()` call deep inside the event loop.
|
||||
|
||||
What the ADR explicitly leaves out (still bounded to
|
||||
future ADRs):
|
||||
|
||||
- Advanced-mode SQL error sanitisation (waits on Q1).
|
||||
- Settings persistence for `messages` (future settings
|
||||
ADR).
|
||||
- Plural-form rules per locale (intentionally not a
|
||||
goal — see ADR §8.5 amendment).
|
||||
- Runtime locale selection (§8.2).
|
||||
- Locale-aware value formatting (rejected, not deferred —
|
||||
§8.7).
|
||||
- Constraint-management surface for CHECK (C3 territory;
|
||||
the catalog has CHECK wording ready as a placeholder).
|
||||
- Echo prefix tags + mode labels in `ui.rs` — left as
|
||||
literals because they're width-coupled to the
|
||||
alignment math; documented in commit `a6fd26d`.
|
||||
|
||||
### Anchor phrases preserved (ADR-0019 §10)
|
||||
|
||||
The catalog's anchor-phrase commitments held throughout:
|
||||
"no such table", "no such column", "no such relationship",
|
||||
"already exists", "already has the value", "cannot be
|
||||
converted", "discard information", "referenced by",
|
||||
"[client-side]". Existing tests asserting on these
|
||||
substrings still pass without rewording.
|
||||
|
||||
## Recommended next move
|
||||
|
||||
### Parser-as-source-of-truth ADR + H1a implementation
|
||||
|
||||
**This is the strongest recommendation.** Rationale:
|
||||
|
||||
- It's the natural follow-on from H1. The friendly-error
|
||||
layer dramatically improved engine-error wording; the
|
||||
parser-error wording is now the visibly-weakest user
|
||||
surface.
|
||||
- A concrete user gap surfaced during manual testing in
|
||||
this session: typing `create` produces
|
||||
`after `create`, expected `table`` — informative about
|
||||
the next missing token but not about the grammar of the
|
||||
command. The user explicitly asked "can we illustrate
|
||||
the expectation?" and we agreed it was a separate piece
|
||||
of work that needs its own ADR.
|
||||
- The handoff-5 pending list named it as the
|
||||
"load-bearing piece" because it unblocks H1a (syntax
|
||||
help in parse errors), I3 (tab completion), I4 (syntax
|
||||
highlighting), and on-the-fly error squiggles in one
|
||||
go.
|
||||
- The chumsky `keyword_ci` structural-error rework is
|
||||
the specific technical piece — today `keyword_ci` emits
|
||||
`Rich::custom` errors that don't aggregate across
|
||||
`choice` alternatives, so we get "expected `table`"
|
||||
instead of "expected `data` or `table`". Fixing that
|
||||
unlocks the rest.
|
||||
|
||||
Suggested ADR scope:
|
||||
|
||||
- What structured information chumsky already gives us
|
||||
(expected sets, span-tagged AST, partial parses on
|
||||
failure) and what we currently throw away.
|
||||
- `keyword_ci` rework so `choice` alternatives aggregate
|
||||
(the load-bearing change).
|
||||
- Per-command grammar templates surfaced in the error
|
||||
("`create table` expects: `<name> with pk
|
||||
[<col>:<type>...]`" rather than a single missing-token
|
||||
pointer).
|
||||
- Thinking ahead: how the same parse-output feeds tab
|
||||
completion (next valid token at cursor position) and
|
||||
syntax highlighting (token classification from the
|
||||
AST).
|
||||
- Catalog migration: parse-error wording joins
|
||||
`parse.*` once the grammar templates are in place.
|
||||
The current `parse.error` / `parse.caret` /
|
||||
`parse.empty` keys cover the wrapper; the per-command
|
||||
templates would land as new keys (`parse.usage.create`
|
||||
etc.).
|
||||
|
||||
Estimated: ADR design 200-400 lines; implementation
|
||||
probably 300-500 lines plus tests. Comparable in scope
|
||||
to ADR-0017's reception path.
|
||||
|
||||
## Other open work, in suggested priority order
|
||||
|
||||
### Easy alternative if you want a quick win first: A1 (CI workflow)
|
||||
|
||||
Single GitHub Actions YAML at `.github/workflows/ci.yml`.
|
||||
Cross-platform Linux / macOS / Windows; `cargo test` +
|
||||
`cargo clippy --all-targets -- -D warnings`. Locks in the
|
||||
610-test green baseline. Standard Rust CI template adapted
|
||||
to nursery-clippy. 1-2 hours. Detailed plan in handoff-5
|
||||
§A1, unchanged.
|
||||
|
||||
### Larger pending pieces
|
||||
|
||||
**Query DSL ADR + implementation.** Biggest remaining
|
||||
design piece. Earlier discussions landed on extending
|
||||
`show data` into a SELECT-style command with WHERE /
|
||||
projection / order; expose generated SQL as a pedagogical
|
||||
hook; bundle C5a's complex WHERE into one coherent
|
||||
feature. Then QA1 (EXPLAIN QUERY PLAN) becomes
|
||||
meaningful.
|
||||
|
||||
**Constraint management surface (C3).** UNIQUE / CHECK /
|
||||
NOT NULL DDL operations. The friendly-error layer has
|
||||
CHECK wording ready; the missing piece is the DDL surface
|
||||
itself. Probably 400-600 lines + tests.
|
||||
|
||||
**V-series UX projects** (handoff-5 §"Bigger UX
|
||||
projects"):
|
||||
- V4 — session log + Markdown export.
|
||||
- V1/V2 — relationship rendering (the "two structures +
|
||||
arrow" view).
|
||||
- V3 — ER diagram export.
|
||||
|
||||
### Smaller items still on the table
|
||||
|
||||
- I1 — multi-line input (Enter inserts newline,
|
||||
Ctrl-Enter submits).
|
||||
- I1b — readline shortcuts (Ctrl-A/E, Ctrl-W/K/U).
|
||||
- I3 — tab completion (depends on parser-as-source-of-
|
||||
truth).
|
||||
- I4 — syntax highlighting (depends on
|
||||
parser-as-source-of-truth).
|
||||
- C4 — m:n convenience (auto-junction-table). Rebuild
|
||||
primitive is solid so this should be straightforward.
|
||||
|
||||
### Tracked but explicitly bounded to other ADRs
|
||||
|
||||
- Q1 (SQL handling in advanced mode) — waits on Q4 (SQL
|
||||
subset ADR).
|
||||
- U-series undo/snapshot (replay landed this session as
|
||||
A3; undo + snapshot are independent and need their own
|
||||
pass).
|
||||
- Settings persistence — feeds the deferred
|
||||
`messages` persistence among other things.
|
||||
|
||||
## Sharp edges and subtleties (delta vs. handoff-5)
|
||||
|
||||
Carried-over edges still apply (sync `update`, worker
|
||||
thread, metadata transactions, rebuild-table primitive,
|
||||
modal infrastructure, project-switch lock dance, `[temp]`
|
||||
cleanup guards, persistence ordering, `DataResult` carries
|
||||
`column_types`, `output_render` is the only place tabular
|
||||
output should originate, `Type::Serial` no longer implies
|
||||
PK, `add column` returns `AddColumnResult`,
|
||||
`ChangeColumnTypeResult.client_side` field shape, non-PK
|
||||
serial INSERT auto-fill via `MAX(col)+1`, schema_to_ddl
|
||||
inline UNIQUE for non-PK, `read_schema` reads UNIQUE via
|
||||
`pragma_index_list`, structured parse-error rendering).
|
||||
New ones this session:
|
||||
|
||||
- **Every user-visible string flows through the catalog.**
|
||||
When adding a new error / hint / modal label / shortcut,
|
||||
the workflow is: add the entry to
|
||||
`src/friendly/strings/en-US.yaml`, add the
|
||||
`(key, &[placeholders])` tuple to
|
||||
`src/friendly/keys.rs::KEYS_AND_PLACEHOLDERS`, then call
|
||||
`crate::t!("category.key", placeholder = value)` at the
|
||||
use site. The validator unit test fails the build if
|
||||
any of those three steps are missed.
|
||||
|
||||
- **The translator's input is `TranslateContext` (owned
|
||||
Strings).** It used to be borrowed; the move to owned
|
||||
strings landed when runtime enrichment took over the
|
||||
schema-resolved facts. App's `build_translate_context`
|
||||
combines runtime-supplied `FailureContext` with the
|
||||
Command's operation derivation and the App's verbosity.
|
||||
|
||||
- **Anchor phrases are load-bearing.** ADR-0019 §10 lists
|
||||
9 substrings the catalog commits to keeping stable. Many
|
||||
existing tests assert on these. When migrating a
|
||||
category to new wording, preserve the anchor or
|
||||
consciously update the catalog comment block.
|
||||
|
||||
- **The `running: ` prefix is hard-coded against the
|
||||
caret-padding math.** `app.rs` derives the caret
|
||||
position from `prefix.chars().count() = 9`. The
|
||||
`dsl.running` catalog template **must** start with
|
||||
"running: " for caret rendering to align. Documented
|
||||
inline.
|
||||
|
||||
- **`main.rs` initialises the catalog before args
|
||||
parsing** so the args-error path can use `help_text()`.
|
||||
A corrupted catalog (impossible in practice since it's
|
||||
`include_str!`'d and validated) would panic before the
|
||||
args error surfaces. Acceptable for a teaching tool.
|
||||
|
||||
- **`AppEvent::DslFailed` carries structured payload, not
|
||||
a pre-rendered string.** Tests that synthesise this
|
||||
event (in `tests/walking_skeleton.rs` and `app::tests`)
|
||||
must construct a `DbError` and a `FailureContext` (use
|
||||
`::default()` if you don't care about enrichment).
|
||||
|
||||
- **`Database::find_rows_matching(table, column, value,
|
||||
limit)`** is the public hook for row-pinpoint queries.
|
||||
The runtime uses it for UNIQUE conflict diagnostics. If
|
||||
a future feature wants similar row-finding (e.g. FK
|
||||
parent-side pinpoint, which is structurally plumbed but
|
||||
not yet populated — see runtime.rs's
|
||||
`enrich_fk_violation`'s "FK pinpoint not implemented in
|
||||
v1" comment), reuse this method.
|
||||
|
||||
- **`Database::read_relationships(table)` returns
|
||||
`(outbound, inbound)`.** The lifted version of the
|
||||
previously-private `read_relationships_outbound/inbound`
|
||||
pair.
|
||||
|
||||
## ADR index (read these before touching the related areas)
|
||||
|
||||
```
|
||||
0000 Record architecture decisions (process)
|
||||
0001 Language and TUI framework (Rust + Ratatui)
|
||||
0002 Database engine
|
||||
— User-facing posture (engine-vocabulary audit
|
||||
regression-tested via tests/engine_vocabulary_audit.rs)
|
||||
0003 Input modes and command dispatch
|
||||
0004 Project file format
|
||||
— amended by 0015
|
||||
0005 Column type vocabulary
|
||||
— definition of `serial` generalised by ADR-0018
|
||||
0006 Undo snapshots and replay log
|
||||
— replay command landed this session (ADR-0019 §9
|
||||
migration sweep covered its message wording too)
|
||||
0007 Sharing and export
|
||||
— amended by 0015 amendment 1
|
||||
0008 Testing approach
|
||||
0009 DSL command syntax conventions
|
||||
0010 Database access via worker thread
|
||||
— ADR-0019 §6 enrichment uses the worker via two new
|
||||
public methods (read_relationships, find_rows_matching)
|
||||
0011 FK column type compatibility
|
||||
0012 Internal metadata for user-facing column types
|
||||
0013 Relationships, naming, and rebuild-table strategy
|
||||
0014 Data operations, value literals, and auto-show
|
||||
0015 Project storage runtime
|
||||
— ColumnSchema gained `unique: bool` for ADR-0018
|
||||
0016 Pretty table rendering for data and structure views
|
||||
— ADR-0019 §7 reuses `render_diagnostic_table` for
|
||||
the friendly-error pinpoint output
|
||||
0017 Column type-change compatibility
|
||||
0018 Auto-fill contracts for serial and shortid columns
|
||||
0019 Friendly error layer (H1) and i18n message catalog
|
||||
— IMPLEMENTED (this session). Catalog covers ~170
|
||||
entries across 16 categories. Runtime enrichment
|
||||
per §6, migration sweep per §9 both done.
|
||||
```
|
||||
|
||||
## Repository layout (delta vs. handoff-5)
|
||||
|
||||
```
|
||||
src/
|
||||
friendly/ — new module (ADR-0019)
|
||||
mod.rs — public API, t!() macro
|
||||
format.rs — catalog loader, substitution
|
||||
keys.rs — KEYS_AND_PLACEHOLDERS + validator
|
||||
error.rs — FriendlyError + DiagnosticTable + render
|
||||
translate.rs — DbError → FriendlyError classification
|
||||
strings/
|
||||
en-US.yaml — the catalog body (~170 entries)
|
||||
action.rs — Action::Replay
|
||||
app.rs — messages command + verbosity field;
|
||||
build_translate_context;
|
||||
attempted-value extraction (later
|
||||
moved to runtime); note_ok_summary
|
||||
helper; modal/help/system notes all
|
||||
go through t!()
|
||||
cli.rs — HELP_TEXT const replaced with
|
||||
pub fn help_text() that reads catalog
|
||||
db.rs — Request::ReadRelationships +
|
||||
Request::FindRowsMatching;
|
||||
read_relationships /
|
||||
find_rows_matching public methods;
|
||||
RelationshipsReply type alias;
|
||||
friendly_message body delegates to
|
||||
translator; friendly_change_column_engine_error
|
||||
+ enrich_fk_message removed;
|
||||
fk_violation_message_lists_outbound_relationships
|
||||
test rewritten as
|
||||
fk_violation_returns_engine_classified_constraint_error
|
||||
dsl/
|
||||
command.rs — Command::Replay variant
|
||||
parser.rs — replay rule + path_literal terminal
|
||||
event.rs — DslFailed { command, error, facts }
|
||||
+ Replay events
|
||||
main.rs — catalog init at top; help_text() use
|
||||
runtime.rs — Action::Replay handler;
|
||||
spawn_replay + run_replay (pub for
|
||||
integration tests);
|
||||
enrich_dsl_failure (pub) + helpers;
|
||||
resolve_replay_path
|
||||
ui.rs — modal/status/panel/shortcut strings
|
||||
routed through t!() (left echo prefix
|
||||
tags + mode labels alone — alignment-
|
||||
coupled, documented)
|
||||
docs/
|
||||
adr/
|
||||
0019-friendly-error-layer-and-i18n.md
|
||||
— new (this session)
|
||||
README.md — indexed
|
||||
handoff/
|
||||
20260509-handoff-6.md — this file
|
||||
tests/
|
||||
engine_vocabulary_audit.rs — new in this session (A2)
|
||||
friendly_enrichment.rs — 8 integration tests for ADR-0019 §6
|
||||
replay_command.rs — 9 integration tests for A3 (U4)
|
||||
```
|
||||
|
||||
## How to take over
|
||||
|
||||
1. Read this file.
|
||||
2. Read `CLAUDE.md` for the working-style rules.
|
||||
3. Read `docs/requirements.md` for the granular progress
|
||||
table.
|
||||
4. **If picking up the recommended next move (parser-as-
|
||||
source-of-truth ADR)**: read `docs/adr/0019-*` to see
|
||||
how ADR-0019 framed catalog wording, since parse errors
|
||||
join the catalog under `parse.*`. The current keys are
|
||||
`parse.error`, `parse.caret`, `parse.empty` — the new
|
||||
work would add `parse.usage.<command>` and friends.
|
||||
Read `src/dsl/parser.rs` for the chumsky scaffolding
|
||||
and `src/app.rs::dispatch_dsl` for the source-line +
|
||||
caret rendering. The `keyword_ci` rework is the
|
||||
technical core.
|
||||
5. **If picking up A1 (CI)**: handoff-5 §A1 has a
|
||||
complete plan. Nothing new to add.
|
||||
6. **If picking up Query DSL or another bigger piece**:
|
||||
start with an ADR draft. Don't implement without one —
|
||||
those touch enough code to warrant the discipline.
|
||||
7. Run `cargo test` to confirm the 610-test green
|
||||
baseline.
|
||||
8. Run `cargo clippy --all-targets` to confirm
|
||||
clippy-clean.
|
||||
9. Run `cargo run --release` and try the smoke test in
|
||||
the next section.
|
||||
|
||||
### End-to-end smoke test (current state)
|
||||
|
||||
Demonstrates ADR-0019's friendly-error wording with row
|
||||
pinpointing. Replaces handoff-5's recipe (which is now
|
||||
stale — every error path renders through the catalog and
|
||||
shows pinpointed rows where applicable).
|
||||
|
||||
```
|
||||
$ rm -rf /tmp/handoff6-smoke
|
||||
$ rdbms-playground --data-dir /tmp/handoff6-smoke
|
||||
|
||||
# Inside the app:
|
||||
help -- in-app help (now from catalog)
|
||||
messages -- shows current verbosity
|
||||
(verbose by default)
|
||||
|
||||
# Setup:
|
||||
create table Customers with pk id:int
|
||||
add column Customers: Name (text)
|
||||
insert into Customers (1, 'Alice')
|
||||
insert into Customers (2, 'Bob')
|
||||
|
||||
create table Orders with pk id:serial
|
||||
add column Orders: CustId (int)
|
||||
add column Orders: Total (real)
|
||||
add 1:n relationship from Customers.id to Orders.CustId
|
||||
insert into Orders (CustId, Total) values (1, 9.99)
|
||||
|
||||
# UNIQUE INSERT — original report case from this session:
|
||||
insert into Customers (1, 'Carol')
|
||||
-- emits:
|
||||
-- "insert into Customers" failed:
|
||||
-- `Customers.id` already has the value `1`.
|
||||
-- The `id` column on `Customers` is unique —
|
||||
-- pick a different value, or update the existing
|
||||
-- row instead.
|
||||
-- + bordered table showing Alice's row.
|
||||
|
||||
# UNIQUE UPDATE — operation-tailored hint:
|
||||
update Customers set id=1 where Name='Bob'
|
||||
-- "your update would create a duplicate"
|
||||
-- (different from the INSERT wording)
|
||||
|
||||
# FK INSERT (child-side) — was broken pre-§6, now resolves
|
||||
# parent_table/parent_column/value via outbound-FK lookup:
|
||||
insert into Orders (CustId, Total) values (999, 5.50)
|
||||
-- "no parent row in `Customers` has `id` = `999`"
|
||||
-- + hint about inserting a matching parent.
|
||||
|
||||
# FK DELETE (parent-side) — child_table from inbound-FK lookup:
|
||||
delete from Customers where id=1
|
||||
-- "`Customers` rows are referenced by `Orders`"
|
||||
|
||||
# Compare verbosity:
|
||||
messages short
|
||||
insert into Customers (1, 'Carol') -- headline only, no hint, but
|
||||
pinpoint table still shows
|
||||
messages verbose
|
||||
insert into Customers (1, 'Carol') -- full headline + hint + pinpoint
|
||||
|
||||
# Replay (A3 from earlier in session):
|
||||
# Save a few commands to a file then replay:
|
||||
save -- prompts for project name
|
||||
# Or use `replay history.log` to re-run the entire session.
|
||||
replay history.log
|
||||
|
||||
# Anchor phrases:
|
||||
show data Ghost -- "no such table: `Ghost`"
|
||||
(anchor: "no such table")
|
||||
|
||||
quit
|
||||
```
|
||||
|
||||
### Manual spot-checks worth running
|
||||
|
||||
- `--help` produces the CLI banner from the catalog (no
|
||||
literal const anymore).
|
||||
- `mode advanced` then any input produces the
|
||||
not-implemented placeholder ("advanced mode SQL not
|
||||
implemented yet — echo: …").
|
||||
- `messages` toggles verbosity in-session; not persisted
|
||||
across restarts (waits on settings ADR).
|
||||
- Switch to a non-existent project path → see "path `…`
|
||||
does not exist" via `project.load_path_missing`.
|
||||
- Trigger a parse error (e.g. `create`) → see the caret
|
||||
pointer aligned under the offending character + the
|
||||
structural "after `create`, expected `table`" message
|
||||
(still chumsky-derived; the parser-as-source-of-truth
|
||||
ADR addresses this). This is the recommended-next-move
|
||||
hook.
|
||||
Reference in New Issue
Block a user