diff --git a/CHANGELOG.md b/CHANGELOG.md index f747adeae..05ed972bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,7 @@ All notable changes to OriginWeave are documented in this file. The format follo - Credential-free sensitive-handle lifecycle evidence binds issuance, exclusive expiry, bounded uses, observed resolution count, and revocation to the exact credential-free `OpaqueHandleOnly` sensitive-access receipt, preserving tenant, actor, task, field set, purpose, destination, classification, policy version, and decision time without storing opaque handle tokens or protected values. - Credential-free connection and redirect evidence containing canonical addresses, destination classes, target digests, hop numbers, and approved-address counts. - Credential-free verified TCP evidence containing the logical origin, requested socket, observed peer, destination class, successful attempt number, and per-attempt timeout. -- Standard `Display` and `std::error::Error` contracts for destination, redirect, digest, direct-network, TLS, and resource-budget failures, including preserved destination-policy, rustls, and operating-system sources where applicable. +- Standard `Display` and `std::error::Error` contracts for destination, redirect, evidence-digest, action-intent-digest, direct-network, TLS, and resource-budget failures, including preserved destination-policy, rustls, and operating-system sources where applicable. - Real loopback TCP integration proof plus deterministic timeout, refusal, retry, peer-inspection, peer-mismatch, canonicalization, IPv6 metadata, and single-use replay tests. - Real loopback rustls integration covering trusted DNS SAN, Common-Name fallback rejection, wrong-name and untrusted-root rejection, fixed-time expiry and not-yet-valid failures, exact IPv4 and IPv6 SANs, TLS 1.2/TLS 1.3, required and optional ALPN, and transport-origin binding. - Cumulative interactive-first RAM, VRAM, batch, local-model, admission, pause, and compositor-pressure mitigation plans, including active-consumer reduction at exact hard limits. @@ -102,4 +102,4 @@ All notable changes to OriginWeave are documented in this file. The format follo - The hourly product agent has no Git metadata or repository authority. A separate post-verification publisher opens one PR and cannot approve or merge it. - The unprivileged OpenCode user is restricted to loopback egress during model execution, preventing runner-wide allow-listed endpoints from becoming direct source-exfiltration channels. -[Unreleased]: https://github.com/ContextualWisdomLab/OriginWeave/compare/main...HEAD \ No newline at end of file +[Unreleased]: https://github.com/ContextualWisdomLab/OriginWeave/compare/main...HEAD diff --git a/crates/originweave-core/src/lib.rs b/crates/originweave-core/src/lib.rs index e33a7e7e5..c7e3d5b13 100644 --- a/crates/originweave-core/src/lib.rs +++ b/crates/originweave-core/src/lib.rs @@ -503,6 +503,18 @@ pub enum ActionIntentDigestError { InvalidFormat, } +impl fmt::Display for ActionIntentDigestError { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::InvalidFormat => formatter.write_str( + "action intent digest must be sha256: followed by 64 lowercase hexadecimal digits", + ), + } + } +} + +impl std::error::Error for ActionIntentDigestError {} + /// The browser execution mode that owns an action. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum SessionMode { diff --git a/crates/originweave-core/tests/action_intent_digest_error_contract.rs b/crates/originweave-core/tests/action_intent_digest_error_contract.rs new file mode 100644 index 000000000..ed5d731cd --- /dev/null +++ b/crates/originweave-core/tests/action_intent_digest_error_contract.rs @@ -0,0 +1,13 @@ +use std::error::Error as _; + +use originweave_core::ActionIntentDigestError; + +#[test] +fn action_intent_digest_error_exposes_standard_error_contract() { + let error = ActionIntentDigestError::InvalidFormat; + assert_eq!( + error.to_string(), + "action intent digest must be sha256: followed by 64 lowercase hexadecimal digits" + ); + assert!(error.source().is_none()); +}