docs: mark H1 done — friendly DB-error layer is shipped

Verification found H1 (ADR-0019) fully implemented and tested: the
friendly::translate_error chokepoint is wired on the live failure path
(runtime + app + DbError::friendly_message), covers all five error
categories (UNIQUE, FOREIGN KEY both sides, NOT NULL, CHECK,
type-mismatch) with operation×kind×verbosity wording, the messages
verbosity command, and §6 row-pinpointing via runtime-resolved facts —
backed by 44 friendly unit tests + 12 full-stack friendly_enrichment
integration tests. The "partial / FK-only" notes were stale.

Mark requirements H1 done; fix the obsolete "diagnostic_table is
always None" comment in translate.rs (pinpointing landed in 431645a).
Remaining ADR-0019 scope (§9 i18n sweep, §OOS-2 advanced-SQL
sanitization, §OOS-3 messages persistence) stays deferred.
This commit is contained in:
claude@clouddev1
2026-06-02 20:07:45 +00:00
parent 56d9671488
commit be7b078878
2 changed files with 27 additions and 18 deletions
+15 -6
View File
@@ -542,12 +542,21 @@ since ADR-0027.)
## Hints, help, errors
- [ ] **H1** Friendly error-rewriting layer translates SQLite
error messages into learner-friendly equivalents.
*(Progress: foreign-key constraint failures are enriched
with both inbound and outbound relationship listings (so
RESTRICT errors point at the children that still reference
this table); full SQL → English translation pending.)*
- [x] **H1** Friendly error-rewriting layer translates engine
error messages into learner-friendly equivalents (ADR-0019).
*(Done: the `friendly::translate_error` chokepoint is wired on
the live failure path (runtime + app + `DbError::friendly_message`)
and covers all five ADR-0019 §3 categories — UNIQUE, FOREIGN KEY
(parent- and child-side), NOT NULL, CHECK, and type-mismatch —
with operation×kind×verbosity catalog wording, the
`messages short|verbose` verbosity command, and §6 row-pinpointing
via runtime-resolved facts rendered through the bordered
diagnostic table. Covered by 44 `friendly` unit tests + 12
full-stack `friendly_enrichment` integration tests. Remaining
ADR-0019 scope is deferred and separately tracked: the §9 i18n
migration sweep of all other user-facing strings, advanced-mode
SQL-error sanitization (§OOS-2), and `messages` persistence
(§OOS-3, awaits the settings ADR).)*
- [ ] **H1a** Strong syntax-help in parse errors. When the user
types something near-correct (e.g. `insert into T ('Oli')` —
forgotten `values`; or `update T set x=1` — missing WHERE),
+12 -12
View File
@@ -16,18 +16,18 @@
//!
//! ADR-0019 §6 calls for re-querying the database after a
//! constraint failure to surface the offending row(s) through
//! ADR-0017's bordered diagnostic-table renderer. That layer
//! is plumbed structurally — [`FriendlyError::diagnostic_table`]
//! exists for it — but the actual re-query implementation is a
//! separate commit alongside its runtime-side wiring (the
//! translator needs the user's attempted values, which arrive
//! through [`TranslateContext`] populated at the runtime
//! callsite).
//!
//! For now, [`FriendlyError::diagnostic_table`] is always
//! `None` and the wording carries the full burden. Adding the
//! diagnostic table later is purely additive: the translator's
//! catalog keys and the renderer don't change.
//! ADR-0017's bordered diagnostic-table renderer. This is
//! **implemented** (commit `431645a`): the *runtime* resolves the
//! schema-dependent facts — table/column, parent/child tables, the
//! attempted value, and any pinpointed rows — into a
//! [`FailureContext`], which [`TranslateContext::from_facts`] feeds
//! into the translator. When those facts carry a pinpoint,
//! [`FriendlyError::diagnostic_table`] is populated and the renderer
//! appends the bordered table; when they don't (no live DB handle,
//! re-query failed, or a fallback callsite), it stays `None` and the
//! catalog wording carries the full burden. The translator itself
//! never touches the database — it only renders the facts it is
//! handed — so the two layers stay cleanly separable.
use crate::db::{DbError, SqliteErrorKind};
use crate::dsl::Type;