commit 87a54fd93c7c4d62b008acba73c51ee0d78f41ff
parent 5af1611cfc896a1ad9890e08b60dad36c5a5ab80
Author: triesap <tyson@radroots.org>
Date: Tue, 30 Jun 2026 20:05:50 +0000
docs: align grouped trade SDK surface
- document grouped trade product handles in the SDK README
- forbid root trade handle claims in README guards
- remove duplicate status and inert validation handle expectations
- guard product client handles against root escape methods
Diffstat:
2 files changed, 62 insertions(+), 20 deletions(-)
diff --git a/crates/sdk/README b/crates/sdk/README
@@ -41,12 +41,12 @@ transport owns signing. `push_outbox_with_adapter(...)` remains available for te
adapter-level substrate checks. `radrootsd-proxy` adds daemon-resolved publishing through
`publish.event`.
-`sdk.trades()` exposes local trade evidence ingestion and status projection APIs. Product workflow
-actions are split into role-specific handles: `sdk.trade_buyer()`, `sdk.trade_seller()`,
-`sdk.trade_status()`, `sdk.trade_resync()`, and `sdk.trade_validation()`. `sdk.trades().status(...)`
-and `sdk.trade_status().status(...)` accept `TradeStatusRequest` and read local projections; they
-return typed source, event count, limit state, event IDs, ambiguity candidates, eligibility,
-next-action, and reducer issue data. Status is not a network fetch.
+`sdk.trades()` exposes local trade evidence ingestion, status projection, and grouped product workflow
+handles. Product workflow actions use `sdk.trades().buyer()`, `sdk.trades().seller()`, and
+`sdk.trades().resync()`. `sdk.trades().status(...)` accepts `TradeStatusRequest` and reads local
+projections; it returns typed source, event count, limit state, event IDs, ambiguity candidates,
+eligibility, next-action, and reducer issue data. Status is not a network fetch. DVM proof requests and
+validation receipt ingestion use `sdk.dvm()`.
The `local-runtime` feature is the curated feature bundle for local product runtime consumers. It
enables `std`, `serde`, `serde_json`, `runtime`, `signer-adapters`, `relay-runtime`, and
diff --git a/crates/sdk/tests/source_boundary.rs b/crates/sdk/tests/source_boundary.rs
@@ -56,15 +56,37 @@ const FORBIDDEN_SDK_README_CONCEPTS: &[ForbiddenSdkConcept] = &[
pattern: "protocol::",
reason: "SDK docs must not advertise a public protocol workflow bypass",
},
+ ForbiddenSdkConcept {
+ pattern: "sdk.trade_buyer()",
+ reason: "SDK docs must use grouped trade product handles",
+ },
+ ForbiddenSdkConcept {
+ pattern: "sdk.trade_seller()",
+ reason: "SDK docs must use grouped trade product handles",
+ },
+ ForbiddenSdkConcept {
+ pattern: "sdk.trade_status()",
+ reason: "SDK docs must use sdk.trades().status(...) as the only product status entrypoint",
+ },
+ ForbiddenSdkConcept {
+ pattern: "sdk.trade_resync()",
+ reason: "SDK docs must use grouped trade product handles",
+ },
+ ForbiddenSdkConcept {
+ pattern: "sdk.trade_validation()",
+ reason: "SDK docs must use sdk.dvm() for validation receipt ingestion",
+ },
];
const REQUIRED_SDK_README_CONCEPTS: &[&str] = &[
"RadrootsClient::builder()",
"sdk.trades()",
"TradeStatusRequest",
- "sdk.trade_buyer()",
- "sdk.trade_seller()",
- "sdk.trade_status()",
+ "sdk.trades().buyer()",
+ "sdk.trades().seller()",
+ "sdk.trades().status(...)",
+ "sdk.trades().resync()",
+ "sdk.dvm()",
];
const REQUIRED_TRADE_RUNTIME_EXPORTS: &[&str] = &[
@@ -234,10 +256,21 @@ const REQUIRED_TRADE_SELLER_CLIENT_METHODS: &[&str] = &[
"pub async fn propose_revision(",
];
-const REQUIRED_TRADE_STATUS_CLIENT_METHODS: &[&str] = &["pub async fn status("];
-
const REQUIRED_TRADE_RESYNC_CLIENT_METHODS: &[&str] = &["pub async fn resync("];
+const FORBIDDEN_PRODUCT_CLIENT_HANDLES: &[&str] = &[
+ "TradeStatusClient",
+ "TradeValidationClient",
+ "pub struct TradeStatusClient",
+ "pub struct TradeValidationClient",
+];
+
+const FORBIDDEN_PRODUCT_CLIENT_METHODS: &[&str] = &[
+ "pub fn status_client(",
+ "pub fn validation(",
+ "pub fn root(&self) -> &'client RadrootsClient",
+];
+
const FORBIDDEN_ORDER_RUNTIME_PUBLIC_EXPORTS: &[&str] = &[
"CheckoutClient",
"EscrowClient",
@@ -673,13 +706,6 @@ fn trade_product_facade_methods_are_inventory_guarded() {
);
}
- for method in REQUIRED_TRADE_STATUS_CLIENT_METHODS {
- assert!(
- source.contains(method),
- "TradeStatusClient must expose product workflow method `{method}`"
- );
- }
-
for method in REQUIRED_TRADE_RESYNC_CLIENT_METHODS {
assert!(
source.contains(method),
@@ -751,8 +777,6 @@ fn product_clients_remain_thin_sdk_handles() {
"TradeBuyerClient",
"TradeResyncClient",
"TradeSellerClient",
- "TradeStatusClient",
- "TradeValidationClient",
"TradesClient",
] {
assert!(
@@ -764,6 +788,24 @@ fn product_clients_remain_thin_sdk_handles() {
"product_clients.rs must define thin handle `{client}`"
);
}
+
+ for forbidden in FORBIDDEN_PRODUCT_CLIENT_HANDLES {
+ assert!(
+ !lib_source.contains(forbidden),
+ "src/lib.rs must not export removed product client handle `{forbidden}`"
+ );
+ assert!(
+ !clients_source.contains(forbidden),
+ "product_clients.rs must not define removed product client handle `{forbidden}`"
+ );
+ }
+
+ for forbidden in FORBIDDEN_PRODUCT_CLIENT_METHODS {
+ assert!(
+ !clients_source.contains(forbidden),
+ "product_clients.rs must not expose removed product client method `{forbidden}`"
+ );
+ }
}
#[test]