commit b4b63c79191d7105e5a12c68602a0e1ab176309c
parent 09b9a80de8a1793b8a7c627bd292bad8fec7abfa
Author: triesap <tyson@radroots.org>
Date: Thu, 30 Jul 2026 13:22:34 +0000
signing: document public api contract
- define the host SPI lifecycle side effects and security boundary
- compile README and external signer examples through package tests
- record the reviewed all-feature public API baseline
- document feature behavior intended consumers and serialization rules
Diffstat:
5 files changed, 497 insertions(+), 3 deletions(-)
diff --git a/crates/signing/README.md b/crates/signing/README.md
@@ -1,6 +1,163 @@
# radroots_signing
-Signing abstractions and authorization policy for Radroots.
+`radroots_signing` is the protocol-neutral host SPI for authorizing and signing
+frozen Radroots event drafts. It owns actor provenance, signer capabilities and
+status, bounded signing requests, exact-draft receipts, progress, and normalized
+secret-safe errors.
-This package root is established for the Release V1 refactor. Its signer SPI
-and policy surface are migrated in the subsequent signing checkpoints.
+The crate is `no_std` with `alloc`. It does not own secret keys, keyrings,
+network clients, NIP-46 sessions, SQL, UI prompts, or an async executor.
+Concrete local Nostr signing belongs in `radroots_nostr`; remote protocol state
+belongs in `radroots_nostr_connect`; applications compose those adapters in
+`radroots_sdk` or their own host layer.
+
+The authoritative package charter is the
+[`radroots_signing` section of the Release V1 specification](https://github.com/radrootslabs/lib/blob/master/docs/specs/radroots_crates_release_v1.md#8-radroots_signing).
+
+## Typical flow
+
+1. A host resolves public actor provenance and roles into an [`Actor`].
+2. Event-domain code freezes a canonical `radroots_event::EventDraft`.
+3. The host combines the actor, draft, typed operation ID, deadline, and
+ cancellation policy into a [`SignRequest`]. Construction validates the
+ draft, required author role, and expected public key before a signer runs.
+4. A dyn-compatible [`Signer`] implementation signs locally, delegates to a
+ remote device/service, or mediates explicit host interaction.
+5. The implementation creates a [`SignReceipt`] from the originating request.
+ Receipt construction rejects any signed-event drift from the frozen draft.
+
+[`Actor`]: crate::Actor
+[`Signer`]: crate::Signer
+[`SignRequest`]: crate::SignRequest
+[`SignReceipt`]: crate::SignReceipt
+
+```rust
+use radroots_event::{EventDraft, contract::AuthorRole};
+use radroots_identity::PublicKey;
+use radroots_protocol::runtime::v1::OperationId;
+use radroots_signing::{
+ Actor, SignRequest,
+ actor::ActorSource,
+ request::{CancellationPolicy, SignPolicy},
+};
+
+let public_key = PublicKey::from_hex(
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+)
+.expect("canonical public key");
+let actor = Actor::new(
+ public_key,
+ ActorSource::ExplicitPublicKey,
+ [AuthorRole::Any],
+)
+.expect("validated actor");
+let draft = EventDraft::new(
+ "radroots.social.geochat.v1",
+ 20_000,
+ 1_700_000_000,
+ Vec::new(),
+ "hello from Radroots",
+ public_key.to_hex(),
+)
+.expect("frozen draft");
+let policy = SignPolicy::new(
+ 1_700_000_030,
+ CancellationPolicy::PreservePublishedRequest,
+)
+.expect("bounded policy");
+let request = SignRequest::new(OperationId::SyncPush, actor, draft, policy)
+ .expect("authorized signing request");
+
+assert_eq!(request.operation_id(), OperationId::SyncPush);
+```
+
+The complete externally implementable SPI example is
+[`examples/host_signer.rs`](examples/host_signer.rs).
+
+## Host SPI contract
+
+`Signer` is intentionally externally implementable, object-safe, `Send`, and
+`Sync`. Its methods return boxed `Future + Send` values so the SPI does not
+select an async runtime or require an async-trait macro.
+
+- `status` is observational and must not create a signing request or another
+ durable side effect.
+- `sign` receives an owned, already-authorized request. Implementations must
+ honor its deadline and cancellation policy for the entire operation and must
+ create success only through `SignReceipt::from_signed_event`.
+- Implementations must not install an executor or spawn hidden workers. The
+ composing host owns polling, scheduling, and process lifecycle.
+- Every concrete adapter must document the exact point at which a request
+ becomes durable. Dropping the future before that point must leave no durable
+ effect; dropping it afterward does not imply rollback.
+- Concrete backend failures are normalized to `radroots_signing::Error`.
+ Native sources may be retained with `std`, but display, debug, and versioned
+ protocol reports never copy source text.
+
+## Deadlines, cancellation, and commit points
+
+`SignPolicy` carries an absolute Unix deadline. A signer must reject work once
+that deadline is reached; request construction does not read a clock.
+
+`CancellationPolicy::LocalCooperative` is for local-only work that may stop
+when cancellation is observed. `PreservePublishedRequest` is for operations
+that may publish a durable remote request: cancellation before publication may
+stop the operation, while cancellation after publication must preserve and
+report the final remote state explicitly. Cancellation never silently converts
+an unknown or committed remote state into success or rollback.
+
+The SPI defines those rules but performs no I/O itself. Commit points belong to
+the concrete adapter and must be visible in that adapter's documentation and
+status/progress behavior.
+
+## Serialization contract
+
+Native `Actor` and `SignRequest` values are runtime-local and are not
+serializable. `SignReceipt` can be serialized with `serde` but cannot be
+deserialized without the originating request; this prevents callers from
+bypassing authorization and exact-draft verification.
+
+The `serde` feature provides stable representations for passive policies,
+capabilities, status, progress, challenges, and receipts. Versioned
+cross-process error data is produced through `Error::to_report` and owned by
+`radroots_protocol`. An authentication challenge URI is deliberately
+host-displayable and serializable, so adapters must not embed credentials or
+secret material in it.
+
+## Security and side effects
+
+- Request construction validates the current draft before role and key
+ authorization and never invokes a signer on failure.
+- A successful receipt proves exact equality of author, timestamp, kind, tags,
+ content, and event ID with the frozen request draft.
+- `Error` display/debug output and protocol reports are redacted. Under `std`,
+ a caller may explicitly inspect a preserved native error source locally.
+- `AuthChallenge` debug output redacts its URI; the value accepts only bounded
+ control-free HTTPS URIs and remains untrusted navigation input for hosts.
+- This crate forbids unsafe code and contains no secret-key type, persistence,
+ network transport, global state, timer, or runtime initialization.
+
+## Features
+
+| Feature | Default | Contract |
+| --- | --- | --- |
+| `std` | yes | Uses `std` collections and permits preserved native error sources; no runtime, I/O, or global initialization is added. |
+| `serde` | yes | Adds serialization for explicitly passive public values and deserialization only where validated reconstruction is safe. |
+
+Features are additive. `--no-default-features` provides the `no_std + alloc`
+core, and `serde` is supported independently of `std`.
+
+## Intended consumers
+
+- `radroots_nostr` implements concrete local signing.
+- `radroots_nostr_connect` supplies remote protocol state without owning this
+ SPI's host composition.
+- `radroots_sync` and `radroots_sdk` orchestrate authorized requests and
+ consume verified receipts.
+- CLI, Studio, mobile/FFI, and service hosts resolve actor provenance, choose
+ adapters, display authentication challenges, and own cancellation/runtime
+ behavior.
+
+Applications that only need ordinary Radroots operations should normally use
+`radroots` or `radroots_sdk`; implement this package directly when providing a
+new signer adapter or advanced host composition.
diff --git a/crates/signing/examples/host_signer.rs b/crates/signing/examples/host_signer.rs
@@ -0,0 +1,51 @@
+use radroots_event::{EventDraft, contract::AuthorRole};
+use radroots_identity::PublicKey;
+use radroots_protocol::runtime::v1::OperationId;
+use radroots_signing::{
+ Actor, Error, SignReceipt, SignRequest, Signer, SignerStatus,
+ actor::ActorSource,
+ error::Kind,
+ request::{CancellationPolicy, SignPolicy},
+ signer::BoxFuture,
+};
+
+struct HostSigner;
+
+impl Signer for HostSigner {
+ fn status(&self) -> BoxFuture<'_, Result<SignerStatus, Error>> {
+ Box::pin(async { Ok(SignerStatus::unavailable()) })
+ }
+
+ fn sign(&self, _request: SignRequest) -> BoxFuture<'_, Result<SignReceipt, Error>> {
+ Box::pin(async { Err(Error::new(Kind::SignerUnavailable)) })
+ }
+}
+
+fn main() {
+ let public_key =
+ PublicKey::from_hex("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
+ .expect("canonical public key");
+ let actor = Actor::new(
+ public_key,
+ ActorSource::ExplicitPublicKey,
+ [AuthorRole::Any],
+ )
+ .expect("validated actor");
+ let draft = EventDraft::new(
+ "radroots.social.geochat.v1",
+ 20_000,
+ 1_700_000_000,
+ Vec::new(),
+ "host-composed signing",
+ public_key.to_hex(),
+ )
+ .expect("frozen draft");
+ let policy = SignPolicy::new(1_700_000_030, CancellationPolicy::PreservePublishedRequest)
+ .expect("bounded policy");
+ let request =
+ SignRequest::new(OperationId::SyncPush, actor, draft, policy).expect("authorized request");
+
+ let signer: &dyn Signer = &HostSigner;
+ let future = signer.sign(request);
+ drop(future); // The composing host chooses and drives its async executor.
+}
diff --git a/crates/signing/tests/package_boundary.rs b/crates/signing/tests/package_boundary.rs
@@ -7,6 +7,9 @@ use radroots_signing::{
};
const MANIFEST: &str = include_str!("../Cargo.toml");
+const EXAMPLE: &str = include_str!("../examples/host_signer.rs");
+const PUBLIC_API: &str = include_str!("../../../docs/api/radroots_signing.txt");
+const README: &str = include_str!("../README.md");
const ROOT: &str = include_str!("../src/lib.rs");
#[test]
@@ -123,6 +126,68 @@ fn crate_root_declares_the_approved_module_skeleton() {
}
#[test]
+fn package_documentation_and_reviewed_api_baseline_are_complete() {
+ for required in [
+ "## Typical flow",
+ "## Host SPI contract",
+ "## Deadlines, cancellation, and commit points",
+ "## Serialization contract",
+ "## Security and side effects",
+ "## Features",
+ "## Intended consumers",
+ "radroots_crates_release_v1.md#8-radroots_signing",
+ "examples/host_signer.rs",
+ ] {
+ assert!(README.contains(required), "README is missing {required}");
+ }
+ for required in [
+ "impl Signer for HostSigner",
+ "fn status(&self) -> BoxFuture",
+ "fn sign(&self, _request: SignRequest) -> BoxFuture",
+ "let signer: &dyn Signer",
+ "drop(future)",
+ ] {
+ assert!(EXAMPLE.contains(required), "example is missing {required}");
+ }
+ for required in [
+ "pub mod radroots_signing::actor",
+ "pub mod radroots_signing::capability",
+ "pub mod radroots_signing::error",
+ "pub mod radroots_signing::receipt",
+ "pub mod radroots_signing::request",
+ "pub mod radroots_signing::signer",
+ "pub mod radroots_signing::status",
+ "pub trait radroots_signing::Signer",
+ ] {
+ assert!(
+ PUBLIC_API.contains(required),
+ "public API baseline is missing {required}"
+ );
+ }
+}
+
+#[test]
+fn every_public_module_has_crate_level_documentation() {
+ let source_root = Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
+ for module in [
+ "actor",
+ "capability",
+ "error",
+ "request",
+ "receipt",
+ "signer",
+ "status",
+ ] {
+ let path = source_root.join(format!("{module}.rs"));
+ let source = fs::read_to_string(&path).expect("read module source");
+ assert!(
+ source.starts_with("//! "),
+ "public module {module} must start with module documentation"
+ );
+ }
+}
+
+#[test]
fn production_sources_publish_only_the_approved_traits_and_no_host_stack() {
let source_root = Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
let mut sources = Vec::new();
diff --git a/docs/api/README.md b/docs/api/README.md
@@ -37,3 +37,4 @@ expand a package beyond its charter.
| `radroots_event` | [`radroots_event.txt`](radroots_event.txt) | [release V1 specification](../specs/radroots_crates_release_v1.md) |
| `radroots_event_codec` | [`radroots_event_codec.txt`](radroots_event_codec.txt) | [release V1 specification](../specs/radroots_crates_release_v1.md) |
| `radroots_trade` | [`radroots_trade.txt`](radroots_trade.txt) | [release V1 specification](../specs/radroots_crates_release_v1.md) |
+| `radroots_signing` | [`radroots_signing.txt`](radroots_signing.txt) | [release V1 specification](../specs/radroots_crates_release_v1.md) |
diff --git a/docs/api/radroots_signing.txt b/docs/api/radroots_signing.txt
@@ -0,0 +1,220 @@
+pub mod radroots_signing
+pub mod radroots_signing::actor
+#[non_exhaustive] pub enum radroots_signing::actor::ActorSelector
+pub radroots_signing::actor::ActorSelector::Account(radroots_identity::account::AccountId)
+pub radroots_signing::actor::ActorSelector::DraftExpectedPublicKey
+pub radroots_signing::actor::ActorSelector::PublicKey(radroots_identity::key::PublicKey)
+pub radroots_signing::actor::ActorSelector::SelectedAccount
+#[non_exhaustive] pub enum radroots_signing::actor::ActorSource
+pub radroots_signing::actor::ActorSource::ExplicitPublicKey
+pub radroots_signing::actor::ActorSource::LocalAccount(radroots_identity::account::AccountId)
+pub radroots_signing::actor::ActorSource::RemoteSigner(radroots_identity::account::AccountId)
+pub radroots_signing::actor::ActorSource::Service(radroots_identity::account::AccountId)
+impl radroots_signing::actor::ActorSource
+pub const fn radroots_signing::actor::ActorSource::account_id(self) -> core::option::Option<radroots_identity::account::AccountId>
+pub struct radroots_signing::actor::Actor
+impl radroots_signing::actor::Actor
+pub const fn radroots_signing::actor::Actor::account_id(&self) -> core::option::Option<radroots_identity::account::AccountId>
+pub fn radroots_signing::actor::Actor::from_public_key_hex<I>(&str, radroots_signing::actor::ActorSource, I) -> core::result::Result<Self, radroots_signing::error::Error> where I: core::iter::traits::collect::IntoIterator<Item = radroots_event::contract::registry_v7::AuthorRole>
+pub fn radroots_signing::actor::Actor::new<I>(radroots_identity::key::PublicKey, radroots_signing::actor::ActorSource, I) -> core::result::Result<Self, radroots_signing::error::Error> where I: core::iter::traits::collect::IntoIterator<Item = radroots_event::contract::registry_v7::AuthorRole>
+pub const fn radroots_signing::actor::Actor::public_key(&self) -> radroots_identity::key::PublicKey
+pub const fn radroots_signing::actor::Actor::roles(&self) -> &alloc::collections::btree::set::BTreeSet<radroots_event::contract::registry_v7::AuthorRole>
+pub fn radroots_signing::actor::Actor::satisfies(&self, radroots_event::contract::registry_v7::AuthorRole) -> bool
+pub const fn radroots_signing::actor::Actor::source(&self) -> radroots_signing::actor::ActorSource
+pub struct radroots_signing::actor::ActorResolutionRequest
+impl radroots_signing::actor::ActorResolutionRequest
+pub const fn radroots_signing::actor::ActorResolutionRequest::expected_public_key(&self) -> radroots_identity::key::PublicKey
+pub const fn radroots_signing::actor::ActorResolutionRequest::new(radroots_signing::actor::ActorSelector, radroots_event::contract::registry_v7::AuthorRole, radroots_identity::key::PublicKey) -> Self
+pub const fn radroots_signing::actor::ActorResolutionRequest::required_role(&self) -> radroots_event::contract::registry_v7::AuthorRole
+pub const fn radroots_signing::actor::ActorResolutionRequest::selector(&self) -> radroots_signing::actor::ActorSelector
+pub mod radroots_signing::capability
+#[non_exhaustive] pub enum radroots_signing::capability::CancellationSupport
+pub radroots_signing::capability::CancellationSupport::BeforeAndAfterPublication
+pub radroots_signing::capability::CancellationSupport::BeforePublication
+#[non_exhaustive] pub enum radroots_signing::capability::SignerKind
+pub radroots_signing::capability::SignerKind::HostMediated
+pub radroots_signing::capability::SignerKind::Local
+pub radroots_signing::capability::SignerKind::Remote
+#[non_exhaustive] pub struct radroots_signing::capability::SignerCapability
+impl radroots_signing::capability::SignerCapability
+pub const fn radroots_signing::capability::SignerCapability::cancellation(self) -> radroots_signing::capability::CancellationSupport
+pub const fn radroots_signing::capability::SignerCapability::kind(self) -> radroots_signing::capability::SignerKind
+pub const fn radroots_signing::capability::SignerCapability::may_require_authentication(self) -> bool
+pub const fn radroots_signing::capability::SignerCapability::new(radroots_signing::capability::SignerKind, radroots_signing::capability::CancellationSupport, bool, bool) -> Self
+pub const fn radroots_signing::capability::SignerCapability::reports_progress(self) -> bool
+pub mod radroots_signing::error
+#[non_exhaustive] pub enum radroots_signing::error::Kind
+pub radroots_signing::error::Kind::AuthorizationDenied
+pub radroots_signing::error::Kind::DeadlineExceeded
+pub radroots_signing::error::Kind::InternalError
+pub radroots_signing::error::Kind::InvalidArgument
+pub radroots_signing::error::Kind::SignerCancelled
+pub radroots_signing::error::Kind::SignerCapabilityMissing
+pub radroots_signing::error::Kind::SignerOutputInvalid
+pub radroots_signing::error::Kind::SignerRejected
+pub radroots_signing::error::Kind::SignerTimeout
+pub radroots_signing::error::Kind::SignerUnavailable
+impl radroots_signing::error::Kind
+pub const radroots_signing::error::Kind::ALL: &'static [Self]
+pub const fn radroots_signing::error::Kind::descriptor(self) -> radroots_signing::error::Descriptor
+pub struct radroots_signing::error::Descriptor
+impl radroots_signing::error::Descriptor
+pub const fn radroots_signing::error::Descriptor::class(self) -> radroots_protocol::error::v1::Class
+pub const fn radroots_signing::error::Descriptor::code(self) -> &'static str
+pub const fn radroots_signing::error::Descriptor::kind(self) -> radroots_signing::error::Kind
+pub const fn radroots_signing::error::Descriptor::known_code(self) -> radroots_protocol::error::v1::KnownCode
+pub const fn radroots_signing::error::Descriptor::message(self) -> &'static str
+pub const fn radroots_signing::error::Descriptor::recovery_actions(self) -> &'static [radroots_protocol::error::v1::RecoveryAction]
+pub const fn radroots_signing::error::Descriptor::retryable(self) -> bool
+pub struct radroots_signing::error::Error
+impl radroots_signing::error::Error
+pub const fn radroots_signing::error::Error::class(&self) -> radroots_protocol::error::v1::Class
+pub const fn radroots_signing::error::Error::code(&self) -> &'static str
+pub const fn radroots_signing::error::Error::descriptor(&self) -> radroots_signing::error::Descriptor
+pub const fn radroots_signing::error::Error::kind(&self) -> radroots_signing::error::Kind
+pub const fn radroots_signing::error::Error::new(radroots_signing::error::Kind) -> Self
+pub const fn radroots_signing::error::Error::recovery_actions(&self) -> &'static [radroots_protocol::error::v1::RecoveryAction]
+pub const fn radroots_signing::error::Error::retryable(&self) -> bool
+pub fn radroots_signing::error::Error::to_report(&self, core::option::Option<radroots_protocol::runtime::v1::OperationId>) -> radroots_protocol::error::v1::ErrorReport
+pub fn radroots_signing::error::Error::with_source<E>(radroots_signing::error::Kind, E) -> Self where E: core::error::Error + core::marker::Send + core::marker::Sync + 'static
+impl core::convert::From<&radroots_signing::error::Error> for radroots_protocol::error::v1::ErrorReport
+pub fn radroots_protocol::error::v1::ErrorReport::from(&radroots_signing::error::Error) -> Self
+impl core::error::Error for radroots_signing::error::Error
+pub fn radroots_signing::error::Error::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)>
+impl core::fmt::Debug for radroots_signing::error::Error
+pub fn radroots_signing::error::Error::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
+impl core::fmt::Display for radroots_signing::error::Error
+pub fn radroots_signing::error::Error::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
+pub const radroots_signing::error::CATALOG: &[radroots_signing::error::Descriptor]
+pub mod radroots_signing::receipt
+#[non_exhaustive] pub struct radroots_signing::receipt::SignReceipt
+impl radroots_signing::receipt::SignReceipt
+pub const fn radroots_signing::receipt::SignReceipt::completed_at_unix(&self) -> u64
+pub fn radroots_signing::receipt::SignReceipt::from_signed_event(&radroots_signing::request::SignRequest, radroots_event::draft::SignedEvent, u64) -> core::result::Result<Self, radroots_signing::error::Error>
+pub const fn radroots_signing::receipt::SignReceipt::operation_id(&self) -> radroots_protocol::runtime::v1::OperationId
+pub const fn radroots_signing::receipt::SignReceipt::signed_event(&self) -> &radroots_event::draft::SignedEvent
+impl core::fmt::Debug for radroots_signing::receipt::SignReceipt
+pub fn radroots_signing::receipt::SignReceipt::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
+pub mod radroots_signing::request
+#[non_exhaustive] pub enum radroots_signing::request::CancellationPolicy
+pub radroots_signing::request::CancellationPolicy::LocalCooperative
+pub radroots_signing::request::CancellationPolicy::PreservePublishedRequest
+#[non_exhaustive] pub struct radroots_signing::request::SignPolicy
+impl radroots_signing::request::SignPolicy
+pub const fn radroots_signing::request::SignPolicy::cancellation(self) -> radroots_signing::request::CancellationPolicy
+pub const fn radroots_signing::request::SignPolicy::deadline_unix(self) -> u64
+pub const fn radroots_signing::request::SignPolicy::new(u64, radroots_signing::request::CancellationPolicy) -> core::result::Result<Self, radroots_signing::error::Error>
+pub struct radroots_signing::request::SignRequest
+impl radroots_signing::request::SignRequest
+pub const fn radroots_signing::request::SignRequest::actor(&self) -> &radroots_signing::actor::Actor
+pub const fn radroots_signing::request::SignRequest::draft(&self) -> &radroots_event::draft::EventDraft
+pub fn radroots_signing::request::SignRequest::new(radroots_protocol::runtime::v1::OperationId, radroots_signing::actor::Actor, radroots_event::draft::EventDraft, radroots_signing::request::SignPolicy) -> core::result::Result<Self, radroots_signing::error::Error>
+pub const fn radroots_signing::request::SignRequest::operation_id(&self) -> radroots_protocol::runtime::v1::OperationId
+pub const fn radroots_signing::request::SignRequest::policy(&self) -> radroots_signing::request::SignPolicy
+pub fn radroots_signing::request::SignRequest::report_progress(&self, &radroots_signing::status::SignProgress)
+pub fn radroots_signing::request::SignRequest::with_progress_observer(self, alloc::sync::Arc<dyn radroots_signing::request::ProgressObserver>) -> Self
+impl core::fmt::Debug for radroots_signing::request::SignRequest
+pub fn radroots_signing::request::SignRequest::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
+pub trait radroots_signing::request::ProgressObserver: core::marker::Send + core::marker::Sync
+pub fn radroots_signing::request::ProgressObserver::on_progress(&self, &radroots_signing::status::SignProgress)
+pub mod radroots_signing::signer
+pub trait radroots_signing::signer::Signer: core::marker::Send + core::marker::Sync
+pub fn radroots_signing::signer::Signer::sign(&self, radroots_signing::request::SignRequest) -> radroots_signing::signer::BoxFuture<'_, core::result::Result<radroots_signing::receipt::SignReceipt, radroots_signing::error::Error>>
+pub fn radroots_signing::signer::Signer::status(&self) -> radroots_signing::signer::BoxFuture<'_, core::result::Result<radroots_signing::status::SignerStatus, radroots_signing::error::Error>>
+pub type radroots_signing::signer::BoxFuture<'a, T> = core::pin::Pin<alloc::boxed::Box<(dyn core::future::future::Future<Output = T> + core::marker::Send + 'a)>>
+pub mod radroots_signing::status
+#[non_exhaustive] pub enum radroots_signing::status::SignProgressStage
+pub radroots_signing::status::SignProgressStage::AwaitingAuthentication
+pub radroots_signing::status::SignProgressStage::AwaitingSignature
+pub radroots_signing::status::SignProgressStage::Complete
+pub radroots_signing::status::SignProgressStage::Queued
+pub radroots_signing::status::SignProgressStage::RequestPublished
+pub radroots_signing::status::SignProgressStage::Validating
+pub radroots_signing::status::SignProgressStage::VerifyingOutput
+#[non_exhaustive] pub enum radroots_signing::status::SignerAvailability
+pub radroots_signing::status::SignerAvailability::AwaitingAuthentication
+pub radroots_signing::status::SignerAvailability::Busy
+pub radroots_signing::status::SignerAvailability::Ready
+pub radroots_signing::status::SignerAvailability::Unavailable
+#[non_exhaustive] pub struct radroots_signing::status::AuthChallenge
+impl radroots_signing::status::AuthChallenge
+pub const fn radroots_signing::status::AuthChallenge::expires_at_unix(&self) -> core::option::Option<u64>
+pub fn radroots_signing::status::AuthChallenge::new(impl core::convert::Into<alloc::string::String>, u64, core::option::Option<u64>) -> core::result::Result<Self, radroots_signing::error::Error>
+pub const fn radroots_signing::status::AuthChallenge::required_at_unix(&self) -> u64
+pub fn radroots_signing::status::AuthChallenge::uri(&self) -> &str
+impl core::fmt::Debug for radroots_signing::status::AuthChallenge
+pub fn radroots_signing::status::AuthChallenge::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
+impl<'de> serde_core::de::Deserialize<'de> for radroots_signing::status::AuthChallenge
+pub fn radroots_signing::status::AuthChallenge::deserialize<D>(D) -> core::result::Result<Self, <D as serde_core::de::Deserializer>::Error> where D: serde_core::de::Deserializer<'de>
+#[non_exhaustive] pub struct radroots_signing::status::SignProgress
+impl radroots_signing::status::SignProgress
+pub const fn radroots_signing::status::SignProgress::authentication(radroots_signing::status::AuthChallenge) -> Self
+pub const fn radroots_signing::status::SignProgress::challenge(&self) -> core::option::Option<&radroots_signing::status::AuthChallenge>
+pub const fn radroots_signing::status::SignProgress::stage(radroots_signing::status::SignProgressStage) -> core::result::Result<Self, radroots_signing::error::Error>
+pub const fn radroots_signing::status::SignProgress::stage_value(&self) -> radroots_signing::status::SignProgressStage
+impl<'de> serde_core::de::Deserialize<'de> for radroots_signing::status::SignProgress
+pub fn radroots_signing::status::SignProgress::deserialize<D>(D) -> core::result::Result<Self, <D as serde_core::de::Deserializer>::Error> where D: serde_core::de::Deserializer<'de>
+#[non_exhaustive] pub struct radroots_signing::status::SignerStatus
+impl radroots_signing::status::SignerStatus
+pub const fn radroots_signing::status::SignerStatus::availability(&self) -> radroots_signing::status::SignerAvailability
+pub fn radroots_signing::status::SignerStatus::capabilities(&self) -> &[radroots_signing::capability::SignerCapability]
+pub fn radroots_signing::status::SignerStatus::new(radroots_signing::status::SignerAvailability, alloc::vec::Vec<radroots_signing::capability::SignerCapability>, core::option::Option<radroots_signing::status::SignProgress>) -> Self
+pub const fn radroots_signing::status::SignerStatus::progress(&self) -> core::option::Option<&radroots_signing::status::SignProgress>
+pub const fn radroots_signing::status::SignerStatus::unavailable() -> Self
+pub struct radroots_signing::Actor
+impl radroots_signing::actor::Actor
+pub const fn radroots_signing::actor::Actor::account_id(&self) -> core::option::Option<radroots_identity::account::AccountId>
+pub fn radroots_signing::actor::Actor::from_public_key_hex<I>(&str, radroots_signing::actor::ActorSource, I) -> core::result::Result<Self, radroots_signing::error::Error> where I: core::iter::traits::collect::IntoIterator<Item = radroots_event::contract::registry_v7::AuthorRole>
+pub fn radroots_signing::actor::Actor::new<I>(radroots_identity::key::PublicKey, radroots_signing::actor::ActorSource, I) -> core::result::Result<Self, radroots_signing::error::Error> where I: core::iter::traits::collect::IntoIterator<Item = radroots_event::contract::registry_v7::AuthorRole>
+pub const fn radroots_signing::actor::Actor::public_key(&self) -> radroots_identity::key::PublicKey
+pub const fn radroots_signing::actor::Actor::roles(&self) -> &alloc::collections::btree::set::BTreeSet<radroots_event::contract::registry_v7::AuthorRole>
+pub fn radroots_signing::actor::Actor::satisfies(&self, radroots_event::contract::registry_v7::AuthorRole) -> bool
+pub const fn radroots_signing::actor::Actor::source(&self) -> radroots_signing::actor::ActorSource
+pub struct radroots_signing::Error
+impl radroots_signing::error::Error
+pub const fn radroots_signing::error::Error::class(&self) -> radroots_protocol::error::v1::Class
+pub const fn radroots_signing::error::Error::code(&self) -> &'static str
+pub const fn radroots_signing::error::Error::descriptor(&self) -> radroots_signing::error::Descriptor
+pub const fn radroots_signing::error::Error::kind(&self) -> radroots_signing::error::Kind
+pub const fn radroots_signing::error::Error::new(radroots_signing::error::Kind) -> Self
+pub const fn radroots_signing::error::Error::recovery_actions(&self) -> &'static [radroots_protocol::error::v1::RecoveryAction]
+pub const fn radroots_signing::error::Error::retryable(&self) -> bool
+pub fn radroots_signing::error::Error::to_report(&self, core::option::Option<radroots_protocol::runtime::v1::OperationId>) -> radroots_protocol::error::v1::ErrorReport
+pub fn radroots_signing::error::Error::with_source<E>(radroots_signing::error::Kind, E) -> Self where E: core::error::Error + core::marker::Send + core::marker::Sync + 'static
+impl core::convert::From<&radroots_signing::error::Error> for radroots_protocol::error::v1::ErrorReport
+pub fn radroots_protocol::error::v1::ErrorReport::from(&radroots_signing::error::Error) -> Self
+impl core::error::Error for radroots_signing::error::Error
+pub fn radroots_signing::error::Error::source(&self) -> core::option::Option<&(dyn core::error::Error + 'static)>
+impl core::fmt::Debug for radroots_signing::error::Error
+pub fn radroots_signing::error::Error::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
+impl core::fmt::Display for radroots_signing::error::Error
+pub fn radroots_signing::error::Error::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
+#[non_exhaustive] pub struct radroots_signing::SignReceipt
+impl radroots_signing::receipt::SignReceipt
+pub const fn radroots_signing::receipt::SignReceipt::completed_at_unix(&self) -> u64
+pub fn radroots_signing::receipt::SignReceipt::from_signed_event(&radroots_signing::request::SignRequest, radroots_event::draft::SignedEvent, u64) -> core::result::Result<Self, radroots_signing::error::Error>
+pub const fn radroots_signing::receipt::SignReceipt::operation_id(&self) -> radroots_protocol::runtime::v1::OperationId
+pub const fn radroots_signing::receipt::SignReceipt::signed_event(&self) -> &radroots_event::draft::SignedEvent
+impl core::fmt::Debug for radroots_signing::receipt::SignReceipt
+pub fn radroots_signing::receipt::SignReceipt::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
+pub struct radroots_signing::SignRequest
+impl radroots_signing::request::SignRequest
+pub const fn radroots_signing::request::SignRequest::actor(&self) -> &radroots_signing::actor::Actor
+pub const fn radroots_signing::request::SignRequest::draft(&self) -> &radroots_event::draft::EventDraft
+pub fn radroots_signing::request::SignRequest::new(radroots_protocol::runtime::v1::OperationId, radroots_signing::actor::Actor, radroots_event::draft::EventDraft, radroots_signing::request::SignPolicy) -> core::result::Result<Self, radroots_signing::error::Error>
+pub const fn radroots_signing::request::SignRequest::operation_id(&self) -> radroots_protocol::runtime::v1::OperationId
+pub const fn radroots_signing::request::SignRequest::policy(&self) -> radroots_signing::request::SignPolicy
+pub fn radroots_signing::request::SignRequest::report_progress(&self, &radroots_signing::status::SignProgress)
+pub fn radroots_signing::request::SignRequest::with_progress_observer(self, alloc::sync::Arc<dyn radroots_signing::request::ProgressObserver>) -> Self
+impl core::fmt::Debug for radroots_signing::request::SignRequest
+pub fn radroots_signing::request::SignRequest::fmt(&self, &mut core::fmt::Formatter<'_>) -> core::fmt::Result
+#[non_exhaustive] pub struct radroots_signing::SignerStatus
+impl radroots_signing::status::SignerStatus
+pub const fn radroots_signing::status::SignerStatus::availability(&self) -> radroots_signing::status::SignerAvailability
+pub fn radroots_signing::status::SignerStatus::capabilities(&self) -> &[radroots_signing::capability::SignerCapability]
+pub fn radroots_signing::status::SignerStatus::new(radroots_signing::status::SignerAvailability, alloc::vec::Vec<radroots_signing::capability::SignerCapability>, core::option::Option<radroots_signing::status::SignProgress>) -> Self
+pub const fn radroots_signing::status::SignerStatus::progress(&self) -> core::option::Option<&radroots_signing::status::SignProgress>
+pub const fn radroots_signing::status::SignerStatus::unavailable() -> Self
+pub trait radroots_signing::Signer: core::marker::Send + core::marker::Sync
+pub fn radroots_signing::Signer::sign(&self, radroots_signing::request::SignRequest) -> radroots_signing::signer::BoxFuture<'_, core::result::Result<radroots_signing::receipt::SignReceipt, radroots_signing::error::Error>>
+pub fn radroots_signing::Signer::status(&self) -> radroots_signing::signer::BoxFuture<'_, core::result::Result<radroots_signing::status::SignerStatus, radroots_signing::error::Error>>