--- id: core-error-model name: Error model — the one-enum family with altitude discipline status: completed depends_on: [scaffold-crate-features] scope: single risk: low impact: component level: implementation tags: [wave-1, errors] --- ## Description Implement the crate's error family (`src/error.rs`, re-exported from `lib.rs`) per store-api.md's error model and ADR-012 §6.5: - One `Error` enum (thiserror) with exactly the five distinguished variants: `Missing`, `Verification`, `Io(String)`, `GcRefuse`, `KeyInvalid`. - **The altitude discipline in doc comments** (store-api.md's "one enum, both altitudes"): the `Backend` trait's methods return this family but its *effective* members are `Missing`/`Verification`/`Io`/`KeyInvalid` — `KeyInvalid` never fires at the trait boundary (keys arrive opaque there) and `GcRefuse` never fires below the facade (arbitration answers flow up as data; the facade decides and owns the refusal). The facade's public surface re-exposes the family with `GcRefuse` added. - Semantics per variant: `Missing` — key absent on ops that signal absence via `Err` (`read_range`, `delete`); `get`/`stat` signal absence with `None` and never carry `Missing`. `Verification` — put/get hash-check failure (content ≠ key). `Io(String)` — backend media failure, stringly because `std::io::Error` is not stable across versions. `GcRefuse` — direct delete refused (protected key: pinned, registered-source-live, or protect-callback-named). `KeyInvalid` — malformed key bytes at the boundary (truncated, unknown algorithm — rejects, never guesses). - **Named design point for the review gate**: store-api.md's wording ("one enum, both altitudes… the trait's effective members… the facade re-exposes them with `GcRefuse` added") is implemented as a *single* enum with the altitude discipline carried by doc comments and construction discipline (not two types). The gate audits this reading against the spec text; if the gate reads it as requiring two types, that is a cheap fix now. No panics; no `unwrap`/`expect` outside tests; `#[non_exhaustive]` is **not** applied unless the spec requires it (the variant set is ADR-pinned; new failure families are new ADRs — match the family's posture on alkstore's error taxonomy). ## Acceptance Criteria - [x] `Error` enum with the five variants, thiserror-derived Display/Error impls - [x] Doc comments on the enum and each variant stating the semantics and the altitude discipline verbatim-traceable to store-api.md - [x] Unit tests: each variant constructs; `Missing` documented get/stat exclusion stated in docs (behavioral enforcement lands with the facade in wave 2) - [x] `cargo test`, `cargo clippy --all-targets -- -D warnings`, `cargo fmt --check` green ## References - docs/architecture/store-api.md (§Error model) - docs/architecture/decisions/012-pre-decomposition-consistency-rulings.md §6.5, §1 ## Notes - Implemented as a *single* enum carrying the altitude discipline in doc comments (module doc, per-variant docs, and a `one_enum_both_altitudes` test asserting the 4-member trait-shape vs 5-member facade-shape split) — the reading recommended by the task's named design point. Payloads verbatim: only `Io(String)` is annotated with a payload in store-api.md/ADR-012 §6.5; `Missing`, `Verification`, `GcRefuse`, `KeyInvalid` are the unit variants the spec text itself writes, so no payloads were invented for them. - `#[non_exhaustive]` not applied per the task's ADR-pinned variant set. `Error` derives `Debug`/`PartialEq`/`Eq` (test/ctor utility; no behavior added). - Re-exported as `pub use error::Error` from `lib.rs`; module remains public per the scaffold shape. - The `missing_is_exclusive_to_err_shaped_ops` test is the marker for the get/stat-exclusion doc contract; behavioral enforcement is deferred to the wave-2 facade task, as scoped. ## Summary `src/error.rs` now defines the crate's error family: one thiserror-derived `Error` enum with exactly the five distinguished variants (`Missing`, `Verification`, `Io(String)`, `GcRefuse`, `KeyInvalid`), doc comments traceable to store-api.md §Error model and ADR-012 §6.5/§1 stating each variant's semantics plus the one-enum/ two-altitude discipline (trait boundary: `Missing`/`Verification`/`Io`/ `KeyInvalid` effective; `KeyInvalid` never fires at the boundary, `GcRefuse` never fires below the facade — the facade re-exposes the family with `GcRefuse` added). Re-exported from `lib.rs`. Three unit tests cover variant construction, the single-enum altitude shape, and the `Missing`-is-never-`get`/`stat`-absence doc contract. Verified: `cargo test`, `cargo clippy --all-targets -- -D warnings`, `cargo fmt --check` all green.