From 7c64fd894e930e533948ce833775dd1653d0e042 Mon Sep 17 00:00:00 2001 From: npub1tquskdu6yc4h8l7xxtceculxw600grekeq0xg2ukqfrwl7vrzg3quz3gmp <58390b379a262b73ffc632f19c73e6769ef40f36c81e642b960246eff9831222@buzz.block.builderlab.xyz> Date: Mon, 27 Jul 2026 21:06:23 -0700 Subject: [PATCH] fix(mobile/ios): drain active push second before advancing Co-authored-by: npub1tquskdu6yc4h8l7xxtceculxw600grekeq0xg2ukqfrwl7vrzg3quz3gmp <58390b379a262b73ffc632f19c73e6769ef40f36c81e642b960246eff9831222@buzz.block.builderlab.xyz> Signed-off-by: npub1tquskdu6yc4h8l7xxtceculxw600grekeq0xg2ukqfrwl7vrzg3quz3gmp <58390b379a262b73ffc632f19c73e6769ef40f36c81e642b960246eff9831222@buzz.block.builderlab.xyz> --- .../Sources/BuzzPushKit/PushCatchUp.swift | 2 +- .../BuzzPushKitTests/PushCatchUpTests.swift | 55 ++++++++++++++++++- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/mobile/ios/BuzzPushKit/Sources/BuzzPushKit/PushCatchUp.swift b/mobile/ios/BuzzPushKit/Sources/BuzzPushKit/PushCatchUp.swift index 71567733c..f3e76fdcb 100644 --- a/mobile/ios/BuzzPushKit/Sources/BuzzPushKit/PushCatchUp.swift +++ b/mobile/ios/BuzzPushKit/Sources/BuzzPushKit/PushCatchUp.swift @@ -93,7 +93,7 @@ public enum PushCatchUp { } let ordered = eventsByID.values.sorted { - $0.createdAt == $1.createdAt ? $0.id < $1.id : $0.createdAt > $1.createdAt + $0.createdAt == $1.createdAt ? $0.id < $1.id : $0.createdAt < $1.createdAt } let selectable = ordered.compactMap { event -> PushCatchUpSelection? in let position = PushEventPosition(createdAt: event.createdAt, id: event.id) diff --git a/mobile/ios/BuzzPushKit/Tests/BuzzPushKitTests/PushCatchUpTests.swift b/mobile/ios/BuzzPushKit/Tests/BuzzPushKitTests/PushCatchUpTests.swift index ef2c825e2..870d4f3ca 100644 --- a/mobile/ios/BuzzPushKit/Tests/BuzzPushKitTests/PushCatchUpTests.swift +++ b/mobile/ios/BuzzPushKit/Tests/BuzzPushKitTests/PushCatchUpTests.swift @@ -35,6 +35,57 @@ final class PushCatchUpTests: XCTestCase { XCTAssertEqual(second.map(\.wasPreviouslyConsumed), [false, true]) } + func testColdStartSelectsOldestAcrossDistinctSeconds() { + let subscription = self.subscription() + let older = event(id: String(format: "%064x", 1)) + let newer = event(id: String(format: "%064x", 2), createdAt: 1_001) + let state = PushConsumptionState() + + let first = PushCatchUp.orderedSelections( + events: [newer, older], + origin: "origin", + subscriptions: [subscription], + consumptionState: state, + verify: { _ in true } + ).first + + XCTAssertEqual(first?.event.id, older.id) + } + + func testActiveSecondSiblingWinsBeforeNewerSecondCandidate() { + let subscription = self.subscription() + let displayed = event(id: String(format: "%064x", 0)) + let activeSibling = event(id: String(format: "%064x", 1)) + let newer = event(id: String(format: "%064x", 2), createdAt: 1_001) + var state = PushConsumptionState() + state.consume( + PushEventPosition(createdAt: displayed.createdAt, id: displayed.id), + for: "origin" + ) + + let first = PushCatchUp.orderedSelections( + events: [newer, activeSibling, displayed], + origin: "origin", + subscriptions: [subscription], + consumptionState: state, + verify: { _ in true } + ).first + XCTAssertEqual(first?.event.id, activeSibling.id) + + state.consume( + PushEventPosition(createdAt: activeSibling.createdAt, id: activeSibling.id), + for: "origin" + ) + let second = PushCatchUp.orderedSelections( + events: [newer, activeSibling, displayed], + origin: "origin", + subscriptions: [subscription], + consumptionState: state, + verify: { _ in true } + ).first + XCTAssertEqual(second?.event.id, newer.id) + } + func testLateLowerIDSiblingIsSelectedThenDuplicateFallbackStaysSeparate() { let subscription = self.subscription() let higherID = String(repeating: "f", count: 64) @@ -109,11 +160,11 @@ final class PushCatchUpTests: XCTestCase { ) } - private func event(id: String) -> VerifiedNostrEvent { + private func event(id: String, createdAt: Int = 1_000) -> VerifiedNostrEvent { VerifiedNostrEvent( id: id, pubkey: other, - createdAt: 1_000, + createdAt: createdAt, kind: 9, tags: [["p", mine]], content: "message",