feat(config): span-annotated validation errors via miette - #110
Conversation
Surface miette-rich diagnostics on config-load failures across all four formats (TOML, YAML, JSON) and across structural and semantic validation paths. - Add `ConfigError::Validation` variant carrying `NamedSource` + `SourceSpan` so post-deserialization issues (currently bad palette hex values) reach the user with a span pointing at the offending line. - Populate `source_code` and `span` on figment-driven YAML/JSON parse errors via a key-search heuristic; previously they were `None`. - Walk `toml::de::DeTable`'s spanned representation to resolve arbitrary dotted paths to byte offsets, so unknown-key and bad-value diagnostics highlight precisely. - Validate `[color.tokens]` entries against `#rgb`/`#rgba`/`#rrggbb`/ `#rrggbbaa` after deserialization. The hex check is pure (no I/O, uses indexmap's deterministic iteration) so the same input always surfaces the same diagnostic. Tested via four failure-class integration tests plus YAML smoke tests covering: unknown top-level key, unknown nested key, wrong type, and bad palette value. Fixes #22 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
I have all the information I need. Let me compile the review. PR #110 — feat(config): span-annotated validation errors via mietteFiles touched: 1. Determinism
The 2. Workspace layering
3. Error handling
4. Test coverage16/16 tests pass. The four documented failure classes (unknown top-level key, unknown nested key, wrong type, bad palette value) are covered for TOML with precise span assertions; YAML/JSON smoke-tested for 5. Documentation
Punch listWarning (not blocker) — double file read in YAML/JSON paths
If this is ever tightened, the fix is to use figment's string-based providers ( Warning —
Observation —
Verdict: APPROVE |
Addresses Claude code-review feedback on PR #110. The CLAUDE.md rule is "Never write multi-line comment blocks — one short line max" and both `#[allow(...)]` rationales fit on one line.
Target branch
mainSpec
Fixes #22
Summary
ConfigError::ValidationcarryingNamedSource+SourceSpanso post-deserialization issues (currently bad palette hex values) reach the user with a label that points at the offending line.source_codeandspanon figment-driven YAML/JSON parse errors via a key-search heuristic; previously they wereNone.toml::de::DeTable's spanned representation to resolve arbitrary dotted paths to byte offsets, so unknown-key, wrong-type, and bad-value diagnostics highlight the offending value precisely.[color.tokens]entries against#rgb,#rgba,#rrggbb, and#rrggbbaaafter deserialization. The walk usesIndexMaporder so the same input always surfaces the same diagnostic.Crates touched
plumb-coreplumb-formatplumb-cdpplumb-configplumb-mcpplumb-clixtaskdocs/.agents/or.claude/.github/System impact
# Errorssection if fallible)tools/listentry + protocol test)register_builtinentry)cargo xtask schema+ commit result).agents/rules/determinism.md)ConfigError::Validationis the new public variant. Its docstring covers each field;load's# Errorssection was extended to mention it. No JSON Schema impact (theConfigdata shape is unchanged).Architectural compliance
plumb-corehas no internal deps; unsafe only inplumb-cdp;println!/eprintln!only inplumb-cli.thiserror-derived in libs;anyhowonly inplumb-cli::main.unwrap/expect/panic!in library crates.SystemTime::now/Instant::nowinplumb-core.HashMapin observable output paths (useIndexMap).#[allow(...)]is local and has a one-line rationale.The two
#![allow(clippy::redundant_pub_crate)]attributes (inspan.rsandvalidate.rs) match the workspace convention already used inplumb-core::rules::util. The#![allow(clippy::expect_used)]in the new integration test is documented in-file: integration-test helpers don't carry the#[test]proximity that clippy'sallow-expect-in-testslooks for.Test plan
just validatepasses locallycargo xtask pre-releasepasses (if rule or schema changed)just determinism-checkpasses (3× byte-diff clean) — covered byjust validatecargo deny checkpasses — covered byjust validateNew tests in
crates/plumb-config/tests/validation_errors.rscover the four documented failure classes plus YAML smoke tests for both Parse and Validation variants. New unit tests invalidate.rscover hex-shape acceptance/rejection. New unit tests inspan.rscover the TOML walk and the YAML key-search fallback.Documentation
# Errorssection on every new public fallible fndocs/src/updated when user-visible behavior changeddocs/src/rules/<category>-<id>.mdwritten for new rulesNo user-visible behavior outside of richer diagnostics on existing failure paths; release-please will pick this up at release time.
Breaking change?
ConfigErroris#[non_exhaustive], so adding theValidationvariant is non-breaking. Existing matches onParsecontinue to compile and behave identically.Checklist
codex/<primary>-<type>-<slug>—codex/22-feat-config-miette-validation/gh-review --local-diff main...HEADrun locallyReviewer notes
ColorSpec/RadiusSpec/AlignmentSpec/A11ySpecshapes in parallel. This PR deliberately stays out ofcrates/plumb-core/src/config.rsdata shapes; onlyplumb-config(the loader) is touched.toml::de::DeTable::parse, which keeps spans on every key and value through the recursiveDeValuetree. That avoids theuntaggedenum buffering issue that broke an earlierSpanned<Value>approach.source_code()is present rather than asserting on a specific span.