From 14c9f8138f30e702b7a8a1de01fe97846d8aa6bc Mon Sep 17 00:00:00 2001 From: Chili Palmer Date: Mon, 17 Aug 2026 20:28:18 +0200 Subject: [PATCH] Keep confirmed Watch snapshots current --- crates/storage/src/mobile_watch.rs | 10 +++++----- crates/storage/tests/mobile_watch.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/crates/storage/src/mobile_watch.rs b/crates/storage/src/mobile_watch.rs index 10c0b05..d43dc24 100644 --- a/crates/storage/src/mobile_watch.rs +++ b/crates/storage/src/mobile_watch.rs @@ -747,11 +747,11 @@ impl WatchSnapshotSender { ); let selected_entries = u32::try_from(entries.len()).map_err(|_| WatchSnapshotError::TooManyEntries)?; - self.status = MobileWatchSnapshotStatus { - state: MobileWatchSnapshotState::Pending, - revision: Some(self.journal.revision), - detail: snapshot_detail("pending delivery", selected_entries, self.journal.revision), - }; + self.status = status_from_journal(&self.journal); + if self.status.state == MobileWatchSnapshotState::Pending { + self.status.detail = + snapshot_detail("pending delivery", selected_entries, self.journal.revision); + } Ok(WatchSnapshotTransfer { revision: self.journal.revision, selected_entries, diff --git a/crates/storage/tests/mobile_watch.rs b/crates/storage/tests/mobile_watch.rs index 500e7b4..71173a0 100644 --- a/crates/storage/tests/mobile_watch.rs +++ b/crates/storage/tests/mobile_watch.rs @@ -261,6 +261,33 @@ fn duplicate_delivery_after_watch_restart_recovers_a_lost_acknowledgement() -> T Ok(()) } +#[test] +fn confirmed_unchanged_snapshot_stays_current_when_republished() -> TestResult { + let directory = tempfile::tempdir()?; + let journal = directory.path().join("watch-snapshot.toml"); + let entries = || vec![entry("otp/alice", "Acme", "alice", b"secret")]; + let mut sender = WatchSnapshotSender::load(journal.clone()); + let first = sender.prepare("paired-watch", entries())?; + let receipt = WatchRuntime::default() + .apply_snapshot(first.snapshot().expose().to_vec())? + .receipt() + .to_vec(); + assert_eq!( + sender.acknowledge(&receipt)?.state(), + MobileWatchSnapshotState::Current + ); + + assert_eq!(sender.prepare("paired-watch", entries())?.revision(), 1); + assert_eq!(sender.status().state(), MobileWatchSnapshotState::Current); + let mut reloaded = WatchSnapshotSender::load(journal); + assert_eq!(reloaded.status().state(), MobileWatchSnapshotState::Current); + reloaded.prepare("paired-watch", entries())?; + assert_eq!(reloaded.status().state(), MobileWatchSnapshotState::Current); + assert_eq!(reloaded.prepare("paired-watch", Vec::new())?.revision(), 2); + assert_eq!(reloaded.status().state(), MobileWatchSnapshotState::Pending); + Ok(()) +} + #[test] fn authoritative_context_switches_sender_generation_and_rejects_delayed_packets() -> TestResult { let directory = tempfile::tempdir()?;