feat: recover MLS conversations after key packages refill (WPB-27077) - #4337
feat: recover MLS conversations after key packages refill (WPB-27077)#4337sbakhtiarov wants to merge 1 commit into
Conversation
Test Results0 tests 0 ✅ 0s ⏱️ Results for commit 47008d2. ♻️ This comment has been updated with latest results. |
b740876 to
47008d2
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #4337 +/- ##
=============================================
+ Coverage 61.09% 61.18% +0.08%
- Complexity 4183 4187 +4
=============================================
Files 2191 2194 +3
Lines 71063 71271 +208
Branches 7168 7198 +30
=============================================
+ Hits 43419 43609 +190
- Misses 24802 24810 +8
- Partials 2842 2852 +10
... and 2 files with indirect coverage changes Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
|
now that i am thinking about it checking every single conversation, it is overkill and not needed, all cases that will cause being in a new MLS group (external link, being added or group reset) will give the conv one of the pending states, so checking those only should do the tirck, wdyt? |
https://wearezeta.atlassian.net/browse/WPB-27077
https://wearezeta.atlassian.net/browse/WPB-27077
What's new in this PR?
Summary
This PR adds MLS conversation membership recovery for clients that were not added to MLS groups because they had no available key packages or had not yet registered an MLS identity during MLS migration.
After key packages become available and synchronization completes, the client audits its active MLS-capable conversations against CoreCrypto and rejoins any missing groups using external commits.
The implementation keeps normal key-package refill behavior separate from MLS membership-audit orchestration.
Issues
Scenario 1 (MLS):
User has two MLS clients (Client A, Client B)
Client B is offline with no key packages left.
User is added to a new conversation, Client A is added, Client B cannot be added (no key packages).
Client B goes online and refills key packages.
Expected:
Client B joins new MLS conversation
Actual:
Client B cannot receive messages in a new conversation.
Scenario 2 (Proteus -> MLS migration):
User has two Proteus clients (Client A, Client B)
Client B is offline.
Proteus to MLS migration is started.
Existing proteus conversation is migrated to MLS.
Client A creates MLS client, uploads key packages and is added to MLS conversation, Client B cannot be added.
Client B goes online and refills key packages.
Expected:
Client B joins migrated MLS conversation.
Actual:
Client B cannot receive messages in migrated conversation.
Solutions
Durable membership-audit state
Added a user-scoped MLSMembershipAuditRepository backed by the existing Metadata table.
The repository supports three states:
The marker survives application restarts and is removed only after the complete membership audit succeeds.
The existing "true" metadata value remains compatible with the new state representation. No database schema migration is required.
Key-package depletion detection
RefillKeyPackagesUseCase now treats backend key packages count of zero as a recovery signal.
When zero packages are observed, it:
RefillKeyPackagesResult.Success now includes:
These values allow the audit flow to determine whether key packages are available after the check:
refilled == true means this pass successfully uploaded replacements.
availableCountBeforeRefill > 0 handles restart recovery where a previous pass uploaded packages before the application stopped. Normal refills from a low but nonzero count do not independently schedule an audit.
Post-registration recovery
RegisterMLSClientUseCase now persists REQUIRED_AFTER_SLOW_SYNC before registering the MLS client or uploading its initial key packages.
This prevents the audit from starting while registration or its subsequent slow sync is still in progress.
After the manager observes a real post-registration slow-sync cycle completing and incremental sync returning to Live, it promotes the marker to REQUIRED.
This covers existing Proteus clients that receive their MLS identity only after conversations have already migrated.
Dedicated audit orchestration
Added MLSConversationMembershipAuditManager to separate membership recovery from normal key-package management.
The manager:
Simplified KeyPackageManager
KeyPackageManager remains focused on its original refill flow:
Normal refill behavior remains independent of slow-sync status. Slow-sync gating applies only to the audit.
Membership audit
Added AuditMLSConversationMembershipUseCase.
The audit queries every active MLS-capable conversation where the self user is still a member:
It excludes:
For each conversation, the audit:
The operation is idempotent: subsequent attempts skip groups repaired by an earlier partial audit.
Stale migration metadata recovery
Updated JoinExistingMLSConversationUseCase to handle migrated conversations whose local metadata incorrectly contains:
Previously, epoch zero caused the use case to establish a new local group instead of joining the already-existing migrated group.
When external-commit recovery is enabled, the use case now refreshes authoritative conversation metadata before choosing the recovery strategy if the local conversation is:
After refresh, a migrated conversation with a nonzero backend epoch is joined using an external commit.
This additional refresh is restricted to external-commit recovery so normal pending Welcome processing remains unchanged.