feat: discover team members in large teams - WPB-24947#4720
Conversation
c40ca22 to
2e59f37
Compare
…-team-notifications-WPB-24947
…-team-notifications-WPB-24947
…-team-notifications-WPB-24947
…-team-notifications-WPB-24947
There was a problem hiding this comment.
Pull request overview
This PR improves large-team member discovery by using /teams/notifications (inclusive cursor semantics) as part of incremental sync, persisting a cursor in Journal, and handling server retention gaps via a dedicated missedEvents error.
Changes:
- Add
TeamMemberDiscoveryAgent(and protocol + journal key) and integrate it intoIncrementalSyncandIncrementalSyncV2. - Update WireNetwork team notifications modeling to include a notification envelope
idand enforce inclusive-cursor semantics (filter cursor item; throw on missing cursor). - Extend/adjust tests and request snapshots for the new cursor behavior and error case.
Reviewed changes
Copilot reviewed 36 out of 37 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/TeamsAPITests.swift | Updates notifications expectations to include envelope IDs and adds tests for inclusive cursor filtering + missed-events handling. |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorMatchesFirstResponseItem_thenFiltersThatItem.request-0-v5.txt | Adds request snapshot for v5. |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorMatchesFirstResponseItem_thenFiltersThatItem.request-0-v6.txt | Adds request snapshot for v6. |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorMatchesFirstResponseItem_thenFiltersThatItem.request-0-v7.txt | Adds request snapshot for v7. |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorMatchesFirstResponseItem_thenFiltersThatItem.request-0-v8.txt | Adds request snapshot for v8. |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorMatchesFirstResponseItem_thenFiltersThatItem.request-0-v9.txt | Adds request snapshot for v9. |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorMatchesFirstResponseItem_thenFiltersThatItem.request-0-v10.txt | Adds request snapshot for v10. |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorMatchesFirstResponseItem_thenFiltersThatItem.request-0-v11.txt | Adds request snapshot for v11. |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorMatchesFirstResponseItem_thenFiltersThatItem.request-0-v12.txt | Adds request snapshot for v12. |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorMatchesFirstResponseItem_thenFiltersThatItem.request-0-v13.txt | Adds request snapshot for v13. |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorMatchesFirstResponseItem_thenFiltersThatItem.request-0-v14.txt | Adds request snapshot for v14. |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorMatchesFirstResponseItem_thenFiltersThatItem.request-0-v15.txt | Adds request snapshot for v15. |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorIsMissingFromResponse_thenThrowsMissedEvents.request-0-v5.txt | Adds request snapshot for missed-events test (v5). |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorIsMissingFromResponse_thenThrowsMissedEvents.request-0-v6.txt | Adds request snapshot for missed-events test (v6). |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorIsMissingFromResponse_thenThrowsMissedEvents.request-0-v7.txt | Adds request snapshot for missed-events test (v7). |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorIsMissingFromResponse_thenThrowsMissedEvents.request-0-v8.txt | Adds request snapshot for missed-events test (v8). |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorIsMissingFromResponse_thenThrowsMissedEvents.request-0-v9.txt | Adds request snapshot for missed-events test (v9). |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorIsMissingFromResponse_thenThrowsMissedEvents.request-0-v10.txt | Adds request snapshot for missed-events test (v10). |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorIsMissingFromResponse_thenThrowsMissedEvents.request-0-v11.txt | Adds request snapshot for missed-events test (v11). |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorIsMissingFromResponse_thenThrowsMissedEvents.request-0-v12.txt | Adds request snapshot for missed-events test (v12). |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorIsMissingFromResponse_thenThrowsMissedEvents.request-0-v13.txt | Adds request snapshot for missed-events test (v13). |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorIsMissingFromResponse_thenThrowsMissedEvents.request-0-v14.txt | Adds request snapshot for missed-events test (v14). |
| WireNetwork/Tests/WireNetworkTests/APIs/Rest/TeamsAPI/Snapshots/TeamsAPITests/testTeamNotifications_givenSinceCursorIsMissingFromResponse_thenThrowsMissedEvents.request-0-v15.txt | Adds request snapshot for missed-events test (v15). |
| WireNetwork/Sources/WireNetwork/Models/Team/TeamNotification.swift | Changes TeamNotification to a struct with id (cursor) + kind. |
| WireNetwork/Sources/WireNetwork/APIs/Rest/TeamsAPI/TeamsAPIV5.swift | Enforces inclusive-cursor semantics: filter cursor item and throw missedEvents if cursor is absent. |
| WireNetwork/Sources/WireNetwork/APIs/Rest/TeamsAPI/TeamsAPIError.swift | Adds TeamsAPIError.missedEvents. |
| WireNetwork/Sources/WireNetwork/APIs/Rest/TeamsAPI/Responses/TeamNotificationV5.swift | Maps decoded payload items into TeamNotification(id:kind:). |
| WireNetwork/Sources/WireNetwork/APIs/Rest/TeamsAPI/EventDecoding/TeamNotificationDecodingProxy.swift | Refactors decoding proxy to decode TeamNotification.Kind (separating envelope id from event kind). |
| WireDomain/Tests/WireDomainTests/Synchronization/IncrementalSyncV2Tests.swift | Injects a TeamMemberDiscoveryAgentProtocol mock into IncrementalSyncV2 tests. |
| WireDomain/Tests/WireDomainTests/Synchronization/IncrementalSyncTests.swift | Injects a TeamMemberDiscoveryAgentProtocol mock into IncrementalSync tests. |
| WireDomain/Sources/WireDomainSupport/Sourcery/generated/AutoMockable.generated.swift | Adds a generated mock for TeamMemberDiscoveryAgentProtocol. |
| WireDomain/Sources/WireDomain/Utilities/Journal/JournalKey.swift | Adds JournalKey.lastTeamNotificationID for persisting the notifications cursor. |
| WireDomain/Sources/WireDomain/Synchronization/TeamMemberDiscoveryAgent.swift | Adds the agent that pages notifications, stores discovered members, and persists/reset cursor. |
| WireDomain/Sources/WireDomain/Synchronization/Protocols/TeamMemberDiscoveryAgentProtocol.swift | Introduces the discovery agent protocol (AutoMockable). |
| WireDomain/Sources/WireDomain/Synchronization/IncrementalSyncV2.swift | Calls team member discovery during sync V2 flow. |
| WireDomain/Sources/WireDomain/Synchronization/IncrementalSync.swift | Calls team member discovery during sync (skipping background-accessible-only mode). |
| WireDomain/Sources/WireDomain/Components/ClientSessionComponent.swift | Wires TeamMemberDiscoveryAgent into both incremental sync implementations. |
Comments suppressed due to low confidence (1)
WireDomain/Tests/WireDomainTests/Synchronization/IncrementalSyncV2Tests.swift:98
MockTeamMemberDiscoveryAgentProtocolwillfatalError("no mock fordiscoverMembers")unlessdiscoverMembers_MockMethodis set. BecauseIncrementalSyncV2.perform()now callsteamMemberDiscoveryAgent.discoverMembers(), any test executingsut.perform()will crash unless the mock is configured. SetteamMemberDiscoveryAgentMock.discoverMembers_MockMethodinsetUp(no-op) and optionally assert it was invoked.
mlsGroupRepairAgent = MockMLSGroupRepairAgentProtocol()
liveBrokenGroupSubject = .init()
cancellables = .init()
earService = MockEARServiceInterface()
teamMemberDiscoveryAgentMock = MockTeamMemberDiscoveryAgentProtocol()
sut = IncrementalSyncV2(
selfClientID: Scaffolding.selfClientID,
pullServerTimeSync: pullServerTimeSync,
pushChannelAPI: pushChannelAPI,
decryptor: decryptor,
updateEventsStore: updateEventsStore,
messageStore: messageLocalStore,
processor: processor,
databaseSaver: databaseSaver,
syncStateSubject: syncStateSubject,
liveBrokenGroupSubject: liveBrokenGroupSubject,
coreCryptoProvider: coreCryptoProvider,
journal: journal,
mlsGroupRepairAgent: mlsGroupRepairAgent,
earService: earService,
teamMemberDiscoveryAgent: teamMemberDiscoveryAgentMock,
createPushChannelState: {
self.pushChannelState
},
syncMarkerGenerator: { Scaffolding.markerID }
)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Test Results 2 files 177 suites 21s ⏱️ Results for commit e8b1b9b. ♻️ This comment has been updated with latest results. Summary: workflow run #26148431862 |
…-team-notifications-WPB-24947 # Conflicts: # WireDomain/Tests/WireDomainTests/Synchronization/IncrementalSyncV2Tests.swift
|
|
|
||
| var discoveredCount = 0 | ||
| for try await notifications in pager { | ||
| let teamMembersInfo = notifications.map { notification -> TeamMemberInfo in |
There was a problem hiding this comment.
nit-pick(subjective): Consider renaming teamMemberInfos to make it clear that this is an collection



Issue
This PR adds a new step for reliably discovering all team members to the incremental sync.
Before we would only get 2000 members (and potentially some more from shared conversations).
Now the iOS client should stay up to date about joined team members.
Testing
Create a large team of more than 2000 members. Ensure the iOS app always knows about all team members (including apps).
Checklist
[WPB-XXX].UI accessibility checklist
If your PR includes UI changes, please utilize this checklist: