commit 3470bf906340ff522d0972180bf82f14c7434550
parent 6655a36134f0e22237006c91cd210f5610e3f329
Author: triesap <tyson@radroots.org>
Date: Wed, 15 Jul 2026 17:35:05 +0000
runtime: align studio with validator receipt flow
Remove Studio order revision publish/import/runtime surfaces after the validator-set receipt cutover.\n\nUpdate SDK storage path metadata, active order reducers, source guards, and UI affordances so Studio consumes the current SDK/runtime stack directly.
Diffstat:
9 files changed, 143 insertions(+), 2029 deletions(-)
diff --git a/crates/desktop/src/runtime.rs b/crates/desktop/src/runtime.rs
@@ -15,11 +15,10 @@ use radroots_event::{
farm::{RadrootsFarm, RadrootsFarmPublicLocation, RadrootsFarmRef},
ids::{
RadrootsDTag, RadrootsEventId, RadrootsInventoryBinId, RadrootsListingAddress,
- RadrootsOrderId, RadrootsOrderRevisionId, RadrootsPublicKey,
+ RadrootsOrderId, RadrootsPublicKey,
},
kinds::{
- KIND_FARM, KIND_LISTING, KIND_LISTING_DRAFT, KIND_ORDER_CANCELLATION, KIND_ORDER_DECISION,
- KIND_ORDER_REQUEST, KIND_ORDER_REVISION_DECISION, KIND_ORDER_REVISION_PROPOSAL,
+ KIND_FARM, KIND_LISTING, KIND_ORDER_CANCELLATION, KIND_ORDER_DECISION, KIND_ORDER_REQUEST,
KIND_PROFILE,
},
listing::{
@@ -30,13 +29,11 @@ use radroots_event::{
order::{
RadrootsOrderDecision, RadrootsOrderEconomics, RadrootsOrderEventType,
RadrootsOrderInventoryCommitment, RadrootsOrderItem, RadrootsOrderRequest,
- RadrootsOrderRevisionDecision, RadrootsOrderRevisionOutcome, RadrootsOrderRevisionProposal,
},
};
use radroots_event_codec::order::{
order_cancellation_from_event, order_decision_from_event, order_event_context_from_tags,
- order_request_from_event, order_revision_decision_from_event,
- order_revision_proposal_from_event,
+ order_request_from_event,
};
use radroots_identity::{RadrootsIdentity, RadrootsIdentityId};
use radroots_nostr::prelude::{
@@ -54,9 +51,8 @@ use radroots_runtime_store::{
};
use radroots_sdk::{
FARM_PUBLISH_OPERATION_KIND, LISTING_PUBLISH_OPERATION_KIND, NostrRelayUrlPolicy,
- TRADE_CANCELLATION_OPERATION_KIND, TRADE_DECISION_OPERATION_KIND,
- TRADE_REVISION_DECISION_OPERATION_KIND, TRADE_REVISION_PROPOSAL_OPERATION_KIND,
- TRADE_SUBMIT_OPERATION_KIND, TargetSet,
+ TRADE_CANCELLATION_OPERATION_KIND, TRADE_DECISION_OPERATION_KIND, TRADE_SUBMIT_OPERATION_KIND,
+ TargetSet,
};
use radroots_sql_core::SqlxSqliteExecutor;
use radroots_studio_app_core::{
@@ -66,9 +62,8 @@ use radroots_studio_app_core::{
AppSdkListingPublishRequest, AppSdkProjectionLifecycleState, AppSdkPublicFarmLocation,
AppSdkRelayUrlPolicy, AppSdkRuntime, AppSdkRuntimeError, AppSdkRuntimeIssue,
AppSdkRuntimeStatus, AppSdkStoragePaths, AppSdkTradeCancellationRequest, AppSdkTradeDecision,
- AppSdkTradeDecisionRequest, AppSdkTradeProposeRequest, AppSdkTradeRevisionDecisionRequest,
- AppSdkTradeRevisionProposalRequest, AppSdkWorkflowReceipt, AppSharedAccountsPaths,
- PackDayExportWriteError, prepare_pack_day_export_bundle_at_data_root,
+ AppSdkTradeDecisionRequest, AppSdkTradeProposeRequest, AppSdkWorkflowReceipt,
+ AppSharedAccountsPaths, PackDayExportWriteError, prepare_pack_day_export_bundle_at_data_root,
shared_runtime_store_database_path_from_shared_accounts, write_prepared_pack_day_export_bundle,
};
use radroots_studio_app_remote_signer::{
@@ -96,12 +91,10 @@ use radroots_studio_app_state::{
use radroots_studio_app_sync::{
AppFarmProfilePublishPayload, AppListingPublishPayload, AppOrderCancellationPublishPayload,
AppOrderDecisionInventoryCommitment, AppOrderDecisionPayload, AppOrderDecisionPublishPayload,
- AppOrderRequestItemPayload, AppOrderRequestPublishPayload,
- AppOrderRevisionDecisionPublishPayload, AppOrderRevisionProposalPublishPayload,
- AppPublishContext, AppPublishPayload, AppPublishedOperationReceipt,
- AppRelayIngestScopeFreshness, AppSyncProjection, AppSyncRequest, AppSyncResult,
- AppSyncRunStatus, AppSyncTransport, AppSyncTransportError, SyncCheckpointStatus,
- SyncConflictSeverity, SyncTrigger,
+ AppOrderRequestItemPayload, AppOrderRequestPublishPayload, AppPublishContext,
+ AppPublishPayload, AppPublishedOperationReceipt, AppRelayIngestScopeFreshness,
+ AppSyncProjection, AppSyncRequest, AppSyncResult, AppSyncRunStatus, AppSyncTransport,
+ AppSyncTransportError, SyncCheckpointStatus, SyncConflictSeverity, SyncTrigger,
};
#[cfg(test)]
use radroots_studio_app_sync::{PendingSyncOperation, SyncAggregateRef, SyncOperationKind};
@@ -126,8 +119,7 @@ use radroots_trade::identity::RadrootsTradeLocator;
use radroots_trade::listing::parse_public_listing_address;
use radroots_trade::order::{
RadrootsOrderCancellationRecord, RadrootsOrderDecisionRecord, RadrootsOrderReductionInputs,
- RadrootsOrderRequestRecord, RadrootsOrderRevisionDecisionRecord,
- RadrootsOrderRevisionProposalRecord, reduce_order_events,
+ RadrootsOrderRequestRecord, reduce_order_events,
};
use radroots_trade::workflow::RadrootsTradeWorkflowState;
use serde_json::json;
@@ -171,11 +163,8 @@ const APP_DIRECT_RELAY_INGEST_KINDS: &[u16] = &[
KIND_PROFILE as u16,
KIND_FARM as u16,
KIND_LISTING as u16,
- KIND_LISTING_DRAFT as u16,
KIND_ORDER_REQUEST as u16,
KIND_ORDER_DECISION as u16,
- KIND_ORDER_REVISION_PROPOSAL as u16,
- KIND_ORDER_REVISION_DECISION as u16,
KIND_ORDER_CANCELLATION as u16,
];
@@ -239,27 +228,12 @@ struct ResolvedAppOrderDecisionEvidence {
}
#[derive(Clone, Debug, Eq, PartialEq)]
-struct ResolvedAppOrderRevisionProposalEvidence {
- event: RadrootsEventEnvelope,
- event_id: String,
- payload: RadrootsOrderRevisionProposal,
-}
-
-#[derive(Clone, Debug, Eq, PartialEq)]
-struct ResolvedAppOrderRevisionDecisionEvidence {
- event_id: String,
- payload: RadrootsOrderRevisionDecision,
-}
-
-#[derive(Clone, Debug, Eq, PartialEq)]
struct ResolvedAppOrderLifecycleEvidence {
request_event_id: String,
status: RadrootsTradeWorkflowState,
agreement_event_id: Option<String>,
last_event_id: Option<String>,
decision: Option<ResolvedAppOrderDecisionEvidence>,
- revision_proposals: Vec<ResolvedAppOrderRevisionProposalEvidence>,
- revision_decisions: Vec<ResolvedAppOrderRevisionDecisionEvidence>,
cancellation_event_id: Option<String>,
}
@@ -267,8 +241,6 @@ struct ResolvedAppOrderLifecycleEvidence {
struct AppActiveOrderEvidenceBuckets {
requests: Vec<RadrootsOrderRequestRecord>,
decisions: Vec<RadrootsOrderDecisionRecord>,
- revision_proposals: Vec<RadrootsOrderRevisionProposalRecord>,
- revision_decisions: Vec<RadrootsOrderRevisionDecisionRecord>,
cancellations: Vec<RadrootsOrderCancellationRecord>,
}
@@ -376,8 +348,6 @@ fn publish_payload_context(publish_payload: &AppPublishPayload) -> &AppPublishCo
AppPublishPayload::Listing(payload) => &payload.context,
AppPublishPayload::OrderRequest(payload) => &payload.context,
AppPublishPayload::OrderDecision(payload) => &payload.context,
- AppPublishPayload::OrderRevisionProposal(payload) => &payload.context,
- AppPublishPayload::OrderRevisionDecision(payload) => &payload.context,
AppPublishPayload::OrderCancellation(payload) => &payload.context,
}
}
@@ -851,24 +821,6 @@ impl DesktopAppRuntime {
)
}
- pub fn publish_order_revision_proposal(
- &self,
- order_id: OrderId,
- items: Vec<RadrootsOrderItem>,
- economics: RadrootsOrderEconomics,
- reason: &str,
- confirm_public_note: bool,
- ) -> Result<bool, AppSqliteError> {
- self.lock_state_mut()
- .publish_seller_order_revision_proposal(
- order_id,
- items,
- economics,
- reason,
- confirm_public_note,
- )
- }
-
pub fn publish_buyer_order_cancel(
&self,
order_id: OrderId,
@@ -878,23 +830,6 @@ impl DesktopAppRuntime {
.publish_buyer_order_cancellation(order_id, confirm_public_note)
}
- pub fn publish_buyer_order_revision_accept(
- &self,
- order_id: OrderId,
- ) -> Result<bool, AppSqliteError> {
- self.lock_state_mut()
- .publish_buyer_order_revision_accept(order_id)
- }
-
- pub fn publish_buyer_order_revision_decline(
- &self,
- order_id: OrderId,
- confirm_public_note: bool,
- ) -> Result<bool, AppSqliteError> {
- self.lock_state_mut()
- .publish_buyer_order_revision_decline(order_id, confirm_public_note)
- }
-
pub fn open_pack_day(
&self,
fulfillment_window_id: Option<FulfillmentWindowId>,
@@ -1213,17 +1148,6 @@ fn start_desktop_sdk_runtime(
AppSdkRuntime::start(AppSdkConfig::from_desktop_paths(paths, nostr_relay_urls))
}
-fn sdk_storage_path_pair(paths: Option<&AppSdkStoragePaths>) -> (Option<PathBuf>, Option<PathBuf>) {
- paths
- .map(|paths| {
- (
- Some(paths.event_store_path.clone()),
- Some(paths.outbox_path.clone()),
- )
- })
- .unwrap_or((None, None))
-}
-
fn desktop_app_sdk_issue_from_runtime_error(
error: &AppSdkRuntimeError,
) -> DesktopAppSdkIssueSummary {
@@ -1285,8 +1209,9 @@ pub struct DesktopAppSdkStatusSummary {
pub projection_lifecycle_state: AppSdkProjectionLifecycleState,
pub projection_lifecycle_reason: Option<String>,
pub storage_root: PathBuf,
- pub event_store_path: Option<PathBuf>,
- pub outbox_path: Option<PathBuf>,
+ pub runtime_path: Option<PathBuf>,
+ pub private_path: Option<PathBuf>,
+ pub studio_path: Option<PathBuf>,
pub relay_target_count: usize,
pub relay_url_policy: AppSdkRelayUrlPolicy,
pub last_issue: Option<DesktopAppSdkIssueSummary>,
@@ -1294,14 +1219,26 @@ pub struct DesktopAppSdkStatusSummary {
impl DesktopAppSdkStatusSummary {
fn from_status(status: &AppSdkRuntimeStatus) -> Self {
- let (event_store_path, outbox_path) = sdk_storage_path_pair(status.storage_paths.as_ref());
+ let runtime_path = status
+ .storage_paths
+ .as_ref()
+ .map(|paths| paths.runtime_path.clone());
+ let private_path = status
+ .storage_paths
+ .as_ref()
+ .map(|paths| paths.private_path.clone());
+ let studio_path = status
+ .storage_paths
+ .as_ref()
+ .map(|paths| paths.studio_path.clone());
Self {
lifecycle_state: status.state,
projection_lifecycle_state: status.projection_lifecycle.state,
projection_lifecycle_reason: status.projection_lifecycle.reason.clone(),
storage_root: status.storage_root.clone(),
- event_store_path,
- outbox_path,
+ runtime_path,
+ private_path,
+ studio_path,
relay_target_count: status.relay_urls.len(),
relay_url_policy: status.relay_url_policy,
last_issue: status
@@ -2614,7 +2551,6 @@ impl DesktopAppRuntimeState {
if lifecycle.decision.is_some()
|| lifecycle.status != RadrootsTradeWorkflowState::Requested
|| lifecycle.cancellation_event_id.is_some()
- || active_order_pending_revision_proposal(&lifecycle).is_some()
{
return Err(AppSqliteError::InvalidProjection {
reason: "seller order decision requires an undecided order",
@@ -2716,291 +2652,6 @@ impl DesktopAppRuntimeState {
Ok(true)
}
- fn prepare_seller_order_revision_proposal(
- &mut self,
- order_id: OrderId,
- items: Vec<RadrootsOrderItem>,
- economics: RadrootsOrderEconomics,
- reason: &str,
- confirm_public_note: bool,
- ) -> Result<AppOrderRevisionProposalPublishPayload, AppSqliteError> {
- let _ = self.import_shared_runtime_store()?;
- let relay_urls = normalized_app_sync_relay_urls(&self.nostr_relay_urls).map_err(|_| {
- AppSqliteError::InvalidProjection {
- reason: "seller order revision requires valid configured relays",
- }
- })?;
- if relay_urls.is_empty() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order revision requires configured relays",
- });
- }
- self.refresh_configured_relay_state_before_order_lifecycle()?;
- let Some(sqlite_store) = self.sqlite_store.as_ref() else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order revision requires local state",
- });
- };
- let Some(farm_id) = self.selected_farm_id() else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order revision requires a selected farm",
- });
- };
- let Some(selected_account) = self
- .state_store
- .identity_projection()
- .selected_account
- .as_ref()
- else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order revision requires a selected seller account",
- });
- };
- let account_id = selected_account.account.account_id.clone();
- let seller_pubkey = self.runtime_store_owner_pubkey(selected_account).ok_or(
- AppSqliteError::InvalidProjection {
- reason: "seller order revision requires a selected seller public key",
- },
- )?;
- let request = self.resolve_seller_order_request_evidence(order_id)?;
- if request.payload.seller_pubkey.trim() != seller_pubkey.as_str() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order revision seller account does not match order seller",
- });
- }
- let listing_address = parse_public_listing_address(request.payload.listing_addr.as_str())
- .map_err(|_| AppSqliteError::InvalidProjection {
- reason: "seller order revision listing address is invalid",
- })?;
- if listing_address.seller_pubkey.as_str() != seller_pubkey.as_str() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order revision listing address is outside seller authority",
- });
- }
- let lifecycle = self.resolve_order_lifecycle_evidence(&request)?;
- if lifecycle.decision.is_some() || lifecycle.status != RadrootsTradeWorkflowState::Requested
- {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order revision requires an undecided order",
- });
- }
- if lifecycle.cancellation_event_id.is_some() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order revision requires an undecided order",
- });
- }
- let Some(order_detail) = sqlite_store.load_order_detail(farm_id, order_id)? else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order revision requires a visible seller order",
- });
- };
- if order_detail.status != OrderStatus::NeedsAction {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order revision requires an undecided order",
- });
- }
- if active_order_pending_revision_proposal(&lifecycle).is_some() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order revision requires no pending revision proposal",
- });
- }
- let reason = reason.trim();
- if reason.is_empty() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "seller order revision requires a non-empty reason",
- });
- }
- let payload = AppOrderRevisionProposalPublishPayload {
- context: AppPublishContext::new(account_id, "seller_order_revision_proposal"),
- app_order_id: order_id,
- farm_id,
- trade_order_id: request.payload.order_id.to_string(),
- request_event_id: request.request_event_id,
- revision_id: format!("app-revision-{}", d_tag_from_uuid(Uuid::now_v7())),
- listing_addr: request.payload.listing_addr.to_string(),
- buyer_pubkey: request.payload.buyer_pubkey.to_string(),
- seller_pubkey: request.payload.seller_pubkey.to_string(),
- items,
- economics,
- reason: reason.to_owned(),
- confirm_public_note,
- };
- AppPublishPayload::OrderRevisionProposal(payload.clone())
- .validate()
- .map_err(|_| AppSqliteError::InvalidProjection {
- reason: "seller order revision publish payload is invalid",
- })?;
- Ok(payload)
- }
-
- fn publish_seller_order_revision_proposal(
- &mut self,
- order_id: OrderId,
- items: Vec<RadrootsOrderItem>,
- economics: RadrootsOrderEconomics,
- reason: &str,
- confirm_public_note: bool,
- ) -> Result<bool, AppSqliteError> {
- let payload = self.prepare_seller_order_revision_proposal(
- order_id,
- items,
- economics,
- reason,
- confirm_public_note,
- )?;
- let source_record_id = order_revision_proposal_sdk_source_record_id(&payload);
- self.enqueue_order_revision_proposal_payload_via_sdk(
- &payload,
- AppSdkWorkflowReceiptSourceKind::LocalOutbox,
- source_record_id.as_str(),
- )?;
- let _ = self.refresh_selected_account_sync()?;
- Ok(true)
- }
-
- fn prepare_buyer_order_revision_decision(
- &mut self,
- order_id: OrderId,
- decision: RadrootsOrderRevisionOutcome,
- confirm_public_note: bool,
- ) -> Result<AppOrderRevisionDecisionPublishPayload, AppSqliteError> {
- let _ = self.import_shared_runtime_store()?;
- let relay_urls = normalized_app_sync_relay_urls(&self.nostr_relay_urls).map_err(|_| {
- AppSqliteError::InvalidProjection {
- reason: "buyer order revision requires valid configured relays",
- }
- })?;
- if relay_urls.is_empty() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order revision requires configured relays",
- });
- }
- self.refresh_configured_relay_state_before_order_lifecycle()?;
- let buyer_context = self.state_store.identity_projection().buyer_context();
- let BuyerContext::Account(account_id) = &buyer_context else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order revision requires a selected buyer account",
- });
- };
- let Some(selected_account) = self.selected_buyer_account(&buyer_context) else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order revision requires a selected buyer account",
- });
- };
- let buyer_pubkey = self.runtime_store_owner_pubkey(selected_account).ok_or(
- AppSqliteError::InvalidProjection {
- reason: "buyer order revision requires a selected buyer public key",
- },
- )?;
- let Some(sqlite_store) = self.sqlite_store.as_ref() else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order revision requires local state",
- });
- };
- let buyer_order_scope = selected_buyer_order_scope(self.state_store.identity_projection());
- let Some(detail) =
- sqlite_store.load_buyer_order_detail_for_scope(&buyer_order_scope, order_id)?
- else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order revision requires a visible buyer order",
- });
- };
- if matches!(
- detail.status,
- BuyerOrderStatus::Ready | BuyerOrderStatus::Completed | BuyerOrderStatus::Declined
- ) {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order revision requires an active negotiated order",
- });
- }
- let request = self.resolve_seller_order_request_evidence(order_id)?;
- if request.payload.buyer_pubkey.trim() != buyer_pubkey.as_str() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order revision buyer account does not match order buyer",
- });
- }
- let lifecycle = self.resolve_order_lifecycle_evidence(&request)?;
- if lifecycle.decision.is_some()
- || !matches!(lifecycle.status, RadrootsTradeWorkflowState::Requested)
- {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order revision requires active pre-agreement negotiation",
- });
- }
- if lifecycle.cancellation_event_id.is_some() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order revision requires active pre-agreement negotiation",
- });
- }
- let Some(proposal) = active_order_pending_revision_proposal(&lifecycle) else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order revision requires a pending seller proposal",
- });
- };
- let payload = AppOrderRevisionDecisionPublishPayload {
- context: AppPublishContext::new(account_id.clone(), "buyer_order_revision_decision"),
- app_order_id: order_id,
- farm_id: detail.farm_id,
- trade_order_id: request.payload.order_id.to_string(),
- request_event_id: request.request_event_id,
- revision_id: proposal.payload.revision_id.to_string(),
- listing_addr: request.payload.listing_addr.to_string(),
- buyer_pubkey: request.payload.buyer_pubkey.to_string(),
- seller_pubkey: request.payload.seller_pubkey.to_string(),
- decision,
- confirm_public_note,
- };
- AppPublishPayload::OrderRevisionDecision(payload.clone())
- .validate()
- .map_err(|_| AppSqliteError::InvalidProjection {
- reason: "buyer order revision publish payload is invalid",
- })?;
- Ok(payload)
- }
-
- fn publish_buyer_order_revision_accept(
- &mut self,
- order_id: OrderId,
- ) -> Result<bool, AppSqliteError> {
- self.publish_buyer_order_revision_decision(
- order_id,
- RadrootsOrderRevisionOutcome::Accepted,
- false,
- )
- }
-
- fn publish_buyer_order_revision_decline(
- &mut self,
- order_id: OrderId,
- confirm_public_note: bool,
- ) -> Result<bool, AppSqliteError> {
- self.publish_buyer_order_revision_decision(
- order_id,
- RadrootsOrderRevisionOutcome::Declined {
- reason: "buyer kept order as placed".to_owned(),
- },
- confirm_public_note,
- )
- }
-
- fn publish_buyer_order_revision_decision(
- &mut self,
- order_id: OrderId,
- decision: RadrootsOrderRevisionOutcome,
- confirm_public_note: bool,
- ) -> Result<bool, AppSqliteError> {
- let payload =
- self.prepare_buyer_order_revision_decision(order_id, decision, confirm_public_note)?;
- let source_record_id = order_revision_decision_sdk_source_record_id(&payload);
- self.enqueue_order_revision_decision_payload_via_sdk(
- &payload,
- AppSdkWorkflowReceiptSourceKind::LocalOutbox,
- source_record_id.as_str(),
- )?;
- let _ = self.refresh_selected_account_sync()?;
- Ok(true)
- }
-
fn prepare_buyer_order_cancellation(
&mut self,
order_id: OrderId,
@@ -3064,11 +2715,6 @@ impl DesktopAppRuntimeState {
reason: "buyer order cancellation requires an open pre-agreement order",
});
}
- if active_order_pending_revision_proposal(&lifecycle).is_some() {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order cancellation requires no pending seller proposal",
- });
- }
match lifecycle.status {
RadrootsTradeWorkflowState::Requested => {}
RadrootsTradeWorkflowState::AgreedPendingValidation
@@ -4922,101 +4568,6 @@ impl DesktopAppRuntimeState {
}
}
- fn enqueue_order_revision_proposal_payload_via_sdk(
- &self,
- payload: &AppOrderRevisionProposalPublishPayload,
- source_kind: AppSdkWorkflowReceiptSourceKind,
- source_record_id: &str,
- ) -> Result<(), AppSqliteError> {
- let operation_kind = TRADE_REVISION_PROPOSAL_OPERATION_KIND;
- let actor_pubkey = self
- .local_signing_identity_for_publish_payload(&AppPublishPayload::OrderRevisionProposal(
- payload.clone(),
- ))
- .and_then(|identity| {
- let actor_pubkey = identity.public_key_hex();
- let request = AppSdkTradeRevisionProposalRequest {
- actor_account_id: payload.context.account_id.clone(),
- actor_pubkey: actor_pubkey.clone(),
- signer_keys: identity.into_keys(),
- locator: trade_locator_from_revision_proposal_payload(payload)?,
- revision_id: publish_revision_id(payload.revision_id.as_str())?,
- items: payload.items.clone(),
- economics: payload.economics.clone(),
- reason: payload.reason.clone(),
- confirm_public_note: payload.confirm_public_note,
- idempotency_key: Some(sdk_idempotency_key(source_record_id)),
- };
- self.enqueue_app_sdk_trade_revision_proposal(request)
- .map(|receipt| (actor_pubkey, receipt))
- .map_err(sync_transport_error_from_sdk_runtime_error)
- });
- match actor_pubkey {
- Ok((actor_pubkey, receipt)) => self.record_app_sdk_workflow_success(
- source_kind,
- source_record_id,
- operation_kind,
- actor_pubkey.as_str(),
- &receipt,
- ),
- Err(error) => self.record_app_sdk_workflow_failure(
- source_kind,
- source_record_id,
- operation_kind,
- None,
- sync_transport_error_detail_json(&error),
- ),
- }
- }
-
- fn enqueue_order_revision_decision_payload_via_sdk(
- &self,
- payload: &AppOrderRevisionDecisionPublishPayload,
- source_kind: AppSdkWorkflowReceiptSourceKind,
- source_record_id: &str,
- ) -> Result<(), AppSqliteError> {
- let operation_kind = TRADE_REVISION_DECISION_OPERATION_KIND;
- let actor_pubkey = self
- .local_signing_identity_for_publish_payload(&AppPublishPayload::OrderRevisionDecision(
- payload.clone(),
- ))
- .and_then(|identity| {
- let actor_pubkey = identity.public_key_hex();
- let request = AppSdkTradeRevisionDecisionRequest {
- actor_account_id: payload.context.account_id.clone(),
- actor_pubkey: actor_pubkey.clone(),
- signer_keys: identity.into_keys(),
- locator: trade_locator_from_revision_decision_payload(payload)?,
- revision_id: publish_revision_id(payload.revision_id.as_str())?,
- decision: payload.decision.clone(),
- evidence: self
- .order_revision_decision_sdk_evidence(payload)
- .map_err(|error| AppSyncTransportError::failed(error.to_string()))?,
- confirm_public_note: payload.confirm_public_note,
- idempotency_key: Some(sdk_idempotency_key(source_record_id)),
- };
- self.enqueue_app_sdk_trade_revision_decision(request)
- .map(|receipt| (actor_pubkey, receipt))
- .map_err(sync_transport_error_from_sdk_runtime_error)
- });
- match actor_pubkey {
- Ok((actor_pubkey, receipt)) => self.record_app_sdk_workflow_success(
- source_kind,
- source_record_id,
- operation_kind,
- actor_pubkey.as_str(),
- &receipt,
- ),
- Err(error) => self.record_app_sdk_workflow_failure(
- source_kind,
- source_record_id,
- operation_kind,
- None,
- sync_transport_error_detail_json(&error),
- ),
- }
- }
-
fn enqueue_order_cancellation_payload_via_sdk(
&self,
payload: &AppOrderCancellationPublishPayload,
@@ -5061,25 +4612,6 @@ impl DesktopAppRuntimeState {
}
}
- fn order_revision_decision_sdk_evidence(
- &self,
- payload: &AppOrderRevisionDecisionPublishPayload,
- ) -> Result<Vec<RadrootsEventEnvelope>, AppSqliteError> {
- let request = self.resolve_seller_order_request_evidence(payload.app_order_id)?;
- let lifecycle = self.resolve_order_lifecycle_evidence(&request)?;
- let Some(proposal) = active_order_pending_revision_proposal(&lifecycle) else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order revision requires a pending seller proposal",
- });
- };
- if proposal.payload.revision_id.to_string() != payload.revision_id {
- return Err(AppSqliteError::InvalidProjection {
- reason: "buyer order revision evidence does not match requested revision",
- });
- }
- Ok(vec![request.request_event, proposal.event.clone()])
- }
-
fn local_signing_identity_for_publish_payload(
&self,
payload: &AppPublishPayload,
@@ -5131,20 +4663,6 @@ impl DesktopAppRuntimeState {
self.with_app_sdk_runtime(|runtime| runtime.trade_decide(request))
}
- fn enqueue_app_sdk_trade_revision_proposal(
- &self,
- request: AppSdkTradeRevisionProposalRequest,
- ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
- self.with_app_sdk_runtime(|runtime| runtime.trade_revision_propose(request))
- }
-
- fn enqueue_app_sdk_trade_revision_decision(
- &self,
- request: AppSdkTradeRevisionDecisionRequest,
- ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
- self.with_app_sdk_runtime(|runtime| runtime.trade_revision_decide(request))
- }
-
fn enqueue_app_sdk_trade_cancellation(
&self,
request: AppSdkTradeCancellationRequest,
@@ -5651,7 +5169,6 @@ impl DesktopAppRuntimeState {
});
let mut buckets = AppActiveOrderEvidenceBuckets::default();
- let mut signed_events_by_id = BTreeMap::new();
let request_event_id =
active_order_event_id(request.request_event_id.as_str(), "request_event_id")?;
let request_author_pubkey = active_order_pubkey(
@@ -5671,7 +5188,6 @@ impl DesktopAppRuntimeState {
}
let event_id = active_order_event_id(event.id_str(), "event_id")?;
let author_pubkey = active_order_pubkey(event.author_str(), "author_pubkey")?;
- signed_events_by_id.insert(event_id.to_string(), event.clone());
match event.kind_u32() {
KIND_ORDER_DECISION => {
let envelope = order_decision_from_event(&event).map_err(|_| {
@@ -5683,47 +5199,11 @@ impl DesktopAppRuntimeState {
buckets.decisions.push(RadrootsOrderDecisionRecord {
event_id,
author_pubkey,
- counterparty_pubkey: context.0,
- root_event_id: context.1,
- prev_event_id: context.2,
- payload: envelope.payload,
- });
- }
- KIND_ORDER_REVISION_PROPOSAL => {
- let Ok(envelope) = order_revision_proposal_from_event(&event) else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "order lifecycle evidence is invalid",
- });
- };
- let context = active_order_event_record_context(&event, envelope.message_type)?;
- buckets
- .revision_proposals
- .push(RadrootsOrderRevisionProposalRecord {
- event_id,
- author_pubkey,
- counterparty_pubkey: context.0,
- root_event_id: context.1,
- prev_event_id: context.2,
- payload: envelope.payload,
- });
- }
- KIND_ORDER_REVISION_DECISION => {
- let Ok(envelope) = order_revision_decision_from_event(&event) else {
- return Err(AppSqliteError::InvalidProjection {
- reason: "order lifecycle evidence is invalid",
- });
- };
- let context = active_order_event_record_context(&event, envelope.message_type)?;
- buckets
- .revision_decisions
- .push(RadrootsOrderRevisionDecisionRecord {
- event_id,
- author_pubkey,
- counterparty_pubkey: context.0,
- root_event_id: context.1,
- prev_event_id: context.2,
- payload: envelope.payload,
- });
+ counterparty_pubkey: context.0,
+ root_event_id: context.1,
+ prev_event_id: context.2,
+ payload: envelope.payload,
+ });
}
KIND_ORDER_CANCELLATION => {
let Ok(envelope) = order_cancellation_from_event(&event) else {
@@ -5750,8 +5230,6 @@ impl DesktopAppRuntimeState {
RadrootsOrderReductionInputs {
requests: buckets.requests.clone(),
decisions: buckets.decisions.clone(),
- revision_proposals: buckets.revision_proposals.clone(),
- revision_decisions: buckets.revision_decisions.clone(),
cancellations: buckets.cancellations.clone(),
},
);
@@ -5794,31 +5272,6 @@ impl DesktopAppRuntimeState {
.last_event_id
.map(|event_id| event_id.to_string()),
decision,
- revision_proposals: buckets
- .revision_proposals
- .into_iter()
- .map(|proposal| {
- let event = signed_events_by_id
- .get(proposal.event_id.as_str())
- .cloned()
- .ok_or(AppSqliteError::InvalidProjection {
- reason: "order lifecycle evidence is invalid",
- })?;
- Ok(ResolvedAppOrderRevisionProposalEvidence {
- event,
- event_id: proposal.event_id.to_string(),
- payload: proposal.payload,
- })
- })
- .collect::<Result<Vec<_>, AppSqliteError>>()?,
- revision_decisions: buckets
- .revision_decisions
- .into_iter()
- .map(|decision| ResolvedAppOrderRevisionDecisionEvidence {
- event_id: decision.event_id.to_string(),
- payload: decision.payload,
- })
- .collect(),
cancellation_event_id: projection
.cancellation_event_id
.map(|event_id| event_id.to_string()),
@@ -5830,12 +5283,7 @@ impl DesktopAppRuntimeState {
) -> Result<Vec<RadrootsEventEnvelope>, AppSqliteError> {
let mut events = Vec::new();
let mut seen_event_ids = BTreeSet::new();
- let kinds = [
- KIND_ORDER_DECISION,
- KIND_ORDER_REVISION_PROPOSAL,
- KIND_ORDER_REVISION_DECISION,
- KIND_ORDER_CANCELLATION,
- ];
+ let kinds = [KIND_ORDER_DECISION, KIND_ORDER_CANCELLATION];
if let Some(sqlite_store) = self.sqlite_store.as_ref() {
for kind in kinds {
@@ -7213,7 +6661,7 @@ fn direct_relay_event_records(
fn direct_relay_event_farm_id(kind: u16, tags: &[Vec<String>]) -> Option<String> {
match kind {
kind if kind == KIND_FARM as u16 => relay_event_tag_value(tags, "d", 1),
- kind if kind == KIND_LISTING as u16 || kind == KIND_LISTING_DRAFT as u16 => {
+ kind if kind == KIND_LISTING as u16 => {
relay_event_tag_value(tags, "a", 1).and_then(|address| relay_address_d_tag(&address))
}
_ => None,
@@ -7226,7 +6674,7 @@ fn direct_relay_event_listing_addr(
listing_d_tag: Option<&str>,
) -> Option<String> {
match kind {
- kind if kind == KIND_LISTING as u16 || kind == KIND_LISTING_DRAFT as u16 => {
+ kind if kind == KIND_LISTING as u16 => {
listing_d_tag.map(|d_tag| format!("{kind}:{event_pubkey}:{d_tag}"))
}
_ => None,
@@ -7443,24 +6891,6 @@ fn order_decision_sdk_source_record_id(payload: &AppOrderDecisionPublishPayload)
format!("app:order_decision:{}", payload.app_order_id)
}
-fn order_revision_proposal_sdk_source_record_id(
- payload: &AppOrderRevisionProposalPublishPayload,
-) -> String {
- format!(
- "app:order_revision_proposal:{}:{}",
- payload.app_order_id, payload.revision_id
- )
-}
-
-fn order_revision_decision_sdk_source_record_id(
- payload: &AppOrderRevisionDecisionPublishPayload,
-) -> String {
- format!(
- "app:order_revision_decision:{}:{}",
- payload.app_order_id, payload.revision_id
- )
-}
-
fn order_cancellation_sdk_source_record_id(payload: &AppOrderCancellationPublishPayload) -> String {
format!("app:order_cancellation:{}", payload.app_order_id)
}
@@ -9545,38 +8975,6 @@ fn active_order_event_record_context(
Ok((context.counterparty_pubkey, root_event_id, prev_event_id))
}
-fn active_order_pending_revision_proposal(
- lifecycle: &ResolvedAppOrderLifecycleEvidence,
-) -> Option<&ResolvedAppOrderRevisionProposalEvidence> {
- let mut parent_event_id = lifecycle.request_event_id.as_str();
- loop {
- let proposals = lifecycle
- .revision_proposals
- .iter()
- .filter(|proposal| proposal.payload.prev_event_id == parent_event_id)
- .collect::<Vec<_>>();
- let proposal = match proposals.as_slice() {
- [] => return None,
- [proposal] => *proposal,
- _ => return None,
- };
- let decisions = lifecycle
- .revision_decisions
- .iter()
- .filter(|decision| {
- decision.payload.prev_event_id == proposal.event_id
- && decision.payload.revision_id == proposal.payload.revision_id
- })
- .collect::<Vec<_>>();
- let decision = match decisions.as_slice() {
- [] => return Some(proposal),
- [decision] => *decision,
- _ => return None,
- };
- parent_event_id = decision.event_id.as_str();
- }
-}
-
fn insert_seller_order_request_evidence(
order_id: &OrderId,
event: &RadrootsEventEnvelope,
@@ -9661,11 +9059,6 @@ fn publish_order_id(value: &str) -> Result<RadrootsOrderId, AppSyncTransportErro
RadrootsOrderId::parse(value).map_err(|error| AppSyncTransportError::failed(error.to_string()))
}
-fn publish_revision_id(value: &str) -> Result<RadrootsOrderRevisionId, AppSyncTransportError> {
- RadrootsOrderRevisionId::parse(value)
- .map_err(|error| AppSyncTransportError::failed(error.to_string()))
-}
-
fn publish_event_id(value: &str) -> Result<RadrootsEventId, AppSyncTransportError> {
RadrootsEventId::parse(value).map_err(|error| AppSyncTransportError::failed(error.to_string()))
}
@@ -9713,30 +9106,6 @@ fn trade_locator_from_decision_payload(
)
}
-fn trade_locator_from_revision_proposal_payload(
- payload: &AppOrderRevisionProposalPublishPayload,
-) -> Result<RadrootsTradeLocator, AppSyncTransportError> {
- trade_locator_from_parts(
- payload.trade_order_id.as_str(),
- payload.request_event_id.as_str(),
- payload.listing_addr.as_str(),
- payload.buyer_pubkey.as_str(),
- payload.seller_pubkey.as_str(),
- )
-}
-
-fn trade_locator_from_revision_decision_payload(
- payload: &AppOrderRevisionDecisionPublishPayload,
-) -> Result<RadrootsTradeLocator, AppSyncTransportError> {
- trade_locator_from_parts(
- payload.trade_order_id.as_str(),
- payload.request_event_id.as_str(),
- payload.listing_addr.as_str(),
- payload.buyer_pubkey.as_str(),
- payload.seller_pubkey.as_str(),
- )
-}
-
fn trade_locator_from_cancellation_payload(
payload: &AppOrderCancellationPublishPayload,
) -> Result<RadrootsTradeLocator, AppSyncTransportError> {
@@ -9841,13 +9210,12 @@ mod tests {
};
use radroots_event::ids::{
RadrootsEventId, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsOrderId,
- RadrootsOrderQuoteId, RadrootsOrderRevisionId, RadrootsPublicKey,
+ RadrootsOrderQuoteId, RadrootsPublicKey,
};
use radroots_event::order::{
RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderDecisionOutcome,
RadrootsOrderEconomicItem, RadrootsOrderEconomics, RadrootsOrderInventoryCommitment,
RadrootsOrderItem, RadrootsOrderPricingBasis, RadrootsOrderRequest,
- RadrootsOrderRevisionOutcome, RadrootsOrderRevisionProposal,
};
use radroots_event::{
RadrootsEventEnvelope, RadrootsEventEnvelopeParts, RadrootsEventPtr,
@@ -9855,7 +9223,6 @@ mod tests {
};
use radroots_event_codec::order::{
order_cancellation_event_build, order_decision_event_build, order_request_event_build,
- order_revision_proposal_event_build,
};
use radroots_identity::{RadrootsIdentity, RadrootsIdentityId};
use radroots_nostr::prelude::{
@@ -9874,8 +9241,7 @@ mod tests {
};
use radroots_sdk::{
LISTING_PUBLISH_OPERATION_KIND, TRADE_CANCELLATION_OPERATION_KIND,
- TRADE_DECISION_OPERATION_KIND, TRADE_REVISION_DECISION_OPERATION_KIND,
- TRADE_SUBMIT_OPERATION_KIND,
+ TRADE_DECISION_OPERATION_KIND, TRADE_SUBMIT_OPERATION_KIND,
};
use radroots_sql_core::{SqlExecutor, SqlxSqliteExecutor};
use radroots_studio_app_core::{
@@ -9901,7 +9267,6 @@ mod tests {
AppFarmProfilePublishPayload, AppListingPublishPayload, AppOrderCancellationPublishPayload,
AppOrderDecisionInventoryCommitment, AppOrderDecisionPayload,
AppOrderDecisionPublishPayload, AppOrderRequestItemPayload, AppOrderRequestPublishPayload,
- AppOrderRevisionDecisionPublishPayload, AppOrderRevisionProposalPublishPayload,
AppPublishContext, AppPublishPayload, AppPublishedOperationReceipt,
AppRelayIngestScopeFreshness, AppRelayIngestScopeStatus, AppSyncRequest, AppSyncResult,
AppSyncRunStatus, AppSyncTransport, AppSyncTransportError, PendingSyncOperation,
@@ -10374,10 +9739,6 @@ mod tests {
RadrootsOrderId::parse(value).expect("order id")
}
- fn test_revision_id(value: &str) -> RadrootsOrderRevisionId {
- RadrootsOrderRevisionId::parse(value).expect("revision id")
- }
-
fn test_quote_id(value: &str) -> RadrootsOrderQuoteId {
RadrootsOrderQuoteId::parse(value).expect("quote id")
}
@@ -10697,69 +10058,6 @@ mod tests {
buyer_identity.public_key_hex(),
seller_identity.public_key_hex(),
);
- let revision_economics = RadrootsOrderEconomics {
- quote_id: test_quote_id("quote-revision-1"),
- quote_version: 2,
- pricing_basis: RadrootsOrderPricingBasis::ListingEvent,
- currency: RadrootsCoreCurrency::USD,
- items: vec![RadrootsOrderEconomicItem {
- bin_id: test_bin_id("bin-1"),
- bin_count: 3,
- quantity_amount: RadrootsCoreDecimal::from(1u32),
- quantity_unit: RadrootsCoreUnit::Each,
- unit_price_amount: RadrootsCoreDecimal::from(8u32),
- unit_price_currency: RadrootsCoreCurrency::USD,
- line_subtotal: RadrootsCoreMoney::from_minor_units_u32(
- 2400,
- RadrootsCoreCurrency::USD,
- ),
- }],
- discounts: Vec::new(),
- adjustments: Vec::new(),
- subtotal: RadrootsCoreMoney::from_minor_units_u32(2400, RadrootsCoreCurrency::USD),
- discount_total: RadrootsCoreMoney::zero(RadrootsCoreCurrency::USD),
- adjustment_total: RadrootsCoreMoney::zero(RadrootsCoreCurrency::USD),
- total: RadrootsCoreMoney::from_minor_units_u32(2400, RadrootsCoreCurrency::USD),
- };
- let revision_proposal =
- AppPublishPayload::OrderRevisionProposal(AppOrderRevisionProposalPublishPayload {
- context: AppPublishContext::new(
- seller_account_id.to_string(),
- "seller_order_revision_proposal",
- ),
- app_order_id: common.0,
- farm_id: common.1,
- trade_order_id: common.2.clone(),
- request_event_id: common.3.clone(),
- revision_id: "revision-1".to_owned(),
- listing_addr: common.4.clone(),
- buyer_pubkey: common.5.clone(),
- seller_pubkey: common.6.clone(),
- items: vec![RadrootsOrderItem {
- bin_id: test_bin_id("bin-1"),
- bin_count: 3,
- }],
- economics: revision_economics,
- reason: "harvest count updated".to_owned(),
- confirm_public_note: false,
- });
- let revision_decision =
- AppPublishPayload::OrderRevisionDecision(AppOrderRevisionDecisionPublishPayload {
- context: AppPublishContext::new(
- buyer_account_id.to_string(),
- "buyer_order_revision_decision",
- ),
- app_order_id: common.0,
- farm_id: common.1,
- trade_order_id: common.2.clone(),
- request_event_id: common.3.clone(),
- revision_id: "revision-1".to_owned(),
- listing_addr: common.4.clone(),
- buyer_pubkey: common.5.clone(),
- seller_pubkey: common.6.clone(),
- decision: RadrootsOrderRevisionOutcome::Accepted,
- confirm_public_note: false,
- });
let cancellation =
AppPublishPayload::OrderCancellation(AppOrderCancellationPublishPayload {
context: AppPublishContext::new(
@@ -10776,7 +10074,7 @@ mod tests {
reason: "buyer cancelled order".to_owned(),
confirm_public_note: false,
});
- let operations = [revision_proposal, revision_decision, cancellation]
+ let operations = [cancellation]
.into_iter()
.map(|payload| {
PendingSyncOperation::from_publish_payload(payload, "2026-05-24T12:00:00Z")
@@ -13714,8 +13012,8 @@ mod tests {
.storage_paths
.as_ref()
.expect("sdk storage paths")
- .event_store_path,
- paths.app.data.join("sdk").join("event_store.sqlite")
+ .runtime_path,
+ paths.app.data.join("sdk").join("runtime.sqlite")
);
let diagnostics = runtime
.sdk_diagnostics()
@@ -13755,8 +13053,16 @@ mod tests {
);
assert_eq!(sdk_status.storage_root, paths.app.data.join("sdk"));
assert_eq!(
- sdk_status.event_store_path.as_ref(),
- Some(&paths.app.data.join("sdk").join("event_store.sqlite"))
+ sdk_status.runtime_path.as_ref(),
+ Some(&paths.app.data.join("sdk").join("runtime.sqlite"))
+ );
+ assert_eq!(
+ sdk_status.private_path.as_ref(),
+ Some(&paths.app.data.join("sdk").join("private.sqlite"))
+ );
+ assert_eq!(
+ sdk_status.studio_path.as_ref(),
+ Some(&paths.app.data.join("sdk").join("studio.sqlite"))
);
assert_eq!(sdk_status.relay_target_count, 1);
assert!(
@@ -15681,51 +14987,6 @@ mod tests {
}
#[test]
- fn runtime_rejects_seller_order_revision_with_reducer_invalid_parent_evidence() {
- let relay = ThreadedAckRelay::spawn();
- let (runtime, paths, order_id, product_id, seller_pubkey, buyer_pubkey) =
- seller_order_decision_runtime("seller_order_revision_invalid_parent", 6, 2);
- install_direct_relay_sync_transport(&runtime, &relay);
- let listing_key = super::d_tag_from_uuid(product_id.as_uuid());
- let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- let request_event_id = shared_order_request_event_id(&paths, "seller-order-decision-1");
- let request_event_id = request_event_id.as_str();
- append_signed_order_decision_record(
- &paths,
- "seller-order-decision-1",
- request_event_id,
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- 2,
- );
- append_signed_order_revision_proposal_record_with_prev(
- &paths,
- "seller-order-decision-1",
- "seller-order-decision-1-stale-revision",
- request_event_id,
- request_event_id,
- listing_addr.as_str(),
- buyer_pubkey.as_str(),
- seller_pubkey.as_str(),
- );
-
- let error = runtime
- .publish_order_revision_proposal(
- order_id,
- revision_test_order_items(),
- revision_test_order_economics(),
- "harvest count updated",
- false,
- )
- .expect_err("seller revision proposal should reject reducer-invalid parent evidence");
-
- assert_order_lifecycle_evidence_invalid(error);
- assert_eq!(relay.event_count(), 0);
- cleanup_bootstrapped_runtime_paths(&paths);
- }
-
- #[test]
fn runtime_places_supported_buyer_order_into_shared_runtime_store() {
let (runtime, paths) = bootstrapped_runtime("buyer_order_local_event");
assert!(
@@ -16347,50 +15608,6 @@ mod tests {
}
#[test]
- fn runtime_rejects_linked_buyer_cancellation_from_pending_revision_proposal() {
- let relay = ThreadedAckRelay::spawn();
- let fixture = linked_buyer_request_runtime("linked_buyer_order_cancel_revision");
- let proposal_key = "linked-buyer-order-cancel-revision-proposal";
- append_signed_order_revision_proposal_record_with_prev(
- &fixture.paths,
- fixture.trade_order_id.as_str(),
- proposal_key,
- fixture.request_event_id.as_str(),
- fixture.request_event_id.as_str(),
- fixture.listing_addr.as_str(),
- fixture.buyer_pubkey.as_str(),
- fixture.seller_pubkey.as_str(),
- );
- install_direct_relay_sync_transport(&fixture.runtime, &relay);
- fixture
- .runtime
- .refresh_shared_runtime_store()
- .expect("linked buyer revision proposal should import");
- assert!(
- fixture
- .runtime
- .open_personal_order_detail(fixture.order_id)
- .expect("linked buyer order detail should open")
- );
-
- let error = fixture
- .runtime
- .publish_buyer_order_cancel(fixture.order_id, false)
- .expect_err("linked buyer cancellation should reject from pending proposal");
-
- assert_invalid_projection_reason(
- error,
- "buyer order cancellation requires no pending seller proposal",
- );
- assert_eq!(relay.event_count(), 0);
- let cancellation_events =
- shared_order_events_by_kind(&fixture.paths, 3432, fixture.buyer_pubkey.as_str());
- assert!(cancellation_events.is_empty());
-
- cleanup_bootstrapped_runtime_paths(&fixture.paths);
- }
-
- #[test]
fn runtime_rejects_linked_buyer_cancellation_after_agreement() {
let relay = ThreadedAckRelay::spawn();
let fixture = linked_buyer_lifecycle_runtime("linked_buyer_order_cancel_after_agreement");
@@ -16470,62 +15687,6 @@ mod tests {
}
#[test]
- fn runtime_publishes_linked_buyer_revision_decision_from_reducer_valid_parent() {
- let relay = ThreadedAckRelay::spawn();
- let fixture = linked_buyer_request_runtime("linked_buyer_order_revision");
- let proposal_key = "linked-buyer-order-revision-proposal";
- let proposal_event_id = append_signed_order_revision_proposal_record_with_prev(
- &fixture.paths,
- fixture.trade_order_id.as_str(),
- proposal_key,
- fixture.request_event_id.as_str(),
- fixture.request_event_id.as_str(),
- fixture.listing_addr.as_str(),
- fixture.buyer_pubkey.as_str(),
- fixture.seller_pubkey.as_str(),
- );
- let revision_id = format!("revision-{proposal_key}");
- install_direct_relay_sync_transport(&fixture.runtime, &relay);
- restore_sdk_runtime_with_relays(
- &fixture.runtime,
- &fixture.paths,
- vec![relay.url().to_owned()],
- );
- fixture
- .runtime
- .refresh_shared_runtime_store()
- .expect("linked buyer runtime store should import");
- assert!(
- fixture
- .runtime
- .open_personal_order_detail(fixture.order_id)
- .expect("linked buyer order detail should open")
- );
- seed_relay_with_shared_event_id(&relay, &fixture.paths, fixture.request_event_id.as_str());
- seed_relay_with_shared_event_id(&relay, &fixture.paths, proposal_event_id.as_str());
-
- assert!(
- fixture
- .runtime
- .publish_buyer_order_revision_accept(fixture.order_id)
- .expect("linked buyer revision decision should publish")
- );
-
- assert_eq!(relay.event_count(), 2);
- let revision_decision_events =
- shared_order_events_by_kind(&fixture.paths, 3425, fixture.buyer_pubkey.as_str());
- assert!(revision_decision_events.is_empty());
- assert_order_revision_decision_sdk_workflow_receipt(
- &fixture.runtime,
- fixture.order_id,
- revision_id.as_str(),
- AppSdkWorkflowReceiptState::Enqueued,
- );
-
- cleanup_bootstrapped_runtime_paths(&fixture.paths);
- }
-
- #[test]
fn runtime_repeat_personal_order_readds_only_currently_eligible_items() {
let runtime = memory_runtime();
let (account_id, farm_id) = provision_ready_farmer_account(&runtime);
@@ -20522,77 +19683,6 @@ mod tests {
)
}
- fn append_signed_order_revision_proposal_record_with_prev(
- paths: &AppDesktopRuntimePaths,
- trade_order_id: &str,
- event_key: &str,
- request_event_id: &str,
- prev_event_id: &str,
- listing_addr: &str,
- buyer_pubkey: &str,
- seller_pubkey: &str,
- ) -> String {
- let request_event_id = test_event_id(request_event_id);
- let prev_event_id = test_event_id(prev_event_id);
- let payload = RadrootsOrderRevisionProposal {
- revision_id: test_revision_id(format!("revision-{event_key}").as_str()),
- order_id: test_order_id(trade_order_id),
- listing_addr: test_listing_addr(listing_addr),
- buyer_pubkey: test_pubkey(buyer_pubkey),
- seller_pubkey: test_pubkey(seller_pubkey),
- root_event_id: request_event_id.clone(),
- prev_event_id: prev_event_id.clone(),
- items: revision_test_order_items(),
- economics: revision_test_order_economics(),
- reason: "harvest count updated".to_owned(),
- };
- let parts =
- order_revision_proposal_event_build(&request_event_id, &prev_event_id, &payload)
- .expect("order revision proposal draft should build");
- let record_id = format!("app:signed_event:revision-proposal:{event_key}");
- append_trade_signed_event_record(
- paths,
- record_id.as_str(),
- seller_pubkey,
- listing_addr,
- parts,
- )
- }
-
- fn revision_test_order_items() -> Vec<RadrootsOrderItem> {
- vec![RadrootsOrderItem {
- bin_id: test_bin_id("seller-order-primary-bin"),
- bin_count: 3,
- }]
- }
-
- fn revision_test_order_economics() -> RadrootsOrderEconomics {
- RadrootsOrderEconomics {
- quote_id: test_quote_id("quote-revision-test"),
- quote_version: 2,
- pricing_basis: RadrootsOrderPricingBasis::ListingEvent,
- currency: RadrootsCoreCurrency::USD,
- items: vec![RadrootsOrderEconomicItem {
- bin_id: test_bin_id("seller-order-primary-bin"),
- bin_count: 3,
- quantity_amount: RadrootsCoreDecimal::from(1u32),
- quantity_unit: RadrootsCoreUnit::Each,
- unit_price_amount: RadrootsCoreDecimal::from(8u32),
- unit_price_currency: RadrootsCoreCurrency::USD,
- line_subtotal: RadrootsCoreMoney::from_minor_units_u32(
- 2400,
- RadrootsCoreCurrency::USD,
- ),
- }],
- discounts: Vec::new(),
- adjustments: Vec::new(),
- subtotal: RadrootsCoreMoney::from_minor_units_u32(2400, RadrootsCoreCurrency::USD),
- discount_total: RadrootsCoreMoney::zero(RadrootsCoreCurrency::USD),
- adjustment_total: RadrootsCoreMoney::zero(RadrootsCoreCurrency::USD),
- total: RadrootsCoreMoney::from_minor_units_u32(2400, RadrootsCoreCurrency::USD),
- }
- }
-
fn assert_order_lifecycle_evidence_invalid(error: AppSqliteError) {
assert!(
matches!(
@@ -21055,20 +20145,6 @@ mod tests {
}
}
- fn assert_order_revision_decision_sdk_workflow_receipt(
- runtime: &DesktopAppRuntime,
- order_id: OrderId,
- revision_id: &str,
- expected_state: AppSdkWorkflowReceiptState,
- ) {
- assert_order_sdk_workflow_receipt(
- runtime,
- format!("app:order_revision_decision:{order_id}:{revision_id}").as_str(),
- TRADE_REVISION_DECISION_OPERATION_KIND,
- expected_state,
- );
- }
-
fn assert_order_cancellation_sdk_workflow_receipt(
runtime: &DesktopAppRuntime,
order_id: OrderId,
diff --git a/crates/desktop/src/source_guards.rs b/crates/desktop/src/source_guards.rs
@@ -81,12 +81,10 @@ const ALLOWED_WINDOW_LITERALS: &[&str] = &[
"buyer-order-review-confirm-public-note",
"buyer-order-review-place-order",
"buyer-listing-open",
- "buyer-order-accept-change",
"buyer-order-confirm-replace",
"buyer-order-cancel",
"buyer-order-detail-back",
"buyer-order-keep-current",
- "buyer-order-keep-order",
"buyer-order-repeat-demand",
"buyer-orders-retry-coordination",
"personal_orders",
@@ -99,8 +97,6 @@ const ALLOWED_WINDOW_LITERALS: &[&str] = &[
"buyer.order_open_failed",
"buyer.order_cancel_failed",
"buyer.order_coordination_retry_failed",
- "buyer.order_revision_accept_failed",
- "buyer.order_revision_decline_failed",
"buyer.repeat_demand_failed",
"buyer.section_select_failed",
"buyer_notice",
@@ -1090,11 +1086,8 @@ const FORBIDDEN_PAYMENT_ACTION_COPY_TERMS: &[&str] = &[
const FORBIDDEN_PRODUCTION_EVENT_KIND_LITERALS: &[(&str, &str)] = &[
("30340", "KIND_FARM"),
("30402", "KIND_LISTING"),
- ("30403", "KIND_LISTING_DRAFT"),
("3422", "KIND_ORDER_REQUEST"),
("3423", "KIND_ORDER_DECISION"),
- ("3424", "KIND_ORDER_REVISION_PROPOSAL"),
- ("3425", "KIND_ORDER_REVISION_DECISION"),
("3426", "KIND_TRADE_QUESTION"),
("3427", "KIND_TRADE_ANSWER"),
("3428", "KIND_TRADE_DISCOUNT_REQUEST"),
@@ -1246,14 +1239,6 @@ const STRICT_SDK_BOUNDARY_FORBIDDEN_PATTERNS: &[SdkBoundaryForbiddenPattern] = &
reason: "app production sources must not call direct SDK order publish APIs",
},
SdkBoundaryForbiddenPattern {
- pattern: "publish_order_revision_proposal_with_identity",
- reason: "app production sources must not call direct SDK order publish APIs",
- },
- SdkBoundaryForbiddenPattern {
- pattern: "publish_order_revision_decision_with_identity",
- reason: "app production sources must not call direct SDK order publish APIs",
- },
- SdkBoundaryForbiddenPattern {
pattern: "publish_order_cancellation_with_identity",
reason: "app production sources must not call direct SDK order publish APIs",
},
@@ -1622,8 +1607,6 @@ fn app_sdk_trade_mutation_requests_stay_locator_and_resync_owned() {
for request_struct in [
"AppSdkTradeProposeRequest",
"AppSdkTradeDecisionRequest",
- "AppSdkTradeRevisionProposalRequest",
- "AppSdkTradeRevisionDecisionRequest",
"AppSdkTradeCancellationRequest",
] {
let request = struct_block(source.as_str(), request_struct);
@@ -1635,8 +1618,6 @@ fn app_sdk_trade_mutation_requests_stay_locator_and_resync_owned() {
for request_struct in [
"AppSdkTradeDecisionRequest",
- "AppSdkTradeRevisionProposalRequest",
- "AppSdkTradeRevisionDecisionRequest",
"AppSdkTradeCancellationRequest",
] {
let request = struct_block(source.as_str(), request_struct);
@@ -1735,7 +1716,7 @@ fn app_store_active_order_projection_is_root_aware_and_non_authoritative() {
let projected_order_id = source_segment(
source.as_str(),
"pub fn projected_order_id_from_trade_request(",
- "fn active_order_revision_status(",
+ "fn active_order_change_status(",
);
assert!(projected_order_id.contains("root_event_id: &str"));
assert!(projected_order_id.contains("radroots-cli-order-root"));
@@ -1743,8 +1724,6 @@ fn app_store_active_order_projection_is_root_aware_and_non_authoritative() {
for forbidden in [
"TradeAcceptRequest::new",
"TradeDeclineRequest::new",
- "TradeRevisionProposalRequest::new",
- "TradeRevisionDecisionRequest::new",
"TradeCancelRequest::new",
"TradeEvidenceMode::",
] {
diff --git a/crates/desktop/src/window.rs b/crates/desktop/src/window.rs
@@ -2910,41 +2910,6 @@ impl HomeView {
}
}
- fn accept_buyer_order_revision(&mut self, order_id: OrderId, cx: &mut Context<Self>) {
- match self.runtime.publish_buyer_order_revision_accept(order_id) {
- Ok(true) => cx.notify(),
- Ok(false) => {}
- Err(runtime_error) => {
- error!(
- target: "personal_orders",
- event = "buyer.order_revision_accept_failed",
- error = %runtime_error,
- order_id = %order_id,
- "failed to accept buyer order change"
- );
- }
- }
- }
-
- fn decline_buyer_order_revision(&mut self, order_id: OrderId, cx: &mut Context<Self>) {
- match self
- .runtime
- .publish_buyer_order_revision_decline(order_id, false)
- {
- Ok(true) => cx.notify(),
- Ok(false) => {}
- Err(runtime_error) => {
- error!(
- target: "personal_orders",
- event = "buyer.order_revision_decline_failed",
- error = %runtime_error,
- order_id = %order_id,
- "failed to keep buyer order"
- );
- }
- }
- }
-
fn open_products_stock_editor(
&mut self,
product_id: ProductId,
@@ -8571,12 +8536,16 @@ fn about_runtime_rows(runtime: &DesktopAppRuntimeSummary) -> Vec<LabelValueRow>
sdk_status.storage_root.display().to_string(),
));
rows.push(LabelValueRow::new(
- app_shared_text(AppTextKey::MetadataSdkEventStorePath),
- path_or_none(sdk_status.event_store_path.as_ref()),
+ app_shared_text(AppTextKey::MetadataSdkRuntimePath),
+ path_or_none(sdk_status.runtime_path.as_ref()),
+ ));
+ rows.push(LabelValueRow::new(
+ app_shared_text(AppTextKey::MetadataSdkPrivatePath),
+ path_or_none(sdk_status.private_path.as_ref()),
));
rows.push(LabelValueRow::new(
- app_shared_text(AppTextKey::MetadataSdkOutboxPath),
- path_or_none(sdk_status.outbox_path.as_ref()),
+ app_shared_text(AppTextKey::MetadataSdkStudioPath),
+ path_or_none(sdk_status.studio_path.as_ref()),
));
rows.push(LabelValueRow::new(
app_shared_text(AppTextKey::MetadataSdkRelayUrlPolicy),
@@ -11879,38 +11848,6 @@ fn buyer_order_detail_card(
this.child(home_body_text(app_shared_text(AppTextKey::ValueNone)))
}),
))
- .when(
- detail.status == BuyerOrderStatus::Scheduled
- && detail.workflow.revision == TradeRevisionStatus::ChangeProposed,
- |this| {
- this.child(
- app_stack_h(APP_UI_THEME.foundation.spacing.small_px)
- .w_full()
- .child(action_button_primary(
- "buyer-order-accept-change",
- app_shared_text(AppTextKey::PersonalOrdersActionAcceptChange),
- cx.listener({
- let order_id = detail.order_id;
- move |this, _, _, cx| {
- this.accept_buyer_order_revision(order_id, cx)
- }
- }),
- cx,
- ))
- .child(action_button_compact(
- "buyer-order-keep-order",
- app_shared_text(AppTextKey::PersonalOrdersActionKeepOrder),
- cx.listener({
- let order_id = detail.order_id;
- move |this, _, _, cx| {
- this.decline_buyer_order_revision(order_id, cx)
- }
- }),
- cx,
- )),
- )
- },
- )
.when(detail.status == BuyerOrderStatus::Placed, |this| {
this.child(action_button_compact(
"buyer-order-cancel",
@@ -18850,8 +18787,9 @@ mod tests {
projection_lifecycle_state: AppSdkProjectionLifecycleState::Current,
projection_lifecycle_reason: None,
storage_root: storage_root.clone(),
- event_store_path: Some(storage_root.join("event_store.sqlite")),
- outbox_path: Some(storage_root.join("outbox.sqlite")),
+ runtime_path: Some(storage_root.join("runtime.sqlite")),
+ private_path: Some(storage_root.join("private.sqlite")),
+ studio_path: Some(storage_root.join("studio.sqlite")),
relay_target_count: 2,
relay_url_policy: AppSdkRelayUrlPolicy::Localhost,
last_issue: None,
diff --git a/crates/i18n/src/keys.rs b/crates/i18n/src/keys.rs
@@ -784,8 +784,9 @@ define_app_text_keys! {
MetadataSdkIssueRetryable => "metadata.sdk_issue_retryable",
MetadataSdkRecoveryAction => "metadata.sdk_recovery_action",
MetadataSdkStorageRoot => "metadata.sdk_storage_root",
- MetadataSdkEventStorePath => "metadata.sdk_event_store_path",
- MetadataSdkOutboxPath => "metadata.sdk_outbox_path",
+ MetadataSdkRuntimePath => "metadata.sdk_runtime_path",
+ MetadataSdkPrivatePath => "metadata.sdk_private_path",
+ MetadataSdkStudioPath => "metadata.sdk_studio_path",
MetadataSdkRelayUrlPolicy => "metadata.sdk_relay_url_policy",
ValueNone => "value.none",
ValueYes => "value.yes",
diff --git a/crates/runtime/src/lib.rs b/crates/runtime/src/lib.rs
@@ -47,7 +47,7 @@ pub use sdk::{
AppSdkStorageDiagnostics, AppSdkStoragePaths, AppSdkSyncDiagnostics,
AppSdkSyncEventStoreDiagnostics, AppSdkSyncOutboxDiagnostics,
AppSdkSyncTransportTargetDiagnostics, AppSdkTradeCancellationRequest, AppSdkTradeDecision,
- AppSdkTradeDecisionRequest, AppSdkTradeProposeRequest, AppSdkTradeRevisionDecisionRequest,
- AppSdkTradeRevisionProposalRequest, AppSdkWorkflowReceipt, app_sdk_storage_root_from_data_root,
+ AppSdkTradeDecisionRequest, AppSdkTradeProposeRequest, AppSdkWorkflowReceipt,
+ app_sdk_storage_root_from_data_root,
};
pub use startup::{AppStartupEvent, AppStartupEventMetadata, launch_startup_event};
diff --git a/crates/runtime/src/sdk.rs b/crates/runtime/src/sdk.rs
@@ -12,19 +12,17 @@ use std::{
use radroots_authority::{RadrootsActorContext, RadrootsLocalEventSigner};
use radroots_event::{
- RadrootsEventEnvelope, RadrootsEventPtr,
+ RadrootsEventPtr,
contract::RadrootsActorRole,
- draft::{RadrootsSignedEvent, RadrootsSignedEventParts},
farm::RadrootsFarm,
ids::{
- RadrootsAddressableCoordinate, RadrootsListingAddress, RadrootsOrderId,
- RadrootsOrderRevisionId, RadrootsPublicKey,
+ RadrootsAddressableCoordinate, RadrootsListingAddress, RadrootsOrderId, RadrootsPublicKey,
},
kinds::KIND_FARM,
listing::RadrootsListing,
order::{
RadrootsOrderEconomics, RadrootsOrderInventoryCommitment, RadrootsOrderItem,
- RadrootsOrderRevisionOutcome,
+ RadrootsOrderRequest,
},
};
use radroots_nostr::prelude::RadrootsNostrKeys;
@@ -37,14 +35,11 @@ use radroots_sdk::{
RadrootsSdkLocalKeySigner, RadrootsSdkSignerProvider, RadrootsSdkStoragePaths, RestoreReceipt,
RestoreRequest, SatisfactionPolicy, SdkBackupVerification, SdkPublicLocality,
StorageStatusReceipt, StorageStatusRequest, SyncStatusReceipt, SyncStatusRequest,
- TRADE_CANCELLATION_OPERATION_KIND, TRADE_DECISION_OPERATION_KIND,
- TRADE_REVISION_DECISION_OPERATION_KIND, TRADE_REVISION_PROPOSAL_OPERATION_KIND,
- TRADE_SUBMIT_OPERATION_KIND, TargetPolicy, TradeAcceptRequest, TradeCancelRequest,
- TradeCancellationPlan, TradeCancellationReceipt, TradeDecisionPlan, TradeDecisionReceipt,
- TradeDeclineRequest, TradeEvidenceIngestRequest, TradeEvidenceMode, TradeMutationOutcome,
- TradeProposeRequest, TradeRevisionDecisionPlan, TradeRevisionDecisionReceipt,
- TradeRevisionDecisionRequest, TradeRevisionProposalPlan, TradeRevisionProposalReceipt,
- TradeRevisionProposalRequest, TradeSubmitPlan, TradeSubmitReceipt, TransportProfile,
+ TRADE_CANCELLATION_OPERATION_KIND, TRADE_DECISION_OPERATION_KIND, TRADE_SUBMIT_OPERATION_KIND,
+ TargetPolicy, TradeAcceptRequest, TradeCancelRequest, TradeCancellationPlan,
+ TradeCancellationReceipt, TradeDecisionPlan, TradeDecisionReceipt, TradeDeclineRequest,
+ TradeEvidenceMode, TradeMutationOutcome, TradeProposeRequest, TradeSubmitPlan,
+ TradeSubmitReceipt, TransportProfile,
};
use radroots_trade::identity::RadrootsTradeLocator;
use serde::Serialize;
@@ -86,8 +81,9 @@ pub struct AppSdkConfig {
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AppSdkStoragePaths {
- pub event_store_path: PathBuf,
- pub outbox_path: PathBuf,
+ pub runtime_path: PathBuf,
+ pub private_path: PathBuf,
+ pub studio_path: PathBuf,
}
#[derive(Clone, Debug, PartialEq)]
@@ -282,31 +278,6 @@ pub struct AppSdkTradeDecisionRequest {
pub idempotency_key: Option<String>,
}
-pub struct AppSdkTradeRevisionProposalRequest {
- pub actor_account_id: String,
- pub actor_pubkey: String,
- pub signer_keys: RadrootsNostrKeys,
- pub locator: RadrootsTradeLocator,
- pub revision_id: RadrootsOrderRevisionId,
- pub items: Vec<RadrootsOrderItem>,
- pub economics: RadrootsOrderEconomics,
- pub reason: String,
- pub confirm_public_note: bool,
- pub idempotency_key: Option<String>,
-}
-
-pub struct AppSdkTradeRevisionDecisionRequest {
- pub actor_account_id: String,
- pub actor_pubkey: String,
- pub signer_keys: RadrootsNostrKeys,
- pub locator: RadrootsTradeLocator,
- pub revision_id: RadrootsOrderRevisionId,
- pub decision: RadrootsOrderRevisionOutcome,
- pub evidence: Vec<RadrootsEventEnvelope>,
- pub confirm_public_note: bool,
- pub idempotency_key: Option<String>,
-}
-
pub struct AppSdkTradeCancellationRequest {
pub actor_account_id: String,
pub actor_pubkey: String,
@@ -336,8 +307,9 @@ pub struct AppSdkRestorePreflightReceipt {
pub state: String,
pub destination_paths: Option<AppSdkStoragePaths>,
pub restored_paths: Option<AppSdkStoragePaths>,
- pub event_store_path: PathBuf,
- pub outbox_path: PathBuf,
+ pub runtime_path: PathBuf,
+ pub private_path: PathBuf,
+ pub studio_path: PathBuf,
pub manifest_path: PathBuf,
pub verification: AppSdkBackupVerificationDiagnostics,
pub source_storage: AppSdkStorageDiagnostics,
@@ -429,14 +401,6 @@ enum AppSdkWorkerCommand {
AppSdkTradeDecisionRequest,
mpsc::Sender<Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue>>,
),
- TradeRevisionProposal(
- AppSdkTradeRevisionProposalRequest,
- mpsc::Sender<Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue>>,
- ),
- TradeRevisionDecision(
- AppSdkTradeRevisionDecisionRequest,
- mpsc::Sender<Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue>>,
- ),
TradeCancellation(
AppSdkTradeCancellationRequest,
mpsc::Sender<Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue>>,
@@ -462,8 +426,6 @@ impl fmt::Debug for AppSdkWorkerCommand {
Self::EnqueueListingPublish(_, _) => formatter.write_str("EnqueueListingPublish"),
Self::TradePropose(_, _) => formatter.write_str("TradePropose"),
Self::TradeDecision(_, _) => formatter.write_str("TradeDecision"),
- Self::TradeRevisionProposal(_, _) => formatter.write_str("TradeRevisionProposal"),
- Self::TradeRevisionDecision(_, _) => formatter.write_str("TradeRevisionDecision"),
Self::TradeCancellation(_, _) => formatter.write_str("TradeCancellation"),
Self::BeginProjectionRebuild(_) => formatter.write_str("BeginProjectionRebuild"),
Self::CompleteProjectionRebuild(_) => formatter.write_str("CompleteProjectionRebuild"),
@@ -631,24 +593,6 @@ impl AppSdkRuntime {
})
}
- pub fn trade_revision_propose(
- &self,
- request: AppSdkTradeRevisionProposalRequest,
- ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
- self.run_command(|response_sender| {
- AppSdkWorkerCommand::TradeRevisionProposal(request, response_sender)
- })
- }
-
- pub fn trade_revision_decide(
- &self,
- request: AppSdkTradeRevisionDecisionRequest,
- ) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeError> {
- self.run_command(|response_sender| {
- AppSdkWorkerCommand::TradeRevisionDecision(request, response_sender)
- })
- }
-
pub fn trade_cancel(
&self,
request: AppSdkTradeCancellationRequest,
@@ -773,8 +717,9 @@ impl From<AppSdkRelayUrlPolicy> for NostrRelayUrlPolicy {
impl From<&RadrootsSdkStoragePaths> for AppSdkStoragePaths {
fn from(paths: &RadrootsSdkStoragePaths) -> Self {
Self {
- event_store_path: paths.event_store_path.clone(),
- outbox_path: paths.outbox_path.clone(),
+ runtime_path: paths.runtime_path.clone(),
+ private_path: paths.private_path.clone(),
+ studio_path: paths.studio_path.clone(),
}
}
}
@@ -988,8 +933,9 @@ impl AppSdkRestorePreflightReceipt {
.restored_paths
.as_ref()
.map(AppSdkStoragePaths::from),
- event_store_path: receipt.event_store_path,
- outbox_path: receipt.outbox_path,
+ runtime_path: receipt.runtime_path,
+ private_path: receipt.private_path,
+ studio_path: receipt.studio_path,
manifest_path: receipt.manifest_path,
verification: receipt.verification.into(),
source_storage: receipt.manifest.source_status.into(),
@@ -1195,28 +1141,6 @@ fn run_app_sdk_worker(
};
send_worker_result(&shared, response_sender, result);
}
- AppSdkWorkerCommand::TradeRevisionProposal(request, response_sender) => {
- let result = if let Some(issue) = lifecycle_busy_issue(&shared) {
- Err(issue)
- } else {
- match sdk.as_ref() {
- Some(_) => trade_revision_propose_with_sdk(&runtime, &config, request),
- None => Err(runtime_unavailable_issue(&shared)),
- }
- };
- send_worker_result(&shared, response_sender, result);
- }
- AppSdkWorkerCommand::TradeRevisionDecision(request, response_sender) => {
- let result = if let Some(issue) = lifecycle_busy_issue(&shared) {
- Err(issue)
- } else {
- match sdk.as_ref() {
- Some(_) => trade_revision_decide_with_sdk(&runtime, &config, request),
- None => Err(runtime_unavailable_issue(&shared)),
- }
- };
- send_worker_result(&shared, response_sender, result);
- }
AppSdkWorkerCommand::TradeCancellation(request, response_sender) => {
let result = if let Some(issue) = lifecycle_busy_issue(&shared) {
Err(issue)
@@ -1330,20 +1254,6 @@ fn run_degraded_worker(
Err(runtime_unavailable_issue(&shared)),
);
}
- AppSdkWorkerCommand::TradeRevisionProposal(_, response_sender) => {
- send_worker_result(
- &shared,
- response_sender,
- Err(runtime_unavailable_issue(&shared)),
- );
- }
- AppSdkWorkerCommand::TradeRevisionDecision(_, response_sender) => {
- send_worker_result(
- &shared,
- response_sender,
- Err(runtime_unavailable_issue(&shared)),
- );
- }
AppSdkWorkerCommand::TradeCancellation(_, response_sender) => {
send_worker_result(
&shared,
@@ -1572,14 +1482,24 @@ fn trade_propose_with_sdk(
RadrootsActorRole::Buyer,
)?;
let sdk = runtime.block_on(build_sdk_runtime_with_signer(config, request.signer_keys))?;
+ let buyer_pubkey =
+ RadrootsPublicKey::parse(request.actor_pubkey.as_str()).map_err(|error| {
+ AppSdkRuntimeIssue::from_sdk_error(&RadrootsSdkError::InvalidRequest {
+ message: format!("trade proposal buyer public key is invalid: {error}"),
+ })
+ })?;
+ let order = RadrootsOrderRequest {
+ order_id: request.order_id,
+ listing_addr: request.listing_addr,
+ buyer_pubkey,
+ seller_pubkey: request.seller_pubkey,
+ items: request.items,
+ economics: request.economics,
+ };
let mut sdk_request = TradeProposeRequest::new(
actor,
request.listing_event,
- request.order_id,
- request.listing_addr,
- request.seller_pubkey,
- request.items,
- request.economics,
+ order,
app_trade_target_policy(),
app_trade_publish_mode(),
app_trade_satisfaction_policy(),
@@ -1657,115 +1577,6 @@ fn trade_decision_with_sdk(
app_sdk_trade_decision_receipt(outcome, request.actor_pubkey)
}
-fn trade_revision_propose_with_sdk(
- runtime: &tokio::runtime::Runtime,
- config: &AppSdkConfig,
- request: AppSdkTradeRevisionProposalRequest,
-) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue> {
- let actor = sdk_actor_context(
- request.actor_pubkey.as_str(),
- request.actor_account_id.as_str(),
- RadrootsActorRole::Seller,
- )?;
- let sdk = runtime.block_on(build_sdk_runtime_with_signer(config, request.signer_keys))?;
- let mut sdk_request = TradeRevisionProposalRequest::new(
- actor,
- request.locator,
- request.revision_id,
- request.items,
- request.economics,
- request.reason,
- app_trade_target_policy(),
- app_trade_publish_mode(),
- app_trade_satisfaction_policy(),
- TradeEvidenceMode::ResyncBeforeMutation,
- )
- .with_privacy_confirmation(app_trade_privacy_confirmation(request.confirm_public_note));
- if let Some(idempotency_key) = request.idempotency_key.as_deref() {
- sdk_request = sdk_request
- .try_with_idempotency_key(idempotency_key)
- .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
- }
- let outcome = runtime
- .block_on(sdk.trades().seller().propose_revision(sdk_request))
- .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
- app_sdk_trade_revision_proposal_receipt(outcome, request.actor_pubkey)
-}
-
-fn trade_revision_decide_with_sdk(
- runtime: &tokio::runtime::Runtime,
- config: &AppSdkConfig,
- request: AppSdkTradeRevisionDecisionRequest,
-) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue> {
- let actor = sdk_actor_context(
- request.actor_pubkey.as_str(),
- request.actor_account_id.as_str(),
- RadrootsActorRole::Buyer,
- )?;
- let sdk = runtime.block_on(build_sdk_runtime_with_signer(config, request.signer_keys))?;
- let evidence = request
- .evidence
- .into_iter()
- .map(signed_trade_evidence_from_envelope)
- .map(|event| event.map(TradeEvidenceIngestRequest::new))
- .collect::<Result<Vec<_>, _>>()?;
- let mut sdk_request = TradeRevisionDecisionRequest::new(
- actor,
- request.locator,
- request.revision_id,
- request.decision.clone(),
- app_trade_target_policy(),
- app_trade_publish_mode(),
- app_trade_satisfaction_policy(),
- TradeEvidenceMode::require_explicit_evidence(evidence),
- )
- .with_privacy_confirmation(app_trade_privacy_confirmation(request.confirm_public_note));
- if let Some(idempotency_key) = request.idempotency_key.as_deref() {
- sdk_request = sdk_request
- .try_with_idempotency_key(idempotency_key)
- .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?;
- }
- let outcome = match request.decision {
- RadrootsOrderRevisionOutcome::Accepted => runtime
- .block_on(sdk.trades().buyer().accept_revision(sdk_request))
- .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?,
- RadrootsOrderRevisionOutcome::Declined { .. } => runtime
- .block_on(sdk.trades().buyer().decline_revision(sdk_request))
- .map_err(|error| AppSdkRuntimeIssue::from_sdk_error(&error))?,
- };
- app_sdk_trade_revision_decision_receipt(outcome, request.actor_pubkey)
-}
-
-fn signed_trade_evidence_from_envelope(
- event: RadrootsEventEnvelope,
-) -> Result<RadrootsSignedEvent, AppSdkRuntimeIssue> {
- let raw_json = json!({
- "id": event.id_str(),
- "pubkey": event.author_str(),
- "created_at": event.created_at_u64(),
- "kind": event.kind_u32(),
- "tags": event.tags_as_vec(),
- "content": event.content(),
- "sig": event.sig_str(),
- })
- .to_string();
- RadrootsSignedEvent::new(RadrootsSignedEventParts {
- id: event.id_str().to_owned(),
- pubkey: event.author_str().to_owned(),
- created_at: event.created_at_u64(),
- kind: event.kind_u32(),
- tags: event.tags_as_vec(),
- content: event.content().to_owned(),
- sig: event.sig_str().to_owned(),
- raw_json,
- })
- .map_err(|error| {
- AppSdkRuntimeIssue::from_sdk_error(&RadrootsSdkError::InvalidRequest {
- message: format!("trade revision evidence signed event is invalid: {error}"),
- })
- })
-}
-
fn trade_cancel_with_sdk(
runtime: &tokio::runtime::Runtime,
config: &AppSdkConfig,
@@ -1896,50 +1707,6 @@ fn app_sdk_trade_decision_receipt(
}
}
-fn app_sdk_trade_revision_proposal_receipt(
- outcome: TradeMutationOutcome<TradeRevisionProposalPlan, TradeRevisionProposalReceipt>,
- actor_pubkey: String,
-) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue> {
- match outcome {
- TradeMutationOutcome::Enqueued { receipt }
- | TradeMutationOutcome::Published { receipt, .. } => Ok(AppSdkWorkflowReceipt {
- operation_kind: TRADE_REVISION_PROPOSAL_OPERATION_KIND.to_owned(),
- expected_event_id: receipt.expected_event_id.as_str().to_owned(),
- signed_event_id: receipt.signed_event_id.as_str().to_owned(),
- outbox_operation_id: receipt.outbox_operation_id,
- outbox_event_id: receipt.outbox_event_id,
- state: sdk_mutation_state_key(receipt.state).to_owned(),
- idempotency_digest_prefix: receipt.idempotency_digest_prefix,
- actor_pubkey,
- }),
- TradeMutationOutcome::DryRun { .. } => {
- Err(unexpected_trade_dry_run_issue("trade.revision.propose"))
- }
- }
-}
-
-fn app_sdk_trade_revision_decision_receipt(
- outcome: TradeMutationOutcome<TradeRevisionDecisionPlan, TradeRevisionDecisionReceipt>,
- actor_pubkey: String,
-) -> Result<AppSdkWorkflowReceipt, AppSdkRuntimeIssue> {
- match outcome {
- TradeMutationOutcome::Enqueued { receipt }
- | TradeMutationOutcome::Published { receipt, .. } => Ok(AppSdkWorkflowReceipt {
- operation_kind: TRADE_REVISION_DECISION_OPERATION_KIND.to_owned(),
- expected_event_id: receipt.expected_event_id.as_str().to_owned(),
- signed_event_id: receipt.signed_event_id.as_str().to_owned(),
- outbox_operation_id: receipt.outbox_operation_id,
- outbox_event_id: receipt.outbox_event_id,
- state: sdk_mutation_state_key(receipt.state).to_owned(),
- idempotency_digest_prefix: receipt.idempotency_digest_prefix,
- actor_pubkey,
- }),
- TradeMutationOutcome::DryRun { .. } => {
- Err(unexpected_trade_dry_run_issue("trade.revision.decide"))
- }
- }
-}
-
fn app_sdk_trade_cancellation_receipt(
outcome: TradeMutationOutcome<TradeCancellationPlan, TradeCancellationReceipt>,
actor_pubkey: String,
@@ -2201,12 +1968,16 @@ mod tests {
.storage_paths
.expect("storage paths should be present");
assert_eq!(
- storage_paths.event_store_path,
- storage_root.join("event_store.sqlite")
+ storage_paths.runtime_path,
+ storage_root.join("runtime.sqlite")
+ );
+ assert_eq!(
+ storage_paths.private_path,
+ storage_root.join("private.sqlite")
);
assert_eq!(
- storage_paths.outbox_path,
- storage_root.join("outbox.sqlite")
+ storage_paths.studio_path,
+ storage_root.join("studio.sqlite")
);
let storage = runtime
.storage_status()
diff --git a/crates/store/src/interop.rs b/crates/store/src/interop.rs
@@ -5,23 +5,15 @@ use radroots_event::{
ids::{RadrootsEventId, RadrootsOrderId, RadrootsPublicKey},
kinds::{
KIND_FARM as RADROOTS_KIND_FARM, KIND_LISTING as RADROOTS_KIND_LISTING,
- KIND_LISTING_DRAFT as RADROOTS_KIND_LISTING_DRAFT,
KIND_ORDER_CANCELLATION as RADROOTS_KIND_ORDER_CANCELLATION,
KIND_ORDER_DECISION as RADROOTS_KIND_ORDER_DECISION,
- KIND_ORDER_REQUEST as RADROOTS_KIND_ORDER_REQUEST,
- KIND_ORDER_REVISION_DECISION as RADROOTS_KIND_ORDER_REVISION_DECISION,
- KIND_ORDER_REVISION_PROPOSAL as RADROOTS_KIND_ORDER_REVISION_PROPOSAL,
- KIND_TRADE_VALIDATION_RECEIPT,
- },
- order::{
- RadrootsOrderEconomics, RadrootsOrderItem, RadrootsOrderRequest,
- RadrootsOrderRevisionOutcome,
+ KIND_ORDER_REQUEST as RADROOTS_KIND_ORDER_REQUEST, KIND_TRADE_VALIDATION_RECEIPT,
},
+ order::{RadrootsOrderEconomics, RadrootsOrderItem, RadrootsOrderRequest},
};
use radroots_event_codec::order::{
order_cancellation_from_event, order_decision_from_event, order_event_context_from_tags,
- order_request_from_event, order_revision_decision_from_event,
- order_revision_proposal_from_event,
+ order_request_from_event,
};
use radroots_runtime_store::{
PublishOutboxStatus, RelayDeliveryEvidence, RelayDeliveryState, RuntimeStore,
@@ -37,8 +29,7 @@ use radroots_studio_app_view::{
};
use radroots_trade::order::{
RadrootsOrderCancellationRecord, RadrootsOrderDecisionRecord, RadrootsOrderProjection,
- RadrootsOrderReductionInputs, RadrootsOrderRequestRecord, RadrootsOrderRevisionDecisionRecord,
- RadrootsOrderRevisionProposalRecord, reduce_order_events,
+ RadrootsOrderReductionInputs, RadrootsOrderRequestRecord, reduce_order_events,
};
use radroots_trade::validation_receipt::{
RadrootsTradeValidationReceipt, RadrootsValidationReceiptTags, validation_receipt_from_event,
@@ -56,20 +47,12 @@ const RUNTIME_STORE_BATCH_LIMIT: u32 = 500;
const APP_LOCAL_INTEROP_CURSOR_ID: &str = "radroots_studio_app_sqlite_projection_v1";
const KIND_FARM: i64 = RADROOTS_KIND_FARM as i64;
const KIND_LISTING: i64 = RADROOTS_KIND_LISTING as i64;
-const KIND_LISTING_DRAFT: i64 = RADROOTS_KIND_LISTING_DRAFT as i64;
const KIND_ORDER_REQUEST: i64 = RADROOTS_KIND_ORDER_REQUEST as i64;
const KIND_ORDER_DECISION: i64 = RADROOTS_KIND_ORDER_DECISION as i64;
-const KIND_ORDER_REVISION: i64 = RADROOTS_KIND_ORDER_REVISION_PROPOSAL as i64;
-const KIND_ORDER_REVISION_DECISION: i64 = RADROOTS_KIND_ORDER_REVISION_DECISION as i64;
const KIND_ORDER_CANCEL: i64 = RADROOTS_KIND_ORDER_CANCELLATION as i64;
const KIND_VALIDATION_RECEIPT: i64 = KIND_TRADE_VALIDATION_RECEIPT as i64;
-const ACTIVE_ORDER_EVENT_KINDS: [i64; 5] = [
- KIND_ORDER_REQUEST,
- KIND_ORDER_DECISION,
- KIND_ORDER_REVISION,
- KIND_ORDER_REVISION_DECISION,
- KIND_ORDER_CANCEL,
-];
+const ACTIVE_ORDER_EVENT_KINDS: [i64; 3] =
+ [KIND_ORDER_REQUEST, KIND_ORDER_DECISION, KIND_ORDER_CANCEL];
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct AppLocalInteropImportReport {
@@ -762,7 +745,7 @@ impl<'a> AppLocalInteropRepository<'a> {
) -> Result<Option<ProjectionRecord>, AppSqliteError> {
match record.event_kind {
Some(KIND_FARM) => self.import_signed_farm(record),
- Some(KIND_LISTING | KIND_LISTING_DRAFT) => self.import_signed_listing(record),
+ Some(KIND_LISTING) => self.import_signed_listing(record),
Some(KIND_VALIDATION_RECEIPT) => self.import_signed_validation_receipt(record),
Some(kind) if active_order_event_kind(kind) => self.import_signed_active_order(record),
_ => Ok(Some(ProjectionRecord {
@@ -1185,8 +1168,6 @@ impl<'a> AppLocalInteropRepository<'a> {
);
let buckets = ActiveOrderEvidenceBuckets::from_evidence(evidence);
let requests = buckets.requests.clone();
- let revision_proposals = buckets.revision_proposals.clone();
- let revision_decisions = buckets.revision_decisions.clone();
let reducer_order_id =
raw_order_id
.parse::<RadrootsOrderId>()
@@ -1199,8 +1180,6 @@ impl<'a> AppLocalInteropRepository<'a> {
RadrootsOrderReductionInputs {
requests: buckets.requests,
decisions: buckets.decisions,
- revision_proposals: buckets.revision_proposals,
- revision_decisions: buckets.revision_decisions,
cancellations: buckets.cancellations,
},
);
@@ -1210,16 +1189,9 @@ impl<'a> AppLocalInteropRepository<'a> {
.find(|request| request.event_id == event_id)
.map(|request| &request.payload)
});
- let revision =
- active_order_revision_status(&projection, &revision_proposals, &revision_decisions);
- let agreement_source = request_payload.map(|request| {
- active_order_agreement_source(
- request,
- &projection,
- &revision_proposals,
- &revision_decisions,
- )
- });
+ let revision = active_order_change_status(&projection);
+ let agreement_source =
+ request_payload.map(|request| active_order_agreement_source(request, &projection));
self.apply_active_order_projection(
order_id,
&projection,
@@ -2813,8 +2785,6 @@ struct ExistingOrderLineMetadata {
enum ActiveOrderEvidence {
Request(RadrootsOrderRequestRecord),
Decision(RadrootsOrderDecisionRecord),
- RevisionProposal(RadrootsOrderRevisionProposalRecord),
- RevisionDecision(RadrootsOrderRevisionDecisionRecord),
Cancellation(RadrootsOrderCancellationRecord),
}
@@ -2823,8 +2793,6 @@ impl ActiveOrderEvidence {
match self {
Self::Request(record) => record.event_id.as_str(),
Self::Decision(record) => record.event_id.as_str(),
- Self::RevisionProposal(record) => record.event_id.as_str(),
- Self::RevisionDecision(record) => record.event_id.as_str(),
Self::Cancellation(record) => record.event_id.as_str(),
}
}
@@ -2833,8 +2801,6 @@ impl ActiveOrderEvidence {
match self {
Self::Request(record) => record.event_id.as_str(),
Self::Decision(record) => record.root_event_id.as_str(),
- Self::RevisionProposal(record) => record.root_event_id.as_str(),
- Self::RevisionDecision(record) => record.root_event_id.as_str(),
Self::Cancellation(record) => record.root_event_id.as_str(),
}
}
@@ -2851,16 +2817,6 @@ impl ActiveOrderEvidence {
record.payload.buyer_pubkey.as_str(),
record.root_event_id.as_str(),
),
- Self::RevisionProposal(record) => (
- record.payload.order_id.as_str(),
- record.payload.buyer_pubkey.as_str(),
- record.root_event_id.as_str(),
- ),
- Self::RevisionDecision(record) => (
- record.payload.order_id.as_str(),
- record.payload.buyer_pubkey.as_str(),
- record.root_event_id.as_str(),
- ),
Self::Cancellation(record) => (
record.payload.order_id.as_str(),
record.payload.buyer_pubkey.as_str(),
@@ -2874,8 +2830,6 @@ impl ActiveOrderEvidence {
struct ActiveOrderEvidenceBuckets {
requests: Vec<RadrootsOrderRequestRecord>,
decisions: Vec<RadrootsOrderDecisionRecord>,
- revision_proposals: Vec<RadrootsOrderRevisionProposalRecord>,
- revision_decisions: Vec<RadrootsOrderRevisionDecisionRecord>,
cancellations: Vec<RadrootsOrderCancellationRecord>,
}
@@ -2886,12 +2840,6 @@ impl ActiveOrderEvidenceBuckets {
match record {
ActiveOrderEvidence::Request(record) => buckets.requests.push(record),
ActiveOrderEvidence::Decision(record) => buckets.decisions.push(record),
- ActiveOrderEvidence::RevisionProposal(record) => {
- buckets.revision_proposals.push(record);
- }
- ActiveOrderEvidence::RevisionDecision(record) => {
- buckets.revision_decisions.push(record);
- }
ActiveOrderEvidence::Cancellation(record) => buckets.cancellations.push(record),
}
}
@@ -3078,36 +3026,6 @@ fn active_order_evidence_from_event(event: &RadrootsEventEnvelope) -> Option<Act
payload: envelope.payload,
}))
}
- KIND_ORDER_REVISION => {
- let envelope = order_revision_proposal_from_event(event).ok()?;
- let tags = event.tags_as_vec();
- let context = order_event_context_from_tags(envelope.message_type, &tags).ok()?;
- Some(ActiveOrderEvidence::RevisionProposal(
- RadrootsOrderRevisionProposalRecord {
- event_id: active_event_id(event)?,
- author_pubkey: active_author_pubkey(event)?,
- counterparty_pubkey: context.counterparty_pubkey,
- root_event_id: context.root_event_id?,
- prev_event_id: context.prev_event_id?,
- payload: envelope.payload,
- },
- ))
- }
- KIND_ORDER_REVISION_DECISION => {
- let envelope = order_revision_decision_from_event(event).ok()?;
- let tags = event.tags_as_vec();
- let context = order_event_context_from_tags(envelope.message_type, &tags).ok()?;
- Some(ActiveOrderEvidence::RevisionDecision(
- RadrootsOrderRevisionDecisionRecord {
- event_id: active_event_id(event)?,
- author_pubkey: active_author_pubkey(event)?,
- counterparty_pubkey: context.counterparty_pubkey,
- root_event_id: context.root_event_id?,
- prev_event_id: context.prev_event_id?,
- payload: envelope.payload,
- },
- ))
- }
KIND_ORDER_CANCEL => {
let envelope = order_cancellation_from_event(event).ok()?;
let tags = event.tags_as_vec();
@@ -3325,76 +3243,14 @@ fn projected_order_id(order_id: &str, buyer_pubkey: &str, root_event_id: &str) -
projected_order_id_from_trade_request(order_id, buyer_pubkey, root_event_id)
}
-fn active_order_revision_status(
- projection: &RadrootsOrderProjection,
- revision_proposals: &[RadrootsOrderRevisionProposalRecord],
- revision_decisions: &[RadrootsOrderRevisionDecisionRecord],
-) -> TradeRevisionStatus {
- let Some(mut parent_event_id) = projection
- .decision_event_id
- .clone()
- .or_else(|| projection.request_event_id.clone())
- else {
- return TradeRevisionStatus::None;
- };
- let mut status = TradeRevisionStatus::None;
- loop {
- let matching_proposals = revision_proposals
- .iter()
- .filter(|proposal| proposal.prev_event_id == parent_event_id)
- .collect::<Vec<_>>();
- let proposal = match matching_proposals.as_slice() {
- [] => return status,
- [proposal] => *proposal,
- _ => return TradeRevisionStatus::None,
- };
- let matching_decisions = revision_decisions
- .iter()
- .filter(|decision| decision.prev_event_id == proposal.event_id)
- .collect::<Vec<_>>();
- let decision = match matching_decisions.as_slice() {
- [] => return TradeRevisionStatus::ChangeProposed,
- [decision] => *decision,
- _ => return TradeRevisionStatus::None,
- };
- if decision.payload.revision_id != proposal.payload.revision_id {
- return TradeRevisionStatus::None;
- }
- status = match &decision.payload.decision {
- RadrootsOrderRevisionOutcome::Accepted => TradeRevisionStatus::Updated,
- RadrootsOrderRevisionOutcome::Declined { .. } => TradeRevisionStatus::KeptAsPlaced,
- };
- parent_event_id.clone_from(&decision.event_id);
- }
+fn active_order_change_status(_projection: &RadrootsOrderProjection) -> TradeRevisionStatus {
+ TradeRevisionStatus::None
}
fn active_order_agreement_source(
request: &RadrootsOrderRequest,
- projection: &RadrootsOrderProjection,
- revision_proposals: &[RadrootsOrderRevisionProposalRecord],
- revision_decisions: &[RadrootsOrderRevisionDecisionRecord],
+ _projection: &RadrootsOrderProjection,
) -> ActiveOrderAgreementSource {
- if let Some(agreement_event_id) = projection.agreement_event_id.as_deref()
- && projection.decision_event_id.as_deref() != Some(agreement_event_id)
- && let Some(revision_decision) = revision_decisions.iter().find(|decision| {
- decision.event_id == agreement_event_id
- && matches!(
- &decision.payload.decision,
- RadrootsOrderRevisionOutcome::Accepted
- )
- })
- && let Some(revision_proposal) = revision_proposals.iter().find(|proposal| {
- proposal.event_id == revision_decision.prev_event_id
- && proposal.payload.revision_id == revision_decision.payload.revision_id
- })
- {
- return ActiveOrderAgreementSource {
- listing_addr: revision_proposal.payload.listing_addr.to_string(),
- seller_pubkey: revision_proposal.payload.seller_pubkey.to_string(),
- items: revision_proposal.payload.items.clone(),
- economics: revision_proposal.payload.economics.clone(),
- };
- }
ActiveOrderAgreementSource {
listing_addr: request.listing_addr.to_string(),
seller_pubkey: request.seller_pubkey.to_string(),
@@ -3884,20 +3740,18 @@ mod tests {
RadrootsEventEnvelope, RadrootsEventEnvelopeParts, RadrootsEventPtr,
ids::{
RadrootsEventId, RadrootsInventoryBinId, RadrootsListingAddress, RadrootsOrderId,
- RadrootsOrderQuoteId, RadrootsOrderRevisionId, RadrootsPublicKey,
+ RadrootsOrderQuoteId, RadrootsPublicKey,
},
order::{
RadrootsOrderCancellation, RadrootsOrderDecision, RadrootsOrderDecisionOutcome,
RadrootsOrderEconomicItem, RadrootsOrderEconomicLine, RadrootsOrderEconomics,
RadrootsOrderInventoryCommitment, RadrootsOrderItem, RadrootsOrderPricingBasis,
- RadrootsOrderRequest, RadrootsOrderRevisionDecision, RadrootsOrderRevisionOutcome,
- RadrootsOrderRevisionProposal,
+ RadrootsOrderRequest,
},
wire::RadrootsNip01EventWireParts as WireEventParts,
};
use radroots_event_codec::order::{
order_cancellation_event_build, order_decision_event_build, order_request_event_build,
- order_revision_decision_event_build, order_revision_proposal_event_build,
};
use radroots_runtime_store::{
PublishOutboxStatus, RelayDeliveryEvidence, RuntimeStore, RuntimeStoreRecordFamily,
@@ -3907,9 +3761,8 @@ mod tests {
use radroots_studio_app_view::{
BuyerContext, BuyerOrderStatus, FarmId, FarmOrderMethod, OrderId, OrderStatus,
OrdersFilter, OrdersScreenQueryState, ProductAvailabilityState, ProductId,
- TradeAgreementStatus, TradeInventoryStatus, TradeRevisionStatus,
- TradeValidationReceiptProofSystem, TradeValidationReceiptResult,
- TradeValidationReceiptType, TradeWorkflowSource,
+ TradeAgreementStatus, TradeInventoryStatus, TradeValidationReceiptProofSystem,
+ TradeValidationReceiptResult, TradeValidationReceiptType, TradeWorkflowSource,
};
use radroots_trade::validation_receipt::{
RadrootsTradeValidationReceipt, RadrootsValidationReceiptProof,
@@ -4401,10 +4254,6 @@ mod tests {
raw.parse().expect("valid order id")
}
- fn typed_revision_id(raw: &str) -> RadrootsOrderRevisionId {
- raw.parse().expect("valid revision id")
- }
-
fn typed_quote_id(raw: &str) -> RadrootsOrderQuoteId {
raw.parse().expect("valid quote id")
}
@@ -4508,62 +4357,6 @@ mod tests {
}
}
- fn revision_proposal_payload(
- revision_id: &str,
- order_id: &str,
- listing_addr: &str,
- buyer_pubkey: &str,
- seller_pubkey: &str,
- root_event_id: &str,
- prev_event_id: &str,
- ) -> RadrootsOrderRevisionProposal {
- let mut request =
- order_request_payload(order_id, listing_addr, buyer_pubkey, seller_pubkey);
- request.items[0].bin_count = 3;
- request.economics.quote_id =
- typed_quote_id(format!("quote-{order_id}-{revision_id}").as_str());
- request.economics.quote_version = 2;
- request.economics.items[0].bin_count = 3;
- request.economics.items[0].line_subtotal = usd("24");
- request.economics.subtotal = usd("24");
- request.economics.total = usd("24");
- RadrootsOrderRevisionProposal {
- revision_id: typed_revision_id(revision_id),
- order_id: typed_order_id(order_id),
- listing_addr: typed_listing_addr(listing_addr),
- buyer_pubkey: typed_pubkey(buyer_pubkey),
- seller_pubkey: typed_pubkey(seller_pubkey),
- root_event_id: typed_event_id(root_event_id),
- prev_event_id: typed_event_id(prev_event_id),
- items: request.items,
- economics: request.economics,
- reason: "seller confirmed updated pickup details".to_owned(),
- }
- }
-
- #[expect(clippy::too_many_arguments)]
- fn revision_decision_payload(
- revision_id: &str,
- order_id: &str,
- listing_addr: &str,
- buyer_pubkey: &str,
- seller_pubkey: &str,
- root_event_id: &str,
- prev_event_id: &str,
- decision: RadrootsOrderRevisionOutcome,
- ) -> RadrootsOrderRevisionDecision {
- RadrootsOrderRevisionDecision {
- revision_id: typed_revision_id(revision_id),
- order_id: typed_order_id(order_id),
- listing_addr: typed_listing_addr(listing_addr),
- buyer_pubkey: typed_pubkey(buyer_pubkey),
- seller_pubkey: typed_pubkey(seller_pubkey),
- root_event_id: typed_event_id(root_event_id),
- prev_event_id: typed_event_id(prev_event_id),
- decision,
- }
- }
-
fn order_cancel_payload(
order_id: &str,
listing_addr: &str,
@@ -4814,6 +4607,13 @@ mod tests {
listing_event_id: listing_event_id.to_owned(),
root_event_id: root_event_id.to_owned(),
target_event_id: target_event_id.to_owned(),
+ validator_set_addr: radroots_trade::validation_receipt::validator_set_address_from_str(
+ "30381:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd:018f3d99-7d35-7c0c-8a0f-7f3b645abcde",
+ )
+ .expect("validator set address"),
+ validator_set_event_id:
+ "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"
+ .to_owned(),
statement_type: RadrootsValidationReceiptType::TradeTransition,
},
version: VALIDATION_RECEIPT_VERSION,
@@ -6091,194 +5891,6 @@ mod tests {
}
#[test]
- fn active_order_revision_projects_through_cli_reducer_state() {
- let app_store =
- AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store");
- let events = runtime_store_store();
- let farm_key = "EEEEEEEEEEEEEEEEEEEEEE";
- let listing_key = "AAAAAAAAAAAAAAAAAAAAAw";
- let seller_pubkey = test_pubkey("seller-pubkey");
- let seller_pubkey = seller_pubkey.as_str();
- let buyer_pubkey = test_pubkey("app-buyer-pubkey");
- let buyer_pubkey = buyer_pubkey.as_str();
- let order_id_raw = "active-revision-order-1";
- let listing_addr = format!("30402:{seller_pubkey}:{listing_key}");
- events
- .append_record(&signed_market_listing_record(
- "active-revision-listing",
- seller_pubkey,
- farm_key,
- listing_key,
- "Revision Eggs",
- "9",
- "active",
- "pickup",
- "North barn pickup",
- 4_102_444_800,
- 4_102_531_200,
- RuntimeStoreRecordStatus::Published,
- PublishOutboxStatus::Acknowledged,
- ))
- .expect("append revision listing");
- app_store
- .import_shared_runtime_store_from_store(&events)
- .expect("import revision listing");
-
- let request_payload = order_request_payload(
- order_id_raw,
- listing_addr.as_str(),
- buyer_pubkey,
- seller_pubkey,
- );
- let request_parts = order_request_event_build(
- &listing_event_ptr("active-revision-listing-event"),
- &request_payload,
- )
- .expect("build revision order request");
- let request_event =
- event_from_parts("active-revision-request-event", buyer_pubkey, request_parts);
- events
- .append_record(&signed_order_event_record(
- "app:signed_event:active-revision:request",
- &request_event,
- listing_addr.as_str(),
- SourceRuntime::App,
- Some("acct_revision"),
- ))
- .expect("append revision order request");
- app_store
- .import_shared_runtime_store_from_store(&events)
- .expect("import revision order request");
-
- let proposal_payload = revision_proposal_payload(
- "revision-1",
- order_id_raw,
- listing_addr.as_str(),
- buyer_pubkey,
- seller_pubkey,
- request_event.id_str(),
- request_event.id_str(),
- );
- let proposal_parts = order_revision_proposal_event_build(
- &typed_event_id(request_event.id_str()),
- &typed_event_id(request_event.id_str()),
- &proposal_payload,
- )
- .expect("build revision proposal");
- let proposal_event = event_from_parts(
- "active-revision-proposal-event",
- seller_pubkey,
- proposal_parts,
- );
- events
- .append_record(&signed_order_event_record(
- "cli:signed_event:active-revision:proposal",
- &proposal_event,
- listing_addr.as_str(),
- SourceRuntime::Cli,
- None,
- ))
- .expect("append revision proposal");
- app_store
- .import_shared_runtime_store_from_store(&events)
- .expect("import revision proposal");
-
- let seller_farm_id = deterministic_farm_id(Some(seller_pubkey), farm_key);
- let order_id = projected_order_id(order_id_raw, buyer_pubkey, request_event.id_str());
- let buyer_context = BuyerContext::account("acct_revision");
- let seller_orders = app_store
- .load_orders_list(
- seller_farm_id,
- &OrdersScreenQueryState {
- filter: OrdersFilter::All,
- fulfillment_window_id: None,
- },
- )
- .expect("load revision seller orders after proposal");
- assert_eq!(seller_orders.rows[0].status, OrderStatus::NeedsAction);
- assert_eq!(
- seller_orders.rows[0].workflow.revision,
- TradeRevisionStatus::ChangeProposed
- );
- let buyer_detail = app_store
- .load_buyer_order_detail(&buyer_context, order_id)
- .expect("load revision buyer detail after proposal")
- .expect("revision buyer detail after proposal");
- assert_eq!(
- buyer_detail.workflow.revision,
- TradeRevisionStatus::ChangeProposed
- );
- assert_eq!(buyer_detail.economics.total_minor_units, Some(1600));
-
- let revision_decision_payload = revision_decision_payload(
- "revision-1",
- order_id_raw,
- listing_addr.as_str(),
- buyer_pubkey,
- seller_pubkey,
- request_event.id_str(),
- proposal_event.id_str(),
- RadrootsOrderRevisionOutcome::Accepted,
- );
- let revision_decision_parts = order_revision_decision_event_build(
- &typed_event_id(request_event.id_str()),
- &typed_event_id(proposal_event.id_str()),
- &revision_decision_payload,
- )
- .expect("build revision decision");
- let revision_decision_event = event_from_parts(
- "active-revision-decision-response-event",
- buyer_pubkey,
- revision_decision_parts,
- );
- events
- .append_record(&signed_order_event_record(
- "app:signed_event:active-revision:decision-response",
- &revision_decision_event,
- listing_addr.as_str(),
- SourceRuntime::App,
- Some("acct_revision"),
- ))
- .expect("append revision decision");
- app_store
- .import_shared_runtime_store_from_store(&events)
- .expect("import revision decision");
- let seller_orders = app_store
- .load_orders_list(
- seller_farm_id,
- &OrdersScreenQueryState {
- filter: OrdersFilter::All,
- fulfillment_window_id: None,
- },
- )
- .expect("load revision seller orders after decision");
- assert_eq!(seller_orders.rows[0].status, OrderStatus::NeedsAction);
- assert_eq!(
- seller_orders.rows[0].workflow.agreement,
- TradeAgreementStatus::AgreedPendingValidation
- );
- assert_eq!(
- seller_orders.rows[0].workflow.revision,
- TradeRevisionStatus::Updated
- );
- let seller_detail = app_store
- .load_order_detail(seller_farm_id, order_id)
- .expect("load revision seller detail after decision")
- .expect("revision seller detail after decision");
- let buyer_detail = app_store
- .load_buyer_order_detail(&buyer_context, order_id)
- .expect("load revision buyer detail after decision")
- .expect("revision buyer detail after decision");
- assert_eq!(
- seller_detail.workflow.revision,
- TradeRevisionStatus::Updated
- );
- assert_eq!(seller_detail.economics.total_minor_units, Some(2400));
- assert_eq!(buyer_detail.workflow.revision, TradeRevisionStatus::Updated);
- assert_eq!(buyer_detail.economics.total_minor_units, Some(2400));
- }
-
- #[test]
fn active_order_pre_agreement_cancellation_projects_through_cli_reducer_state() {
let app_store =
AppSqliteStore::open(DatabaseTarget::InMemory).expect("open app sqlite store");
diff --git a/crates/sync/src/lib.rs b/crates/sync/src/lib.rs
@@ -5,9 +5,8 @@ mod publish;
pub use publish::{
AppFarmProfilePublishPayload, AppListingPublishPayload, AppOrderCancellationPublishPayload,
AppOrderDecisionInventoryCommitment, AppOrderDecisionPayload, AppOrderDecisionPublishPayload,
- AppOrderRequestItemPayload, AppOrderRequestPublishPayload,
- AppOrderRevisionDecisionPublishPayload, AppOrderRevisionProposalPublishPayload,
- AppPublishContext, AppPublishPayload, AppPublishPayloadJsonError, AppPublishValidationFailure,
+ AppOrderRequestItemPayload, AppOrderRequestPublishPayload, AppPublishContext,
+ AppPublishPayload, AppPublishPayloadJsonError, AppPublishValidationFailure,
AppPublishValidationFailureSet, AppPublishWorkKind,
};
diff --git a/crates/sync/src/publish.rs b/crates/sync/src/publish.rs
@@ -1,10 +1,6 @@
-use radroots_event::order::{
- RadrootsOrderEconomics, RadrootsOrderItem, RadrootsOrderRevisionOutcome,
-};
use radroots_sdk::{
FARM_PUBLISH_OPERATION_KIND, LISTING_PUBLISH_OPERATION_KIND, TRADE_CANCELLATION_OPERATION_KIND,
- TRADE_DECISION_OPERATION_KIND, TRADE_REVISION_DECISION_OPERATION_KIND,
- TRADE_REVISION_PROPOSAL_OPERATION_KIND, TRADE_SUBMIT_OPERATION_KIND,
+ TRADE_DECISION_OPERATION_KIND, TRADE_SUBMIT_OPERATION_KIND,
};
use radroots_studio_app_view::{
FarmId, FarmReadiness, FulfillmentWindowId, OrderId, ProductId, ProductStatus,
@@ -21,8 +17,6 @@ pub enum AppPublishWorkKind {
Listing,
OrderRequest,
OrderDecision,
- OrderRevisionProposal,
- OrderRevisionDecision,
OrderCancellation,
}
@@ -33,8 +27,6 @@ impl AppPublishWorkKind {
Self::Listing => "listing",
Self::OrderRequest => "order_request",
Self::OrderDecision => "order_decision",
- Self::OrderRevisionProposal => "order_revision_proposal",
- Self::OrderRevisionDecision => "order_revision_decision",
Self::OrderCancellation => "order_cancellation",
}
}
@@ -45,8 +37,6 @@ impl AppPublishWorkKind {
Self::Listing => LISTING_PUBLISH_OPERATION_KIND,
Self::OrderRequest => TRADE_SUBMIT_OPERATION_KIND,
Self::OrderDecision => TRADE_DECISION_OPERATION_KIND,
- Self::OrderRevisionProposal => TRADE_REVISION_PROPOSAL_OPERATION_KIND,
- Self::OrderRevisionDecision => TRADE_REVISION_DECISION_OPERATION_KIND,
Self::OrderCancellation => TRADE_CANCELLATION_OPERATION_KIND,
}
}
@@ -182,38 +172,6 @@ pub struct AppOrderDecisionPublishPayload {
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
-pub struct AppOrderRevisionProposalPublishPayload {
- pub context: AppPublishContext,
- pub app_order_id: OrderId,
- pub farm_id: FarmId,
- pub trade_order_id: String,
- pub request_event_id: String,
- pub revision_id: String,
- pub listing_addr: String,
- pub buyer_pubkey: String,
- pub seller_pubkey: String,
- pub items: Vec<RadrootsOrderItem>,
- pub economics: RadrootsOrderEconomics,
- pub reason: String,
- pub confirm_public_note: bool,
-}
-
-#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
-pub struct AppOrderRevisionDecisionPublishPayload {
- pub context: AppPublishContext,
- pub app_order_id: OrderId,
- pub farm_id: FarmId,
- pub trade_order_id: String,
- pub request_event_id: String,
- pub revision_id: String,
- pub listing_addr: String,
- pub buyer_pubkey: String,
- pub seller_pubkey: String,
- pub decision: RadrootsOrderRevisionOutcome,
- pub confirm_public_note: bool,
-}
-
-#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct AppOrderCancellationPublishPayload {
pub context: AppPublishContext,
pub app_order_id: OrderId,
@@ -234,8 +192,6 @@ pub enum AppPublishPayload {
Listing(AppListingPublishPayload),
OrderRequest(AppOrderRequestPublishPayload),
OrderDecision(AppOrderDecisionPublishPayload),
- OrderRevisionProposal(AppOrderRevisionProposalPublishPayload),
- OrderRevisionDecision(AppOrderRevisionDecisionPublishPayload),
OrderCancellation(AppOrderCancellationPublishPayload),
}
@@ -246,8 +202,6 @@ impl AppPublishPayload {
Self::Listing(_) => AppPublishWorkKind::Listing,
Self::OrderRequest(_) => AppPublishWorkKind::OrderRequest,
Self::OrderDecision(_) => AppPublishWorkKind::OrderDecision,
- Self::OrderRevisionProposal(_) => AppPublishWorkKind::OrderRevisionProposal,
- Self::OrderRevisionDecision(_) => AppPublishWorkKind::OrderRevisionDecision,
Self::OrderCancellation(_) => AppPublishWorkKind::OrderCancellation,
}
}
@@ -262,8 +216,6 @@ impl AppPublishPayload {
Self::Listing(payload) => SyncAggregateRef::Product(payload.product_id),
Self::OrderRequest(payload) => SyncAggregateRef::Order(payload.order_id),
Self::OrderDecision(payload) => SyncAggregateRef::Order(payload.app_order_id),
- Self::OrderRevisionProposal(payload) => SyncAggregateRef::Order(payload.app_order_id),
- Self::OrderRevisionDecision(payload) => SyncAggregateRef::Order(payload.app_order_id),
Self::OrderCancellation(payload) => SyncAggregateRef::Order(payload.app_order_id),
}
}
@@ -430,51 +382,6 @@ impl AppPublishPayload {
}
}
}
- Self::OrderRevisionProposal(payload) => {
- validate_lifecycle_order_fields(
- &payload.context,
- payload.trade_order_id.as_str(),
- payload.request_event_id.as_str(),
- payload.listing_addr.as_str(),
- payload.buyer_pubkey.as_str(),
- payload.seller_pubkey.as_str(),
- &mut failures,
- );
- if payload.revision_id.trim().is_empty() {
- failures.push(AppPublishValidationFailure::MissingOrderRevisionId);
- }
- if payload.items.is_empty()
- || payload
- .items
- .iter()
- .any(|item| item.bin_id.trim().is_empty() || item.bin_count == 0)
- {
- failures.push(AppPublishValidationFailure::MissingOrderRevisionItems);
- }
- if payload.economics.validate().is_err() {
- failures.push(AppPublishValidationFailure::InvalidOrderRevisionEconomics);
- }
- if payload.reason.trim().is_empty() {
- failures.push(AppPublishValidationFailure::MissingOrderRevisionReason);
- }
- }
- Self::OrderRevisionDecision(payload) => {
- validate_lifecycle_order_fields(
- &payload.context,
- payload.trade_order_id.as_str(),
- payload.request_event_id.as_str(),
- payload.listing_addr.as_str(),
- payload.buyer_pubkey.as_str(),
- payload.seller_pubkey.as_str(),
- &mut failures,
- );
- if payload.revision_id.trim().is_empty() {
- failures.push(AppPublishValidationFailure::MissingOrderRevisionId);
- }
- if payload.decision.validate().is_err() {
- failures.push(AppPublishValidationFailure::MissingOrderRevisionDecisionReason);
- }
- }
Self::OrderCancellation(payload) => {
validate_lifecycle_order_fields(
&payload.context,
@@ -567,11 +474,6 @@ pub enum AppPublishValidationFailure {
MissingOrderRequestEventId,
MissingOrderDecisionInventory,
MissingOrderDeclineReason,
- MissingOrderRevisionId,
- MissingOrderRevisionItems,
- InvalidOrderRevisionEconomics,
- MissingOrderRevisionReason,
- MissingOrderRevisionDecisionReason,
MissingOrderCancellationReason,
}
@@ -605,11 +507,6 @@ impl AppPublishValidationFailure {
Self::MissingOrderRequestEventId => "missing_order_request_event_id",
Self::MissingOrderDecisionInventory => "missing_order_decision_inventory",
Self::MissingOrderDeclineReason => "missing_order_decline_reason",
- Self::MissingOrderRevisionId => "missing_order_revision_id",
- Self::MissingOrderRevisionItems => "missing_order_revision_items",
- Self::InvalidOrderRevisionEconomics => "invalid_order_revision_economics",
- Self::MissingOrderRevisionReason => "missing_order_revision_reason",
- Self::MissingOrderRevisionDecisionReason => "missing_order_revision_decision_reason",
Self::MissingOrderCancellationReason => "missing_order_cancellation_reason",
}
}
@@ -664,20 +561,14 @@ mod tests {
use super::{
AppFarmProfilePublishPayload, AppListingPublishPayload, AppOrderCancellationPublishPayload,
AppOrderDecisionPayload, AppOrderDecisionPublishPayload, AppOrderRequestItemPayload,
- AppOrderRequestPublishPayload, AppOrderRevisionDecisionPublishPayload,
- AppOrderRevisionProposalPublishPayload, AppPublishContext, AppPublishPayload,
+ AppOrderRequestPublishPayload, AppPublishContext, AppPublishPayload,
AppPublishValidationFailure, AppPublishWorkKind, FARM_PUBLISH_OPERATION_KIND,
TRADE_CANCELLATION_OPERATION_KIND, TRADE_DECISION_OPERATION_KIND,
- TRADE_REVISION_DECISION_OPERATION_KIND, TRADE_REVISION_PROPOSAL_OPERATION_KIND,
};
use crate::{
PendingSyncOperation, PendingSyncOperationState, SyncAggregateRef, SyncOperationKind,
};
- use radroots_event::order::{
- RadrootsOrderEconomics, RadrootsOrderItem, RadrootsOrderRevisionOutcome,
- };
use radroots_studio_app_view::{FarmId, FarmReadiness, OrderId, ProductId, ProductStatus};
- use serde_json::json;
#[test]
fn publish_payload_serializes_with_stable_kind_and_sdk_target() {
@@ -720,19 +611,15 @@ mod tests {
AppPublishWorkKind::Listing,
AppPublishWorkKind::OrderRequest,
AppPublishWorkKind::OrderDecision,
- AppPublishWorkKind::OrderRevisionProposal,
- AppPublishWorkKind::OrderRevisionDecision,
AppPublishWorkKind::OrderCancellation,
];
- assert_eq!(work_kinds.len(), 7);
+ assert_eq!(work_kinds.len(), 5);
assert_eq!(work_kinds[0].storage_key(), "farm_profile");
assert_eq!(work_kinds[1].storage_key(), "listing");
assert_eq!(work_kinds[2].storage_key(), "order_request");
assert_eq!(work_kinds[3].storage_key(), "order_decision");
- assert_eq!(work_kinds[4].storage_key(), "order_revision_proposal");
- assert_eq!(work_kinds[5].storage_key(), "order_revision_decision");
- assert_eq!(work_kinds[6].storage_key(), "order_cancellation");
+ assert_eq!(work_kinds[4].storage_key(), "order_cancellation");
}
#[test]
@@ -955,115 +842,6 @@ mod tests {
}
#[test]
- fn order_revision_publish_payloads_report_stable_validation_reason_codes() {
- let order_id = OrderId::generate();
- let farm_id = FarmId::generate();
- let economics = revision_economics();
- let valid_proposal =
- AppPublishPayload::OrderRevisionProposal(AppOrderRevisionProposalPublishPayload {
- context: AppPublishContext::new("acct_seller", "seller_order_revision_proposal"),
- app_order_id: order_id,
- farm_id,
- trade_order_id: "order-1".to_owned(),
- request_event_id: "request-event-1".to_owned(),
- revision_id: "revision-1".to_owned(),
- listing_addr: "30402:seller:listing".to_owned(),
- buyer_pubkey: "buyer".to_owned(),
- seller_pubkey: "seller".to_owned(),
- items: vec![RadrootsOrderItem {
- bin_id: "bin-1".parse().expect("valid bin id"),
- bin_count: 2,
- }],
- economics: economics.clone(),
- reason: "harvest count updated".to_owned(),
- confirm_public_note: false,
- });
- let invalid_proposal =
- AppPublishPayload::OrderRevisionProposal(AppOrderRevisionProposalPublishPayload {
- context: AppPublishContext::new("", ""),
- app_order_id: order_id,
- farm_id,
- trade_order_id: " ".to_owned(),
- request_event_id: String::new(),
- revision_id: String::new(),
- listing_addr: String::new(),
- buyer_pubkey: String::new(),
- seller_pubkey: String::new(),
- items: Vec::new(),
- economics: economics.clone(),
- reason: " ".to_owned(),
- confirm_public_note: false,
- });
- let invalid_decision =
- AppPublishPayload::OrderRevisionDecision(AppOrderRevisionDecisionPublishPayload {
- context: AppPublishContext::new("", ""),
- app_order_id: order_id,
- farm_id,
- trade_order_id: " ".to_owned(),
- request_event_id: String::new(),
- revision_id: String::new(),
- listing_addr: String::new(),
- buyer_pubkey: String::new(),
- seller_pubkey: String::new(),
- decision: RadrootsOrderRevisionOutcome::Declined {
- reason: " ".to_owned(),
- },
- confirm_public_note: false,
- });
-
- assert_eq!(
- valid_proposal.work_kind().sdk_operation(),
- TRADE_REVISION_PROPOSAL_OPERATION_KIND
- );
- assert_eq!(valid_proposal.validation_failures(), Vec::new());
- assert_eq!(
- invalid_decision.work_kind().sdk_operation(),
- TRADE_REVISION_DECISION_OPERATION_KIND
- );
-
- let proposal_reason_codes: Vec<&str> = invalid_proposal
- .validation_failures()
- .into_iter()
- .map(AppPublishValidationFailure::storage_key)
- .collect();
- let decision_reason_codes: Vec<&str> = invalid_decision
- .validation_failures()
- .into_iter()
- .map(AppPublishValidationFailure::storage_key)
- .collect();
-
- assert_eq!(
- proposal_reason_codes,
- vec![
- "missing_account_id",
- "missing_source",
- "missing_order_trade_order_id",
- "missing_order_request_event_id",
- "missing_order_listing_address",
- "missing_order_buyer_pubkey",
- "missing_order_seller_pubkey",
- "missing_order_revision_id",
- "missing_order_revision_items",
- "missing_order_revision_reason",
- ]
- );
- assert_eq!(
- decision_reason_codes,
- vec![
- "missing_account_id",
- "missing_source",
- "missing_order_trade_order_id",
- "missing_order_request_event_id",
- "missing_order_listing_address",
- "missing_order_buyer_pubkey",
- "missing_order_seller_pubkey",
- "missing_order_revision_id",
- "missing_order_revision_decision_reason",
- ]
- );
- }
-
- #[test]
fn existing_raw_payload_outbox_work_rejects_publish_payload() {
let pending_operation = PendingSyncOperation {
operation_key: "product:greens:upsert".to_owned(),
@@ -1080,44 +858,4 @@ mod tests {
assert!(!pending_operation.is_retry());
assert!(pending_operation.publish_payload().is_err());
}
-
- fn revision_economics() -> RadrootsOrderEconomics {
- serde_json::from_value(json!({
- "quote_id": "quote-revision-1",
- "quote_version": 2,
- "pricing_basis": "listing_event",
- "currency": "USD",
- "items": [{
- "bin_id": "bin-1",
- "bin_count": 2,
- "quantity_amount": "1",
- "quantity_unit": "each",
- "unit_price_amount": "8",
- "unit_price_currency": "USD",
- "line_subtotal": {
- "amount": "16",
- "currency": "USD"
- }
- }],
- "discounts": [],
- "adjustments": [],
- "subtotal": {
- "amount": "16",
- "currency": "USD"
- },
- "discount_total": {
- "amount": "0",
- "currency": "USD"
- },
- "adjustment_total": {
- "amount": "0",
- "currency": "USD"
- },
- "total": {
- "amount": "16",
- "currency": "USD"
- }
- }))
- .expect("revision economics fixture should decode")
- }
}