commit 52dedb8a3211ba7374731f8fef14951017a4c384
parent 1e922fb3c24b8fa9f183230e975dae9efbf0517c
Author: triesap <tyson@radroots.org>
Date: Wed, 17 Jun 2026 17:42:40 -0700
sdk: harden public error contract
- mark RadrootsSdkError as non-exhaustive for public evolution
- document method-based error handling for runtime callers
- extend error detail assertions for class and recovery data
- preserve existing error codes and structured behavior
Diffstat:
3 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/crates/sdk/README b/crates/sdk/README
@@ -96,3 +96,7 @@ The crate is licensed as `MIT OR Apache-2.0`. Its manifest is configured for a
future crates.io release, but a public release still requires the full SDK check
lane, generated artifact reproducibility checks, metadata review, and a publish
dry run.
+
+Runtime errors use a non-exhaustive `RadrootsSdkError` enum. Public callers
+should branch on the stable method surface: `code`, `class`, `retryable`,
+`detail_json`, and `recovery_actions`.
diff --git a/crates/sdk/src/error.rs b/crates/sdk/src/error.rs
@@ -57,6 +57,7 @@ pub struct RadrootsSdkPartialLocalMutationError {
#[cfg(feature = "runtime")]
#[derive(Debug)]
+#[non_exhaustive]
pub enum RadrootsSdkError {
Io {
path: PathBuf,
diff --git a/crates/sdk/tests/runtime_foundation.rs b/crates/sdk/tests/runtime_foundation.rs
@@ -444,7 +444,15 @@ fn sdk_error_contract_methods_cover_all_variants() {
assert_eq!(error.recovery_actions(), recovery_actions);
let detail = error.detail_json();
assert_eq!(detail["code"], code);
+ assert_eq!(
+ detail["class"],
+ serde_json::to_value(class).expect("class json")
+ );
assert_eq!(detail["retryable"], retryable);
+ assert_eq!(
+ detail["recovery_actions"],
+ serde_json::to_value(&recovery_actions).expect("recovery actions json")
+ );
assert!(detail["message"].is_string());
assert!(detail["detail"].is_object());
}