app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit cf297f00c9938665709a347d55580755e562ea72
parent 43ea1dd89f4b3ee36547307e825f984ae8526dab
Author: triesap <tyson@radroots.org>
Date:   Sun, 24 May 2026 23:59:36 +0000

sync: recover order coordination on resume

Diffstat:
Mcrates/launchers/desktop/src/runtime.rs | 56+++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 55 insertions(+), 1 deletion(-)

diff --git a/crates/launchers/desktop/src/runtime.rs b/crates/launchers/desktop/src/runtime.rs @@ -3975,9 +3975,10 @@ impl DesktopAppRuntimeState { let report = self.import_shared_local_events()?; let local_changed = report.imported_records > 0 || report.skipped_records > 0; let context_changed = self.refresh_selected_account_context_after_local_events()?; + let coordination_changed = self.retry_pending_personal_order_coordination()?; let sync_changed = self.attempt_sync(SyncTrigger::ForegroundResume)?; - Ok(local_changed || context_changed || sync_changed) + Ok(local_changed || context_changed || coordination_changed || sync_changed) } fn replace_orders_query( @@ -9137,6 +9138,59 @@ mod tests { } #[test] + fn runtime_outbox_recovery_buyer_order_shared_append_failure_is_recoverable_on_foreground_resume() + { + let (runtime, paths, buyer_account_id, order_id, order_farm_id) = + blocked_buyer_order_runtime("buyer_order_append_failure_foreground_resume"); + let expected_order_sync_payload = super::order_sync_payload( + order_id, + order_farm_id, + "place_personal_order", + Some("needs_action"), + ); + unblock_shared_local_events_database(&paths); + assert!( + runtime + .sync_on_foreground_resume() + .expect("foreground resume should repair buyer order coordination") + ); + let summary = runtime.summary(); + assert!( + !summary + .personal_projection + .orders + .has_recoverable_coordination + ); + assert_eq!( + app_buyer_order_local_work_record_ids(&paths), + vec![format!("app:local_work:order_request:{order_id}")] + ); + assert_eq!( + pending_order_sync_payloads(&runtime, buyer_account_id.as_str(), order_id), + vec![expected_order_sync_payload] + ); + { + let state = runtime.lock_state_mut(); + let buyer_context = state.state_store.identity_projection().buyer_context(); + let sqlite_store = state.sqlite_store.as_ref().expect("sqlite store"); + let coordination = sqlite_store + .load_buyer_order_coordination_record(&buyer_context, order_id) + .expect("buyer order coordination should reload") + .expect("buyer order coordination should still exist"); + assert_eq!(coordination.state, BuyerOrderCoordinationState::Synced); + assert_eq!(coordination.attempt_count, 2); + assert_eq!(coordination.last_error_message, None); + } + assert!( + !runtime + .retry_pending_personal_order_coordination() + .expect("foreground-resumed buyer order retry should be idempotent") + ); + + cleanup_bootstrapped_runtime_paths(&paths); + } + + #[test] fn runtime_opens_buyer_order_detail_from_personal_orders() { let runtime = memory_runtime(); let (account_id, farm_id) = provision_ready_farmer_account(&runtime);