cli

Command-line interface for Radroots
git clone https://radroots.dev/git/cli.git
Log | Files | Refs | README | LICENSE

commit c0b700cbf5d3ec4f14bd1330cd9c1c33797620ac
parent f52866fac56e3ce5754655405322d6430c5a5a53
Author: triesap <tyson@radroots.org>
Date:   Mon, 27 Apr 2026 23:09:45 +0000

cli: reconcile seller relay publish docs

- describe direct relay seller publish behavior in CLI docs
- add fast coverage for configured-relay publish attempts
- keep order submit and listing update documented as deferred paths
- update legacy write-plane provider wording for the active path

Diffstat:
Msrc/runtime/provider.rs | 13+++++--------
Mtests/signer_runtime_modes.rs | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 100 insertions(+), 8 deletions(-)

diff --git a/src/runtime/provider.rs b/src/runtime/provider.rs @@ -8,7 +8,7 @@ use crate::runtime::config::{ #[cfg(test)] use crate::runtime::hyf; -const WRITE_PLANE_UNAVAILABLE_DETAIL: &str = "actor-authored relay writes are unavailable until direct Nostr relay publishing is implemented"; +const WRITE_PLANE_UNAVAILABLE_DETAIL: &str = "legacy write-plane provider is unavailable; use seller publish commands with configured direct relays"; #[cfg(test)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -160,7 +160,7 @@ fn unavailable_write_plane_view() -> WritePlaneProviderView { binding_model: "direct_relay_publish".to_owned(), state: "unavailable".to_owned(), provenance: ProviderProvenance::Unavailable.as_str().to_owned(), - source: "direct relay publishing is not implemented".to_owned(), + source: "legacy write-plane provider is not active".to_owned(), target_kind: None, target: None, detail: WRITE_PLANE_UNAVAILABLE_DETAIL.to_owned(), @@ -344,17 +344,14 @@ mod tests { } #[test] - fn write_plane_is_unavailable_until_direct_relay_publish_lands() { + fn write_plane_provider_is_not_active_for_direct_relay_publish() { let view = resolve_write_plane_provider(&sample_config(Vec::new(), false)); assert_eq!(view.provider_runtime_id, "nostr_relay"); assert_eq!(view.binding_model, "direct_relay_publish"); assert_eq!(view.state, "unavailable"); assert_eq!(view.provenance, ProviderProvenance::Unavailable.as_str()); assert!(view.target.is_none()); - assert!( - view.detail - .contains("direct Nostr relay publishing is implemented") - ); + assert!(view.detail.contains("seller publish commands")); } #[test] @@ -363,7 +360,7 @@ mod tests { .expect_err("write plane target"); assert_eq!( error, - "actor-authored relay writes are unavailable until direct Nostr relay publishing is implemented" + "legacy write-plane provider is unavailable; use seller publish commands with configured direct relays" ); } diff --git a/tests/signer_runtime_modes.rs b/tests/signer_runtime_modes.rs @@ -641,6 +641,83 @@ fn local_farm_publish_fails_without_configured_relay() { } #[test] +fn local_seller_publish_commands_attempt_configured_direct_relay() { + let sandbox = RadrootsCliSandbox::new(); + sandbox.json_success(&["--format", "json", "account", "create"]); + let farm = sandbox.json_success(&[ + "--format", + "json", + "farm", + "create", + "--name", + "Green Farm", + "--location", + "farmstand", + "--country", + "US", + "--delivery-method", + "pickup", + ]); + let farm_d_tag = farm["result"]["config"]["farm_d_tag"] + .as_str() + .expect("farm d tag"); + let relay = "ws://127.0.0.1:9"; + + let (farm_output, farm_value) = sandbox.json_output(&[ + "--format", + "json", + "--relay", + relay, + "--approval-token", + "approve", + "farm", + "publish", + ]); + assert!(!farm_output.status.success()); + assert_direct_relay_connection_failure(&farm_value, "farm.publish", &["farm", "publish"]); + + let listing_file = create_listing_draft(&sandbox, "direct-relay-attempt"); + make_listing_publishable(&listing_file, farm_d_tag); + let listing_file_arg = listing_file.to_string_lossy(); + + let (publish_output, publish_value) = sandbox.json_output(&[ + "--format", + "json", + "--relay", + relay, + "--approval-token", + "approve", + "listing", + "publish", + listing_file_arg.as_ref(), + ]); + assert!(!publish_output.status.success()); + assert_direct_relay_connection_failure( + &publish_value, + "listing.publish", + &["listing", "publish"], + ); + + let (archive_output, archive_value) = sandbox.json_output(&[ + "--format", + "json", + "--relay", + relay, + "--approval-token", + "approve", + "listing", + "archive", + listing_file_arg.as_ref(), + ]); + assert!(!archive_output.status.success()); + assert_direct_relay_connection_failure( + &archive_value, + "listing.archive", + &["listing", "archive"], + ); +} + +#[test] fn watch_only_farm_publish_dry_run_fails_as_account_watch_only() { let sandbox = RadrootsCliSandbox::new(); let public_identity = identity_public(13); @@ -764,3 +841,21 @@ fn configure_myc_mode(sandbox: &RadrootsCliSandbox, executable: &Path) { toml_string(executable.display().to_string().as_str()) )); } + +fn assert_direct_relay_connection_failure( + value: &serde_json::Value, + operation_id: &str, + args: &[&str], +) { + assert_eq!(value["operation_id"], operation_id); + assert_eq!(value["result"], serde_json::Value::Null); + assert_eq!(value["errors"][0]["code"], "network_unavailable"); + assert_ne!(value["errors"][0]["code"], "operation_unavailable"); + assert_eq!(value["errors"][0]["detail"]["class"], "network"); + assert_contains( + &value["errors"][0]["message"], + "direct relay connection failed", + ); + assert_no_removed_command_reference(value, args); + assert_no_daemon_runtime_reference(value, args); +}