cli

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

commit 44ab15546bca8034df7f70408d0b977479dbb203
parent c03413fad3b6ff2d1311267e4c6fd343832f66f6
Author: triesap <tyson@radroots.org>
Date:   Fri, 26 Jun 2026 08:23:29 +0000

cli: align with RadrootsClient locality

- Switch CLI runtime calls to RadrootsClient and trades().
- Require public city/country/geohash locality across farm and listing flows.
- Map trade workflow status through pending RHI and committed states.
- Validate with full CLI all-feature tests and stale API scans.

Diffstat:
MCargo.lock | 18++++++++++++++++++
Msrc/cli/farm.rs | 2++
Msrc/cli/global.rs | 2++
Msrc/cli/input.rs | 1+
Msrc/ops/exec/farm.rs | 2++
Msrc/runtime/farm.rs | 64+++++++++++++++++++++++++++++++++++++++++++++++-----------------
Msrc/runtime/farm_config.rs | 58++++++++++++++++++++++++++++++++++++++++++++++------------
Msrc/runtime/listing.rs | 22++++++++++++++--------
Msrc/runtime/order.rs | 173++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msrc/runtime/order/sdk_status.rs | 9+++++++--
Msrc/runtime/sdk.rs | 18+++++++++---------
Msrc/runtime/store.rs | 10+++++-----
Msrc/view/runtime.rs | 4++--
Mtests/signer_runtime_modes.rs | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtests/support/mod.rs | 42++++++++++++++++++++++++++++++++++++++++--
Mtests/target_cli.rs | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16 files changed, 448 insertions(+), 106 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -3696,6 +3696,21 @@ dependencies = [ ] [[package]] +name = "radroots_geocoder" +version = "0.1.0-alpha.2" +dependencies = [ + "hex", + "radroots_runtime_paths", + "reqwest", + "rusqlite", + "serde", + "sha2", + "tempfile", + "thiserror 1.0.69", + "url", +] + +[[package]] name = "radroots_identity" version = "0.1.0-alpha.2" dependencies = [ @@ -3920,6 +3935,7 @@ dependencies = [ "radroots_event_store", "radroots_events", "radroots_events_codec", + "radroots_geocoder", "radroots_identity", "radroots_nostr", "radroots_nostr_connect", @@ -3927,6 +3943,7 @@ dependencies = [ "radroots_outbox", "radroots_publish_proxy_protocol", "radroots_relay_transport", + "radroots_runtime_paths", "radroots_trade", "reqwest", "serde", @@ -4172,6 +4189,7 @@ checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64 0.22.1", "bytes", + "futures-channel", "futures-core", "futures-util", "http", diff --git a/src/cli/farm.rs b/src/cli/farm.rs @@ -42,6 +42,8 @@ pub struct FarmCreateArgs { pub region: Option<String>, #[arg(long)] pub country: Option<String>, + #[arg(long)] + pub geohash: Option<String>, #[arg(long = "delivery-method")] pub delivery_method: Option<String>, } diff --git a/src/cli/global.rs b/src/cli/global.rs @@ -92,6 +92,7 @@ pub enum FarmFieldArg { City, Region, Country, + Geohash, Delivery, } @@ -114,6 +115,7 @@ pub struct FarmCreateArgs { pub city: Option<String>, pub region: Option<String>, pub country: Option<String>, + pub geohash: Option<String>, pub delivery_method: Option<String>, } diff --git a/src/cli/input.rs b/src/cli/input.rs @@ -90,6 +90,7 @@ pub fn target_operation_input(command: &TargetCommand) -> OperationData { insert_string(&mut input, "city", &args.city); insert_string(&mut input, "region", &args.region); insert_string(&mut input, "country", &args.country); + insert_string(&mut input, "geohash", &args.geohash); insert_string(&mut input, "delivery_method", &args.delivery_method); } FarmCommand::Rebind(args) => { diff --git a/src/ops/exec/farm.rs b/src/ops/exec/farm.rs @@ -47,6 +47,7 @@ impl OperationService<FarmCreateRequest> for FarmOperationService<'_> { city: string_input(&request, "city"), region: string_input(&request, "region"), country: string_input(&request, "country"), + geohash: string_input(&request, "geohash"), delivery_method: string_input(&request, "delivery_method"), }; if request.context.dry_run { @@ -241,6 +242,7 @@ fn location_field( Some("city") => Ok(FarmFieldArg::City), Some("region") => Ok(FarmFieldArg::Region), Some("country") => Ok(FarmFieldArg::Country), + Some("geohash") => Ok(FarmFieldArg::Geohash), Some(other) => Err(invalid_input( request.operation_id(), format!("location field `{other}` is not supported"), diff --git a/src/runtime/farm.rs b/src/runtime/farm.rs @@ -3,9 +3,9 @@ use std::time::{SystemTime, UNIX_EPOCH}; use radroots_authority::RadrootsActorContext; use radroots_events::contract::RadrootsActorRole; -use radroots_events::farm::{RadrootsFarm, RadrootsFarmLocation}; +use radroots_events::farm::{RadrootsFarm, RadrootsFarmPublicLocation}; use radroots_events::kinds::{KIND_FARM, KIND_PROFILE}; -use radroots_events::listing::RadrootsListingLocation; +use radroots_events::listing::RadrootsListingPublicLocation; use radroots_events::profile::{RadrootsProfile, RadrootsProfileType}; use radroots_events_codec::d_tag::is_d_tag_base64url; use radroots_events_codec::profile::encode::to_wire_parts_with_profile_type; @@ -1289,6 +1289,7 @@ fn init_document( let existing_city = existing_city(existing_document); let existing_region = existing_region(existing_document); let existing_country = existing_country(existing_document); + let existing_geohash = existing_geohash(existing_document); let existing_delivery = existing_delivery_method(existing_document); let name = optional_arg_or_existing(args.name.as_ref(), existing_name.as_ref()) .or_else(|| draft_name_from_account(account)) @@ -1320,6 +1321,8 @@ fn init_document( let city = optional_arg_or_existing(args.city.as_ref(), existing_city.as_ref()); let region = optional_arg_or_existing(args.region.as_ref(), existing_region.as_ref()); let country = optional_arg_or_existing(args.country.as_ref(), existing_country.as_ref()); + let geohash = optional_arg_or_existing(args.geohash.as_ref(), existing_geohash.as_ref()) + .unwrap_or_default(); let delivery_method = optional_arg_or_existing(args.delivery_method.as_ref(), existing_delivery.as_ref()) .unwrap_or_default(); @@ -1351,25 +1354,23 @@ fn init_document( website, picture, banner, - location: Some(RadrootsFarmLocation { - primary: non_empty(location_primary.as_str()), + location: Some(RadrootsFarmPublicLocation { + primary: location_primary.clone(), city: city.clone(), region: region.clone(), country: country.clone(), - gcs: None, + geohash: geohash.clone(), }), tags: None, }, listing_defaults: FarmListingDefaults { delivery_method, - location: RadrootsListingLocation { + location: RadrootsListingPublicLocation { primary: location_primary, city, region, country, - lat: None, - lng: None, - geohash: None, + geohash, }, }, publication, @@ -1483,7 +1484,10 @@ fn missing_blocks_listing_defaults(missing: &[FarmMissingField]) -> bool { missing.iter().any(|field| { matches!( field, - FarmMissingField::Location | FarmMissingField::Delivery + FarmMissingField::Location + | FarmMissingField::City + | FarmMissingField::Delivery + | FarmMissingField::Geohash ) }) } @@ -1508,12 +1512,18 @@ fn missing_field_actions(missing: &[FarmMissingField]) -> Vec<String> { "radroots farm set location \"San Francisco, CA\"", ); } + FarmMissingField::City => { + push_action(&mut actions, "radroots farm set city \"San Francisco\""); + } FarmMissingField::Delivery => { push_action(&mut actions, "radroots farm set delivery pickup"); } FarmMissingField::Country => { push_action(&mut actions, "radroots farm set country US"); } + FarmMissingField::Geohash => { + push_action(&mut actions, "radroots farm set geohash 9q8yy"); + } } } actions @@ -1537,6 +1547,7 @@ fn human_field_name(field: FarmFieldArg) -> &'static str { FarmFieldArg::City => "City", FarmFieldArg::Region => "Region", FarmFieldArg::Country => "Country", + FarmFieldArg::Geohash => "Geohash", FarmFieldArg::Delivery => "Delivery", } } @@ -1580,7 +1591,7 @@ fn apply_field_update( } FarmFieldArg::Location => { document.listing_defaults.location.primary = value.clone(); - ensure_farm_location(document).primary = Some(value); + ensure_farm_location(document).primary = value; } FarmFieldArg::City => { document.listing_defaults.location.city = Some(value.clone()); @@ -1594,6 +1605,10 @@ fn apply_field_update( document.listing_defaults.location.country = Some(value.clone()); ensure_farm_location(document).country = Some(value); } + FarmFieldArg::Geohash => { + document.listing_defaults.location.geohash = value.clone(); + ensure_farm_location(document).geohash = value; + } FarmFieldArg::Delivery => { document.listing_defaults.delivery_method = value; } @@ -1601,20 +1616,21 @@ fn apply_field_update( Ok(()) } -fn ensure_farm_location(document: &mut FarmConfigDocument) -> &mut RadrootsFarmLocation { - let primary = non_empty(document.listing_defaults.location.primary.as_str()); +fn ensure_farm_location(document: &mut FarmConfigDocument) -> &mut RadrootsFarmPublicLocation { + let primary = document.listing_defaults.location.primary.clone(); let city = document.listing_defaults.location.city.clone(); let region = document.listing_defaults.location.region.clone(); let country = document.listing_defaults.location.country.clone(); + let geohash = document.listing_defaults.location.geohash.clone(); document .farm .location - .get_or_insert_with(|| RadrootsFarmLocation { + .get_or_insert_with(|| RadrootsFarmPublicLocation { primary, city, region, country, - gcs: None, + geohash, }) } @@ -1805,6 +1821,21 @@ fn existing_country(existing_document: Option<&FarmConfigDocument>) -> Option<St }) } +fn existing_geohash(existing_document: Option<&FarmConfigDocument>) -> Option<String> { + existing_document + .and_then(|document| { + document + .farm + .location + .as_ref() + .and_then(|location| non_empty(location.geohash.as_str())) + }) + .or_else(|| { + existing_document + .and_then(|document| non_empty(document.listing_defaults.location.geohash.as_str())) + }) +} + fn existing_delivery_method(existing_document: Option<&FarmConfigDocument>) -> Option<String> { existing_document .and_then(|document| non_empty(document.listing_defaults.delivery_method.as_str())) @@ -1820,8 +1851,7 @@ fn resolved_location_primary(document: &FarmConfigDocument) -> Option<String> { .farm .location .as_ref() - .and_then(|location| location.primary.as_deref()) - .and_then(non_empty) + .and_then(|location| non_empty(location.primary.as_str())) }) } diff --git a/src/runtime/farm_config.rs b/src/runtime/farm_config.rs @@ -2,7 +2,7 @@ use std::fs; use std::path::{Path, PathBuf}; use radroots_events::farm::RadrootsFarm; -use radroots_events::listing::{RadrootsListingDeliveryMethod, RadrootsListingLocation}; +use radroots_events::listing::{RadrootsListingDeliveryMethod, RadrootsListingPublicLocation}; use radroots_events::profile::RadrootsProfile; use radroots_events_codec::d_tag::is_d_tag_base64url; use serde::{Deserialize, Serialize}; @@ -53,7 +53,7 @@ pub struct FarmConfigSelection { #[serde(deny_unknown_fields)] pub struct FarmListingDefaults { pub delivery_method: String, - pub location: RadrootsListingLocation, + pub location: RadrootsListingPublicLocation, } impl FarmListingDefaults { @@ -86,8 +86,10 @@ pub struct ResolvedFarmConfig { pub enum FarmMissingField { Name, Location, + City, Delivery, Country, + Geohash, } impl FarmMissingField { @@ -95,8 +97,10 @@ impl FarmMissingField { match self { Self::Name => "Farm name", Self::Location => "Location", + Self::City => "City", Self::Delivery => "Delivery method", Self::Country => "Country", + Self::Geohash => "Geohash", } } } @@ -271,6 +275,9 @@ pub fn missing_fields(document: &FarmConfigDocument) -> Vec<FarmMissingField> { if !location_present { missing.push(FarmMissingField::Location); } + if location_present && location_city(document).is_none() { + missing.push(FarmMissingField::City); + } if trimmed(document.listing_defaults.delivery_method.as_str()).is_empty() { missing.push(FarmMissingField::Delivery); @@ -279,6 +286,9 @@ pub fn missing_fields(document: &FarmConfigDocument) -> Vec<FarmMissingField> { if location_present && location_country(document).is_none() { missing.push(FarmMissingField::Country); } + if location_present && location_geohash(document).is_none() { + missing.push(FarmMissingField::Geohash); + } missing } @@ -294,8 +304,7 @@ fn location_primary(document: &FarmConfigDocument) -> Option<&str> { .farm .location .as_ref() - .and_then(|location| location.primary.as_deref()) - .and_then(non_empty_ref) + .and_then(|location| non_empty_ref(location.primary.as_str())) }) } @@ -316,6 +325,33 @@ fn location_country(document: &FarmConfigDocument) -> Option<&str> { }) } +fn location_city(document: &FarmConfigDocument) -> Option<&str> { + document + .listing_defaults + .location + .city + .as_deref() + .and_then(non_empty_ref) + .or_else(|| { + document + .farm + .location + .as_ref() + .and_then(|location| location.city.as_deref()) + .and_then(non_empty_ref) + }) +} + +fn location_geohash(document: &FarmConfigDocument) -> Option<&str> { + non_empty_ref(document.listing_defaults.location.geohash.as_str()).or_else(|| { + document + .farm + .location + .as_ref() + .and_then(|location| non_empty_ref(location.geohash.as_str())) + }) +} + fn parse_delivery_method(value: &str) -> Result<RadrootsListingDeliveryMethod, RuntimeError> { let method = trimmed(value); if method.is_empty() { @@ -352,7 +388,7 @@ mod tests { use std::path::PathBuf; - use radroots_events::farm::RadrootsFarmLocation; + use radroots_events::farm::RadrootsFarmPublicLocation; use tempfile::tempdir; fn sample_paths(profile: &str, root: &Path) -> PathsConfig { @@ -407,25 +443,23 @@ mod tests { website: Some("https://example.invalid/la-huerta".to_owned()), picture: None, banner: None, - location: Some(RadrootsFarmLocation { - primary: Some("San Francisco, CA".to_owned()), + location: Some(RadrootsFarmPublicLocation { + primary: "San Francisco, CA".to_owned(), city: Some("San Francisco".to_owned()), region: Some("CA".to_owned()), country: Some("US".to_owned()), - gcs: None, + geohash: "9q8yy".to_owned(), }), tags: None, }, listing_defaults: FarmListingDefaults { delivery_method: "pickup".to_owned(), - location: RadrootsListingLocation { + location: RadrootsListingPublicLocation { primary: "San Francisco, CA".to_owned(), city: Some("San Francisco".to_owned()), region: Some("CA".to_owned()), country: Some("US".to_owned()), - lat: None, - lng: None, - geohash: None, + geohash: "9q8yy".to_owned(), }, }, publication: FarmPublicationStatus::default(), diff --git a/src/runtime/listing.rs b/src/runtime/listing.rs @@ -17,7 +17,7 @@ use radroots_events::ids::{RadrootsDTag, RadrootsInventoryBinId}; use radroots_events::kinds::{KIND_LISTING, KIND_LISTING_DRAFT}; use radroots_events::listing::{ RadrootsListing, RadrootsListingAvailability, RadrootsListingBin, - RadrootsListingDeliveryMethod, RadrootsListingLocation, RadrootsListingProduct, + RadrootsListingDeliveryMethod, RadrootsListingProduct, RadrootsListingPublicLocation, RadrootsListingStatus, }; use radroots_events::trade_validation::RadrootsTradeValidationListingError; @@ -181,6 +181,7 @@ struct ListingDraftLocation { region: Option<String>, #[serde(default, skip_serializing_if = "Option::is_none")] country: Option<String>, + geohash: String, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -417,6 +418,7 @@ fn build_listing_draft( city: None, region: None, country: None, + geohash: String::new(), }), discounts: listing_discount_drafts_from_args(args), }; @@ -2537,15 +2539,13 @@ fn build_delivery_method( }) } -fn build_location(draft: &ListingDraftDocument) -> RadrootsListingLocation { - RadrootsListingLocation { +fn build_location(draft: &ListingDraftDocument) -> RadrootsListingPublicLocation { + RadrootsListingPublicLocation { primary: draft.location.primary.trim().to_owned(), city: draft.location.city.clone().and_then(non_empty), region: draft.location.region.clone().and_then(non_empty), country: draft.location.country.clone().and_then(non_empty), - lat: None, - lng: None, - geohash: None, + geohash: draft.location.geohash.trim().to_owned(), } } @@ -2927,7 +2927,10 @@ fn authoring_defaults(config: &RuntimeConfig) -> Result<ListingAuthoringDefaults defaults.farm_defaults_ready = !draft_missing.iter().any(|field| { matches!( field, - farm_config::FarmMissingField::Location | farm_config::FarmMissingField::Delivery + farm_config::FarmMissingField::Location + | farm_config::FarmMissingField::City + | farm_config::FarmMissingField::Delivery + | farm_config::FarmMissingField::Geohash ) }); if defaults.farm_defaults_ready { @@ -2947,12 +2950,13 @@ fn authoring_defaults(config: &RuntimeConfig) -> Result<ListingAuthoringDefaults Ok(defaults) } -fn draft_location_from_model(location: &RadrootsListingLocation) -> ListingDraftLocation { +fn draft_location_from_model(location: &RadrootsListingPublicLocation) -> ListingDraftLocation { ListingDraftLocation { primary: location.primary.clone(), city: location.city.clone(), region: location.region.clone(), country: location.country.clone(), + geohash: location.geohash.clone(), } } @@ -3257,6 +3261,7 @@ mod tests { city: None, region: None, country: None, + geohash: "dnqwy".to_owned(), }, discounts: Vec::new(), }; @@ -3312,6 +3317,7 @@ mod tests { city: None, region: None, country: None, + geohash: "dnqwy".to_owned(), }, discounts: vec![super::ListingDraftDiscount { id: "discount_farmstand".to_owned(), diff --git a/src/runtime/order.rs b/src/runtime/order.rs @@ -79,10 +79,11 @@ use radroots_trade::order::{ RadrootsListingInventoryAccountingProjection, RadrootsListingInventoryBinAvailability, RadrootsOrderCancellationRecord, RadrootsOrderDecisionRecord, RadrootsOrderIssue, RadrootsOrderReductionInputs, RadrootsOrderRequestRecord, RadrootsOrderRevisionDecisionRecord, - RadrootsOrderRevisionProposalRecord, RadrootsOrderStatus, - canonicalize_order_decision_for_signer, canonicalize_order_request_for_signer, - reduce_listing_inventory_accounting, reduce_order_events, + RadrootsOrderRevisionProposalRecord, canonicalize_order_decision_for_signer, + canonicalize_order_request_for_signer, reduce_listing_inventory_accounting, + reduce_order_events, }; +use radroots_trade::workflow::RadrootsTradeWorkflowState; use serde::{Deserialize, Serialize}; use serde_json::{Value, json}; @@ -1795,7 +1796,7 @@ pub fn status( ) -> Result<OrderStatusView, CliSdkAdapterError> { let request = OrderStatusRequest::parse(args.key.as_str())?; let session = CliSdkSession::connect(config)?; - let receipt = session.block_on(session.sdk().orders().status(request))?; + let receipt = session.block_on(session.sdk().trades().status(request))?; Ok(sdk_order_status_view(receipt)) } @@ -2776,23 +2777,28 @@ fn order_revision_proposals_from_events( OrderRevisionProposalCandidates { records, issues } } -fn active_order_status_state(status: &RadrootsOrderStatus) -> &'static str { +fn active_order_status_state(status: &RadrootsTradeWorkflowState) -> &'static str { match status { - RadrootsOrderStatus::Missing => "missing", - RadrootsOrderStatus::Requested => "requested", - RadrootsOrderStatus::Accepted => "accepted", - RadrootsOrderStatus::Declined => "declined", - RadrootsOrderStatus::Cancelled => "cancelled", - RadrootsOrderStatus::Invalid => "invalid", + RadrootsTradeWorkflowState::Missing => "missing", + RadrootsTradeWorkflowState::Requested => "requested", + RadrootsTradeWorkflowState::RevisionProposed => "revision_proposed", + RadrootsTradeWorkflowState::AgreedPendingRhi => "pending_rhi", + RadrootsTradeWorkflowState::Committed => "committed", + RadrootsTradeWorkflowState::Declined => "declined", + RadrootsTradeWorkflowState::Cancelled => "cancelled", + RadrootsTradeWorkflowState::Invalid => "invalid", } } -fn active_order_status_reason(status: &RadrootsOrderStatus, order_id: &str) -> Option<String> { +fn active_order_status_reason( + status: &RadrootsTradeWorkflowState, + order_id: &str, +) -> Option<String> { match status { - RadrootsOrderStatus::Missing => { + RadrootsTradeWorkflowState::Missing => { Some(format!("no active order events matched `{order_id}`")) } - RadrootsOrderStatus::Invalid => Some(format!( + RadrootsTradeWorkflowState::Invalid => Some(format!( "active order events for `{order_id}` failed reducer validation" )), _ => None, @@ -2800,7 +2806,7 @@ fn active_order_status_reason(status: &RadrootsOrderStatus, order_id: &str) -> O } fn order_status_inventory_view( - status: &RadrootsOrderStatus, + status: &RadrootsTradeWorkflowState, listing_event_id: Option<String>, decision_event_id: Option<&RadrootsEventId>, decisions: &[RadrootsOrderDecisionRecord], @@ -2824,7 +2830,7 @@ fn order_status_inventory_view( .collect::<Vec<_>>(); match status { - RadrootsOrderStatus::Accepted => { + RadrootsTradeWorkflowState::AgreedPendingRhi | RadrootsTradeWorkflowState::Committed => { let bins = decision_event_id .and_then(|event_id| { decisions @@ -2835,7 +2841,10 @@ fn order_status_inventory_view( .unwrap_or_default(); Some(OrderInventoryView { state: if inventory_issues.is_empty() { - "reserved".to_owned() + match status { + RadrootsTradeWorkflowState::Committed => "committed".to_owned(), + _ => "reserved".to_owned(), + } } else { "invalid".to_owned() }, @@ -2845,7 +2854,7 @@ fn order_status_inventory_view( issues: inventory_issues, }) } - RadrootsOrderStatus::Cancelled => Some(OrderInventoryView { + RadrootsTradeWorkflowState::Cancelled => Some(OrderInventoryView { state: if decision_event_id.is_some() { "released".to_owned() } else { @@ -2856,26 +2865,28 @@ fn order_status_inventory_view( bins: Vec::new(), issues: inventory_issues, }), - RadrootsOrderStatus::Declined => Some(OrderInventoryView { + RadrootsTradeWorkflowState::Declined => Some(OrderInventoryView { state: "not_reserved".to_owned(), listing_event_id, commitment_valid: true, bins: Vec::new(), issues: inventory_issues, }), - RadrootsOrderStatus::Invalid if !inventory_issues.is_empty() => Some(OrderInventoryView { - state: "invalid".to_owned(), - listing_event_id, - commitment_valid: false, - bins: Vec::new(), - issues: inventory_issues, - }), + RadrootsTradeWorkflowState::Invalid if !inventory_issues.is_empty() => { + Some(OrderInventoryView { + state: "invalid".to_owned(), + listing_event_id, + commitment_valid: false, + bins: Vec::new(), + issues: inventory_issues, + }) + } _ => None, } } fn order_status_lifecycle_view( - status: &RadrootsOrderStatus, + status: &RadrootsTradeWorkflowState, request_event_id: Option<String>, last_event_id: Option<String>, cancellation_event_id: Option<String>, @@ -2887,9 +2898,10 @@ fn order_status_lifecycle_view( let phase = order_status_lifecycle_phase(status).to_owned(); let terminal = matches!( status, - RadrootsOrderStatus::Accepted - | RadrootsOrderStatus::Cancelled - | RadrootsOrderStatus::Invalid + RadrootsTradeWorkflowState::Committed + | RadrootsTradeWorkflowState::Declined + | RadrootsTradeWorkflowState::Cancelled + | RadrootsTradeWorkflowState::Invalid ); let cancellation = cancellation_event_id @@ -2970,14 +2982,16 @@ fn order_status_revision_view_from_decision( } } -fn order_status_lifecycle_phase(status: &RadrootsOrderStatus) -> &'static str { +fn order_status_lifecycle_phase(status: &RadrootsTradeWorkflowState) -> &'static str { match status { - RadrootsOrderStatus::Missing => "missing", - RadrootsOrderStatus::Requested => "requested", - RadrootsOrderStatus::Accepted => "accepted", - RadrootsOrderStatus::Declined => "declined", - RadrootsOrderStatus::Cancelled => "cancelled", - RadrootsOrderStatus::Invalid => "invalid", + RadrootsTradeWorkflowState::Missing => "missing", + RadrootsTradeWorkflowState::Requested => "requested", + RadrootsTradeWorkflowState::RevisionProposed => "revision_proposed", + RadrootsTradeWorkflowState::AgreedPendingRhi => "pending_rhi", + RadrootsTradeWorkflowState::Committed => "committed", + RadrootsTradeWorkflowState::Declined => "declined", + RadrootsTradeWorkflowState::Cancelled => "cancelled", + RadrootsTradeWorkflowState::Invalid => "invalid", } } @@ -3334,6 +3348,67 @@ fn active_order_reducer_issue_view(issue_value: RadrootsOrderIssue) -> OrderIssu "active order reducer reported cancellation previous mismatch", vec![event_id], ), + RadrootsOrderIssue::ValidationReceiptWithoutPendingAgreement { event_id } => { + issue_with_events( + "validation_receipt_without_pending_agreement", + "validation_receipt_event_id", + "active order reducer reported validation receipt without pending agreement", + vec![event_id], + ) + } + RadrootsOrderIssue::ValidationReceiptOrderIdMismatch { event_id } => issue_with_events( + "validation_receipt_order_id_mismatch", + "order_id", + "active order reducer reported validation receipt order id mismatch", + vec![event_id], + ), + RadrootsOrderIssue::ValidationReceiptTypeMismatch { event_id } => issue_with_events( + "validation_receipt_type_mismatch", + "validation_receipt_type", + "active order reducer reported validation receipt type mismatch", + vec![event_id], + ), + RadrootsOrderIssue::ValidationReceiptRootMismatch { event_id } => issue_with_events( + "validation_receipt_root_mismatch", + "root_event_id", + "active order reducer reported validation receipt root mismatch", + vec![event_id], + ), + RadrootsOrderIssue::ValidationReceiptTargetMismatch { event_id } => issue_with_events( + "validation_receipt_target_mismatch", + "target_event_id", + "active order reducer reported validation receipt target mismatch", + vec![event_id], + ), + RadrootsOrderIssue::ValidationReceiptListingMismatch { event_id } => issue_with_events( + "validation_receipt_listing_mismatch", + "listing_event_id", + "active order reducer reported validation receipt listing mismatch", + vec![event_id], + ), + RadrootsOrderIssue::ConflictingValidationReceipts { event_ids } => issue_with_events( + "conflicting_validation_receipts", + "validation_receipt_event_id", + "active order reducer reported conflicting validation receipts", + event_ids, + ), + RadrootsOrderIssue::DeterministicValidationFailure { event_id, reason } => { + issue_with_events( + "deterministic_validation_failure", + "validation_event_id", + format!("active order reducer reported deterministic validation failure: {reason}"), + vec![event_id], + ) + } + RadrootsOrderIssue::StaleListingEvent { + expected_event_id, + current_event_id, + } => issue_with_events( + "stale_listing_event", + "listing_event_id", + "active order reducer reported stale listing event evidence", + vec![expected_event_id, current_event_id], + ), RadrootsOrderIssue::ForkedLifecycle { event_ids } => issue_with_events( "forked_lifecycle", "event_id", @@ -4378,7 +4453,7 @@ fn order_inventory_view_from_listing_projection( .iter() .map(|bin| OrderInventoryBinView { bin_id: bin.bin_id.to_string(), - committed_count: bin.accepted_reserved_count, + committed_count: bin.committed_reserved_count, available_count: Some(bin.available_count), remaining_count: Some(bin.remaining_count), over_reserved: bin.over_reserved, @@ -5324,7 +5399,7 @@ fn prepare_order_revision_proposal_dry_run_via_sdk( let session = CliSdkSession::connect_memory(config).map_err(cli_sdk_error_to_runtime)?; session .sdk() - .orders() + .trades() .prepare_revision_proposal(OrderRevisionProposalPrepareRequest::new( actor, sdk_order_event_ptr(&payload.root_event_id, config.relay.urls.as_slice()), @@ -5345,7 +5420,7 @@ fn prepare_order_revision_decision_dry_run_via_sdk( let session = CliSdkSession::connect_memory(config).map_err(cli_sdk_error_to_runtime)?; session .sdk() - .orders() + .trades() .prepare_revision_decision(OrderRevisionDecisionPrepareRequest::new( actor, sdk_order_event_ptr(&payload.root_event_id, config.relay.urls.as_slice()), @@ -5381,7 +5456,7 @@ fn prepare_order_cancellation_dry_run_via_sdk( let session = CliSdkSession::connect_memory(config).map_err(cli_sdk_error_to_runtime)?; session .sdk() - .orders() + .trades() .prepare_cancellation(OrderCancellationPrepareRequest::new( actor, sdk_order_event_ptr(&root_event_id, config.relay.urls.as_slice()), @@ -5421,7 +5496,7 @@ fn enqueue_order_revision_proposal_via_sdk( let enqueue = session.block_on( session .sdk() - .orders() + .trades() .enqueue_revision_proposal_with_explicit_signer(request, &signer), )?; let push = push_one_sdk_outbox_event(&session, policy)?; @@ -5466,7 +5541,7 @@ fn enqueue_order_revision_decision_via_sdk( let enqueue = session.block_on( session .sdk() - .orders() + .trades() .enqueue_revision_decision_with_explicit_signer(request, &signer), )?; let push = push_one_sdk_outbox_event(&session, policy)?; @@ -5525,7 +5600,7 @@ fn enqueue_order_cancellation_via_sdk( let enqueue = session.block_on( session .sdk() - .orders() + .trades() .enqueue_cancellation_with_explicit_signer(request, &signer), )?; let push = push_one_sdk_outbox_event(&session, policy)?; @@ -5585,7 +5660,7 @@ fn ingest_order_evidence_events( session.block_on( session .sdk() - .orders() + .trades() .ingest_evidence(OrderEvidenceIngestRequest::new(event)), )?; } @@ -6116,7 +6191,7 @@ fn enqueue_order_decision_via_sdk( session.block_on( session .sdk() - .orders() + .trades() .ingest_request_evidence(OrderRequestEvidenceIngestRequest::new(input.request_event)), )?; let keys: RadrootsNostrKeys = signing.identity.into_keys(); @@ -6125,7 +6200,7 @@ fn enqueue_order_decision_via_sdk( let enqueue = session.block_on( session .sdk() - .orders() + .trades() .enqueue_decision_with_explicit_signer(request, &signer), )?; let push = session.block_on( @@ -9431,7 +9506,7 @@ fn prepare_order_submit_via_sdk( let session = CliSdkSession::connect_memory(config)?; let plan = session .sdk() - .orders() + .trades() .prepare_submit(OrderSubmitPrepareRequest::new( input.actor, input.listing_event, @@ -9473,7 +9548,7 @@ fn submit_via_sdk( let enqueue = session.block_on( session .sdk() - .orders() + .trades() .enqueue_submit_with_explicit_signer(request, &signer), )?; let push = session.block_on( diff --git a/src/runtime/order/sdk_status.rs b/src/runtime/order/sdk_status.rs @@ -91,6 +91,7 @@ fn sdk_status_next_action(kind: OrderStatusNextActionKind) -> &'static str { OrderStatusNextActionKind::InspectEvidenceIssues => "inspect_evidence_issues", OrderStatusNextActionKind::AwaitSellerDecision => "await_seller_decision", OrderStatusNextActionKind::DecideRevision => "decide_revision", + OrderStatusNextActionKind::AwaitRhiValidation => "await_rhi_validation", OrderStatusNextActionKind::Terminal => "terminal", _ => "unknown", } @@ -100,7 +101,9 @@ fn sdk_order_status_state(status: OrderStatusKind) -> &'static str { match status { OrderStatusKind::Missing => "missing", OrderStatusKind::Requested => "requested", - OrderStatusKind::Accepted => "accepted", + OrderStatusKind::RevisionProposed => "revision_proposed", + OrderStatusKind::AgreedPendingRhi => "pending_rhi", + OrderStatusKind::Committed => "committed", OrderStatusKind::Declined => "declined", OrderStatusKind::Cancelled => "cancelled", OrderStatusKind::Invalid => "invalid", @@ -149,7 +152,9 @@ fn sdk_order_status_lifecycle_phase(receipt: &OrderStatusReceipt) -> &'static st match receipt.status { OrderStatusKind::Missing => "missing", OrderStatusKind::Requested => "requested", - OrderStatusKind::Accepted => "accepted", + OrderStatusKind::RevisionProposed => "revision_proposed", + OrderStatusKind::AgreedPendingRhi => "pending_rhi", + OrderStatusKind::Committed => "committed", OrderStatusKind::Declined => "declined", OrderStatusKind::Cancelled => "cancelled", OrderStatusKind::Invalid => "invalid", diff --git a/src/runtime/sdk.rs b/src/runtime/sdk.rs @@ -18,7 +18,7 @@ use radroots_nostr_connect::prelude::{ RadrootsNostrConnectClientTarget, RadrootsNostrConnectError, RadrootsNostrConnectUri, }; use radroots_sdk::{ - RadrootsSdk, RadrootsSdkBuilder, RadrootsSdkError, RadrootsSdkLocalKeySigner, + RadrootsClient, RadrootsClientBuilder, RadrootsSdkError, RadrootsSdkLocalKeySigner, RadrootsSdkMycNip46RequestPolicy, RadrootsSdkMycNip46Signer, RadrootsSdkNip46Transport, RadrootsSdkNip46TransportFuture, RadrootsSdkSignerProvider, RadrootsSdkStorageConfig, SdkPublishTransport, SdkRelayUrlPolicy, @@ -67,9 +67,9 @@ impl CliSdkConfig { }) } - pub fn builder(&self) -> RadrootsSdkBuilder { + pub fn builder(&self) -> RadrootsClientBuilder { self.relay_urls.iter().fold( - RadrootsSdk::builder() + RadrootsClient::builder() .storage(RadrootsSdkStorageConfig::Directory( self.storage_root.clone(), )) @@ -82,7 +82,7 @@ impl CliSdkConfig { pub struct CliSdkSession { runtime: Runtime, - sdk: RadrootsSdk, + sdk: RadrootsClient, config: CliSdkConfig, } @@ -156,7 +156,7 @@ impl CliSdkSession { }) } - pub fn sdk(&self) -> &RadrootsSdk { + pub fn sdk(&self) -> &RadrootsClient { &self.sdk } @@ -587,9 +587,9 @@ pub(crate) fn sdk_runtime() -> Result<Runtime, RuntimeError> { }) } -fn memory_builder(config: &CliSdkConfig) -> RadrootsSdkBuilder { +fn memory_builder(config: &CliSdkConfig) -> RadrootsClientBuilder { config.relay_urls.iter().fold( - RadrootsSdk::builder() + RadrootsClient::builder() .relay_url_policy(config.relay_url_policy) .publish_transport(config.publish_transport.clone()), |builder, relay_url| builder.relay_url(relay_url.clone()), @@ -934,7 +934,7 @@ mod tests { path: "src/runtime/order.rs", start: "pub fn status(\n config: &RuntimeConfig", end: "fn legacy_order_preflight_relay_status(", - required_tokens: &["OrderStatusRequest::parse", "session.sdk().orders().status"], + required_tokens: &["OrderStatusRequest::parse", "session.sdk().trades().status"], }, MigratedCliPathGuard { label: "order SDK status adapter", @@ -1024,7 +1024,7 @@ mod tests { required_tokens: &[ "RestoreRequest::new", "sdk_runtime()", - "RadrootsSdk::restore", + "RadrootsClient::restore", ], }, ]; diff --git a/src/runtime/store.rs b/src/runtime/store.rs @@ -5,10 +5,10 @@ use radroots_replica_db::export::{ReplicaDbExportManifestRs, export_manifest}; use radroots_replica_db::migrations; use radroots_replica_sync::radroots_replica_sync_status; use radroots_sdk::{ - BackupReceipt, BackupRequest, IntegrityReceipt, IntegrityRequest, RadrootsSdk, RestoreReceipt, - RestoreRequest, SdkBackupState, SdkEventStoreStorageStatus, SdkOutboxStorageStatus, - SdkRestoreState, SdkSqliteStoreStatus, SdkStorageKind, StorageStatusReceipt, - StorageStatusRequest, + BackupReceipt, BackupRequest, IntegrityReceipt, IntegrityRequest, RadrootsClient, + RestoreReceipt, RestoreRequest, SdkBackupState, SdkEventStoreStorageStatus, + SdkOutboxStorageStatus, SdkRestoreState, SdkSqliteStoreStatus, SdkStorageKind, + StorageStatusReceipt, StorageStatusRequest, }; use radroots_sql_core::SqliteExecutor; use serde::Serialize; @@ -206,7 +206,7 @@ pub fn restore( .with_overwrite(overwrite) .with_dry_run(dry_run); let runtime = sdk_runtime()?; - let receipt = runtime.block_on(RadrootsSdk::restore(request))?; + let receipt = runtime.block_on(RadrootsClient::restore(request))?; sdk_restore_view(receipt, overwrite, dry_run) } diff --git a/src/view/runtime.rs b/src/view/runtime.rs @@ -5,7 +5,7 @@ use std::process::ExitCode; use radroots_events::farm::RadrootsFarm; use radroots_events::ids::RadrootsListingAddress; use radroots_events::kinds::KIND_LISTING; -use radroots_events::listing::RadrootsListingLocation; +use radroots_events::listing::RadrootsListingPublicLocation; use radroots_events::order::RadrootsOrderEconomics; use radroots_events::profile::RadrootsProfile; use radroots_nostr_accounts::prelude::RadrootsNostrAccountRecord; @@ -1057,7 +1057,7 @@ pub struct FarmSelectionView { #[derive(Debug, Clone, Serialize)] pub struct FarmListingDefaultsView { pub delivery_method: String, - pub location: RadrootsListingLocation, + pub location: RadrootsListingPublicLocation, } #[derive(Debug, Clone, Serialize)] diff --git a/tests/signer_runtime_modes.rs b/tests/signer_runtime_modes.rs @@ -1044,8 +1044,12 @@ fn local_farm_publish_dry_run_validates_secret_backed_account() { "Green Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -1080,8 +1084,12 @@ fn local_farm_publish_dry_run_fails_without_configured_relay() { "Green Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -1116,8 +1124,12 @@ fn local_farm_publish_fails_without_configured_relay() { "Green Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -1158,8 +1170,12 @@ fn farm_setup_actions_offer_publish_only_when_relay_publish_executable() { "Green Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -1213,8 +1229,12 @@ fn farm_setup_actions_withhold_publish_for_watch_only_account() { "Watch Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -1253,8 +1273,12 @@ fn local_farm_publish_reports_sdk_push_failure_without_profile_publish() { "Green Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -1335,8 +1359,12 @@ fn local_farm_publish_does_not_persist_publication_until_sdk_push_publishes() { "Green Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -1412,8 +1440,12 @@ fn farm_rebind_is_explicit_and_publish_defaults_ignore_ambient_selection() { "Green Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -1512,8 +1544,12 @@ fn farm_rebind_is_explicit_and_publish_defaults_ignore_ambient_selection() { "Green Farm Retarget", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -1709,8 +1745,12 @@ fn missing_farm_bound_seller_blocks_listing_create_and_guides_setup_repair() { "Missing Seller Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -1818,8 +1858,12 @@ fn farm_rebind_allows_watch_only_target_and_attach_secret_recovers_publish() { "Watch Rebind Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -1932,8 +1976,12 @@ fn local_seller_publish_commands_attempt_configured_relay() { "Green Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -2318,8 +2366,12 @@ fn watch_only_farm_publish_dry_run_fails_as_account_watch_only() { "Green Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); diff --git a/tests/support/mod.rs b/tests/support/mod.rs @@ -494,6 +494,12 @@ pub fn make_listing_publishable(path: &Path, farm_d_tag: &str) { let raw = fs::read_to_string(path).expect("listing draft"); let mut seller_pubkey_present = false; let mut in_seller_actor = false; + let location_city_present = raw + .lines() + .any(|line| line.trim_start().starts_with("city =")); + let location_country_present = raw + .lines() + .any(|line| line.trim_start().starts_with("country =")); let patched = raw .lines() .map(|line| { @@ -509,7 +515,20 @@ pub fn make_listing_publishable(path: &Path, farm_d_tag: &str) { } else if trimmed.starts_with("method =") { format!("{}method = \"pickup\"", line_indent(line)) } else if trimmed.starts_with("primary =") { - format!("{}primary = \"farmstand\"", line_indent(line)) + let mut value = format!("{}primary = \"farmstand\"", line_indent(line)); + if !location_city_present { + value.push_str(&format!("\n{}city = \"San Francisco\"", line_indent(line))); + } + if !location_country_present { + value.push_str(&format!("\n{}country = \"US\"", line_indent(line))); + } + value + } else if trimmed.starts_with("city =") { + format!("{}city = \"San Francisco\"", line_indent(line)) + } else if trimmed.starts_with("country =") { + format!("{}country = \"US\"", line_indent(line)) + } else if trimmed.starts_with("geohash =") { + format!("{}geohash = \"9q8yy\"", line_indent(line)) } else { line.to_owned() } @@ -524,6 +543,12 @@ pub fn make_listing_publishable_with_seller(path: &Path, farm_d_tag: &str, selle let raw = fs::read_to_string(path).expect("listing draft"); let mut seller_pubkey_field_present = false; let mut in_seller_actor = false; + let location_city_present = raw + .lines() + .any(|line| line.trim_start().starts_with("city =")); + let location_country_present = raw + .lines() + .any(|line| line.trim_start().starts_with("country =")); let patched = raw .lines() .map(|line| { @@ -539,7 +564,20 @@ pub fn make_listing_publishable_with_seller(path: &Path, farm_d_tag: &str, selle } else if trimmed.starts_with("method =") { format!("{}method = \"pickup\"", line_indent(line)) } else if trimmed.starts_with("primary =") { - format!("{}primary = \"farmstand\"", line_indent(line)) + let mut value = format!("{}primary = \"farmstand\"", line_indent(line)); + if !location_city_present { + value.push_str(&format!("\n{}city = \"San Francisco\"", line_indent(line))); + } + if !location_country_present { + value.push_str(&format!("\n{}country = \"US\"", line_indent(line))); + } + value + } else if trimmed.starts_with("city =") { + format!("{}city = \"San Francisco\"", line_indent(line)) + } else if trimmed.starts_with("country =") { + format!("{}country = \"US\"", line_indent(line)) + } else if trimmed.starts_with("geohash =") { + format!("{}geohash = \"9q8yy\"", line_indent(line)) } else { line.to_owned() } diff --git a/tests/target_cli.rs b/tests/target_cli.rs @@ -677,12 +677,18 @@ fn seed_app_farm_record( "name": "App Farm", "location": { "primary": "farmstand", + "city": "San Francisco", + "country": "US", + "geohash": "9q8yy", }, }, "listing_defaults": { "delivery_method": "pickup", "location": { "primary": "farmstand", + "city": "San Francisco", + "country": "US", + "geohash": "9q8yy", }, }, }, @@ -849,6 +855,9 @@ fn seed_app_listing_record_identity_variant( }, "location": { "primary": "farmstand", + "city": "San Francisco", + "country": "US", + "geohash": "9q8yy", }, }, }); @@ -1792,8 +1801,12 @@ fn farm_readiness_check_reports_mode_specific_publish_gates() { "Ready Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -1866,8 +1879,12 @@ fn radrootsd_proxy_listing_publish_update_and_archive_dry_run_without_direct_rel "Proxy Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -1951,8 +1968,12 @@ token_file = "{}" "Proxy Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -2080,8 +2101,12 @@ fn direct_relay_listing_publish_uses_myc_nip46_sdk_signer() { "Myc Relay Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -2202,8 +2227,12 @@ token_file = "{}" "Myc Proxy Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -2272,8 +2301,12 @@ fn listing_update_publish_attempts_direct_relay_with_approval() { "Update Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -2505,8 +2538,12 @@ fn listing_list_reports_default_local_drafts() { "Green Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -3150,8 +3187,12 @@ fn offline_listing_publish_enqueues_sdk_outbox_without_direct_relay_push() { "Offline Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -3216,8 +3257,12 @@ fn listing_publish_idempotency_conflict_maps_sdk_partial_mutation_recovery() { "Conflict Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -4035,8 +4080,12 @@ fn seller_dry_runs_preflight_without_mutating_farm_or_listing_files() { "Green Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -4070,8 +4119,12 @@ fn seller_dry_runs_preflight_without_mutating_farm_or_listing_files() { "Green Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -4192,8 +4245,12 @@ fn seller_dry_runs_do_not_write_shared_local_work_records() { "Dry Run Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -4253,8 +4310,12 @@ fn seller_local_writes_append_shared_local_work_records() { "Green Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -5597,8 +5658,12 @@ fn farm_publish_uses_sdk_outbox_without_legacy_signed_event_records() { "Green Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -5658,8 +5723,12 @@ fn listing_publish_failure_uses_sdk_outbox_without_legacy_local_event_record() { "Green Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -5729,8 +5798,12 @@ fn sync_push_sdk_outbox_failure_reports_network_unavailable() { "Sync SDK Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]); @@ -7984,8 +8057,12 @@ fn seller_target_flow_acceptance_uses_target_operations() { "Green Farm", "--location", "farmstand", + "--city", + "San Francisco", "--country", "US", + "--geohash", + "9q8yy", "--delivery-method", "pickup", ]);