Repository navigation
feat: structured error codes foundation (MinigrafError, ErrorCategory) — #277 (1/6) - #357
Merged
Merged
Conversation
…ion tests) Preflight scan caught the discrepancy before dispatching implementers. Part of #277.
Foundation types for structured runtime error codes. No call sites wired up yet — this is pure scaffolding. Part of #277.
Task 1's implementer necessarily added `pub(crate) mod error;` to src/lib.rs -- cargo test --lib error:: cannot compile/run without the module being part of the crate tree, a gap the original brief didn't anticipate. Task 4 was written assuming no such line existed yet and would have inserted a duplicate `mod error;`, a compile error. Fixed Task 4's text to upgrade the existing line's visibility instead. Ruling from Task 1's task review. Part of #277.
Call-site macros that tag an anyhow::Error with a compile-time-checked ErrorCode, formatted from the code's REGISTRY template. Not yet used by any real call site. Part of #277.
MinigrafError is the new public error type: category + stable code + Display as "[CODE] message" + std::error::Error. From<anyhow::Error> walks the error chain for a CodedError, falling back to INT-000 for any error not yet migrated to a specific code. Part of #277.
Wires the new error module into the public API surface, documents the INT-000 catch-all code in ERROR_REFERENCE.md, and adds a test that fails if REGISTRY and the doc's code list/message templates ever diverge. Part of #277.
…ded! These have no production call sites until the first category PR (PRS) starts using them -- Task 11's clippy -D warnings gate needs this clean now rather than deferred. Also replaces registry_entry's expect() with a debug_assert! + defensive fallback, since clippy::expect_used is denied crate-wide and this was blocking `cargo clippy --all-features -- -D warnings` independently of the dead-code warnings. Part of #277.
open, open_with_options, in_memory, in_memory_with_options, and the OpenOptions/OpenOptionsWithPath builders now return Result<Minigraf, MinigrafError>. Bodies are unchanged (renamed to _inner twins); every error still surfaces as INT-000 until a later category PR wires up real codes. Part of #277.
Signature-only change; body renamed to execute_inner, unchanged. Part of #277.
Signature-only changes; bodies renamed to _inner twins, unchanged. Part of #277.
Signature-only changes; bodies renamed to _inner twins, unchanged. Part of #277.
Signature-only changes; bodies renamed to _inner twins, unchanged. Part of #277.
The mutation happens inside commit_inner, which already declares its own mut self -- the outer wrapper never mutates self directly. Part of #277. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P7e4uTBWtM8fMZiPZc4bCw
- Remove unused `pub use` re-exports of FaultConfig and FaultInjectingBackend (tests import directly from fault_inject module, not through the re-export) - Apply rustfmt formatting to match project style - Verify all clippy checks pass with -D warnings Part of #277.
…s scope The unused FaultConfig/FaultInjectingBackend re-export predates this branch (confirmed via git log against the merge-base with main) and is unrelated to structured error codes. Reported, not fixed, matching how Tasks 4/8/9 handled other pre-existing out-of-scope issues in this same plan. Part of #277.
Line 4 said errors surface as anyhow::Error, but this PR (part of #277) made db.execute()/db.prepare()/etc. return MinigrafError, as the very next paragraph already documented. Align line 4 with reality.
…ry entry
From<anyhow::Error>'s fallback branch (no CodedError found in the chain)
hardcoded code/category/message instead of calling registry_entry, so
the emitted Display text never actually matched the documented
'unclassified internal error: {}' template in ERROR_REFERENCE.md. Route
it through registry_entry(ErrorCode::Int000) + format_template instead,
removing the third hardcoded duplicate of INT-000/Internal (REGISTRY and
registry_entry's own fallback were the other two).
Updates one existing test's expected Display text to the now-correct
template-prefixed form; part of #277.
ErrorCategory is a public enum designed for downstream consumers to match on, in a library targeting decades-long API stability per PHILOSOPHY.md. Marking it non_exhaustive now, before any release ships it, means a future 7th category (STG/WAL/QRY/API's categories already exist as variants; further growth is plausible) won't be a breaking change for consumers who already have to write a wildcard arm. No effect within this crate. Part of #277.
…ANGELOG The #277 foundation entry was missing that every error's Display/ to_string() now carries a [CODE] prefix it didn't have before — a behavior change beyond the Result<T, MinigrafError> type signature, affecting anything that string-matches error output (the REPL's printed errors, and all 7 language-binding repos per cascade-monitoring practice). Also fixes .code() -> &str to the actual signature, .code() -> &'static str. Part of #277.
…e advice During the multi-PR #277 migration window (this Foundation PR is 1 of 6; only INT-000 exists so far), ordinary user syntax mistakes surface as INT-000 too, same as genuine internal bugs, since nothing is migrated to specific codes yet. Reorder the INT section's opening sentences so a reader hits that transitional caveat before the 'likely indicates a bug ... please file an issue' advice, not after. Part of #277.
…rorCode coverage test registry_entry's doc comment claimed the sync test (registry_is_a_subset_of_error_reference_doc) exercises every ErrorCode variant — false, it iterates REGISTRY, not ErrorCode, so a new ErrorCode variant added without a matching REGISTRY row is caught by nothing outside a debug_assert! that's compiled out in release builds. Correct the comment, and add error::tests::every_error_code_variant_has_a_registry_entry: an exhaustive match over ErrorCode with no wildcard arm, so the PRS category PR's ~79 new variants (and every one after) fail to compile here if a REGISTRY row is missing, rather than silently falling back to INT-000 at runtime. Part of #277.
…t chain Two small gaps flagged as risk for the next (PRS category) PR, which will be the first real caller of both bail_coded!/err_coded! (multi-hop .context() chains are routine there) and format_template with varying arg counts: - format_template_arg_count_mismatch_debug_asserts: a #[should_panic] test confirming the debug_assert_eq! fires under cargo test's debug build; in release (debug_assert compiled out) the same call does not panic and instead drops the unfilled placeholder's text, per the function's existing doc comment. - minigraf_error_finds_coded_error_through_two_context_hops: extends the existing single-hop context-chain test to two .context() calls, proving the chain-walk in MinigrafError::from finds a CodedError buried multiple hops deep, not just one. Part of #277.
Final whole-branch review of the Foundation PR found that src/query/datalog/parser.rs returns Result<_, String> everywhere, not anyhow::Result -- bail_coded!/err_coded! (which produce anyhow::Error) won't compile there as a drop-in replacement the way they do everywhere else in the crate. This doesn't require any code change in this PR, but must be decided before the PRS category PR (79 of 130 codes, the next PR in the #277 rollout) is planned. Part of #277.
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This was referenced Aug 25, 2026
This was referenced Aug 25, 2026
Closed
adityamukho
added a commit
that referenced
this pull request
Aug 25, 2026
#366) * feat: migrate parser.rs to PRS-0xx structured error codes — #277 (2/6) Wires up all 79 documented PRS-0xx codes (docs/ERROR_REFERENCE.md) in src/query/datalog/parser.rs via bail_coded!/err_coded!, replacing the generic INT-000 fallback the #277 foundation PR (#357) left in place for every category. parser.rs's internal Result<_, String> signatures (118 error sites) convert to anyhow::Result<_> so bail_coded!/err_coded! can be used directly, per the decision recorded in the foundation PR. db.rs's three parse_datalog_command() call sites (Minigraf::execute, WriteTransaction::execute, Minigraf::prepare) drop their .map_err(|e| anyhow::anyhow!("{}", e)) — that stringified and discarded any CodedError chain before it could reach MinigrafError::from at the API boundary. docs/ERROR_REFERENCE.md's PRS "Error text" lines are updated to show the real {}-templated form (matching the INT-000 convention already established) instead of a fully-rendered example value, verified byte-for-byte against error.rs's REGISTRY by the existing registry_is_a_subset_of_error_reference_doc sync test. Two documented codes are wired up but structurally unreachable through the public API: PRS-028 ("window expression cannot be empty") and PRS-049 ("unexpected end of fact vector") sit behind conditions their call sites' own guards already rule out. Pre-existing parser logic, not introduced by this change. Adds tests/error_codes_prs_test.rs: 16 test functions covering all 77 reachable PRS codes end-to-end through db.execute() and db.prepare(), asserting both .code() and .category(). Updates the foundation PR's placeholder assertion (execute_parse_error_returns_coded_error) from INT-000/Internal to the real PRS-005/Parser it now produces. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P7e4uTBWtM8fMZiPZc4bCw * ci: retrigger workflows (no rust.yml/rust-clippy.yml runs fired on initial push) --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Foundation PR for issue #277 (structured runtime error codes) — 1 of 6 planned PRs. Adds a new
src/error.rsmodule (ErrorCategory,ErrorCode, aREGISTRYmapping codes to message templates,bail_coded!/err_coded!macros, and the publicMinigrafErrortype) and migrates 13 public API functions acrosssrc/db.rsandsrc/query/datalog/prepared.rsfromanyhow::Result<T>toResult<T, MinigrafError>.By design, zero real call sites are migrated to specific error codes in this PR — every error currently falls through to a generic
INT-000catch-all. The 5 follow-up category PRs (PRS, STG, WAL, QRY, API+INT) wire up the 130 documented codes indocs/ERROR_REFERENCE.mdone category at a time. Part of #277 — the umbrella issue stays open until all 6 land.Design spec:
docs/superpowers/specs/2026-08-25-structured-error-codes-design.mdImplementation plan:
docs/superpowers/plans/2026-08-25-structured-error-codes-foundation.mdType of change
Minigraf's,WriteTransaction's, andPreparedQuery's public methods now returnResult<T, MinigrafError>instead ofanyhow::Result<T>.MinigrafErrorimplementsstd::error::Error, so?still works againstanyhow::Result/Box<dyn Error>callers. Every error'sDisplay/to_string()output now carries a[CODE]prefix — a behavior change beyond the type signature (see CHANGELOG). Bundles into the version bump already pending from the unreleasedOpenOptionsfield addition.Checklist
cargo testpasses (1085 tests, 0 failures)cargo clippy --all-features -- -D warningsis cleancargo fmt --checkpassessrc/error.rs, 8 integration tests intests/error_codes_foundation_test.rs.context()chain-walking and theINT-000fallback pathunwrap()/expect()in library code pathsCHANGELOG.mdupdated underUnreleasedthiserror),ErrorCategory/code stay a stable matchable surface rather than a 130-variant enum, appropriate for a decades-stability commitmentNotes for reviewer
ErrorCategoryis marked#[non_exhaustive]— a deliberate forward-compatibility choice for a 6-variant public enum meant for downstreammatch, made during final review. 10000 li>_inner/wrapper migration pattern (rename the existing function to a private_innertwin with an unchanged body, add a thinpubwrapper doing.map_err(MinigrafError::from)) is applied uniformly across all 13 functions — verified consistent by both per-task and whole-branch review.src/query/datalog/parser.rsisResult<_, String>-based, notanyhow-based, sobail_coded!/err_coded!won't work there as a drop-in replacement the way they do everywhere else. This needs a decision before the PRS category PR (79 of 130 codes, the next PR) is planned — see the spec's Migration phasing section, step 2.superpowers:subagent-driven-development— 12 implementer/reviewer task cycles plus a final whole-branch review and one consolidated fix wave. Full history in the commit log.