Skip to content

Recover pending encrypted chat membership after reconnect - #231

Draft
dmitryvm1 wants to merge 2 commits into
TinyComms:mainfrom
dmitryvm1:fix/encrypted-membership-reconnect
Draft

dmitryvm1 wants to merge 2 commits into
TinyComms:mainfrom
dmitryvm1:fix/encrypted-membership-reconnect

Conversation

@dmitryvm1

@dmitryvm1 dmitryvm1 commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

What changed and why

An encrypted chat can remain stuck with a signed, uncommitted device addition when its existing member misses the live handshake event while offline. Returning online now starts background membership catch-up after the startup conversation list loads and after socket ready/resume, allowing admission to finish without sending a message first.

Concurrent catch-up requests share one worker per device. UI navigation does not start catch-up. Successful sync requests a message backfill so messages can become readable after the device joins. Failed background syncs log at debug because cached groups may refer to deleted or left rooms.

Type

  • feature
  • fix
  • perf
  • refactor
  • chore
  • docs

Platforms

  • windows
  • macos
  • linux
  • android
  • ios

Proof

Scenario: e2e/scenarios/encrypted-membership-reconnect

Lab run: Deferred. Linux, Windows and Android drivers are not implemented despite those lab platforms being able to record today. macOS and iOS drivers are also deferred, with the lab blockers documented in e2e/README.md. The scenario README lists the missing driver and recording for each platform. This PR remains draft: there is nothing for the lab to execute yet, and no e2e-proof or quality-gate completion is claimed.

Validation completed locally:

  • The focused regression exercises real MLS devices through conversation-list publication followed by explicit resume: navigation starts no worker, a returning creator commits a missed Add, the recipient accepts its Welcome, and the recipient's first message decrypts on the creator.
  • The original regression was checked behaviorally against the base; the updated regression additionally checks that navigation alone starts no membership worker. A drop guard removes test devices from the global registry even if an assertion fails.
  • cargo test --locked -p chatd --lib adapters::tiny::: 246 passed, 9 ignored.
  • git diff --check: passed.

Compatibility

No protocol changes or server deployment required. Existing membership APIs are reused, including bounded retries for older servers that batch changes. An existing member still needs to connect for an admission to complete.

Risk and rollback

Startup and socket ready/resume cause additional membership reads and possible commits for known encrypted conversations. Workers are coalesced per device and retain the existing bounded retry schedule. Revert this commit to restore the previous event-driven behavior.

Release note

Finish pending encrypted-chat device additions automatically after startup or reconnection.

Revisit known encrypted conversations after list publication and socket resume so missed handshake events do not leave device additions uncommitted. Coalesce membership catch-up workers and backfill messages after successful sync.

Add a regression covering offline admission and document the required recorded app scenario. Verified that the regression fails with the original list-refresh code; the Tiny adapter suite passes with 246 tests passed and 9 ignored. Full recorded platform proof remains pending.

@itz4blitz itz4blitz left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed as a draft; this is what I'd want fixed before it is marked ready.

The fix itself looks right. Nudging from publish and from the non-fresh resume path covers the missed-handshake case. The per-device flag with the drop guard resets correctly, including when the thread spawn fails. CI is green on all three OSes plus package and pr-gate. The in-process MLS regression is a good test.

Changes I'd like:

  1. The scenario can't run. e2e/scenarios/encrypted-membership-reconnect has only a README and scenario.json. Every other scenario has drive.py plus the per-OS drive.* scripts. The gate wants a scenario that drives the real app and fails on main. The lab has nothing to execute here, so there is no e2e-proof to wait for. Please add at least the drivers for the platforms the lab can record today (linux, windows, android), or say plainly which ones are deferred.

  2. publish also runs on OpenSpace/OpenHome (messages.rs ~353), so moving around the UI now starts a sync of every known encrypted conversation, then two more passes at 35s and 40s. The flag stops overlap, but it can still repeat about every 75s. Consider nudging only from the ready/resume paths, or rate-limiting it.

  3. known_encrypted() also includes conversations from stale cache-*.log files. Those will now log a warn! on each of the 3 passes if the sync fails (deleted or left rooms). Keep it at debug or only warn on unexpected errors.

  4. Small: the test sleeps against a 5s wall clock and uses the global devices() registry. It's fine now, but worth a drop guard so a failed assert doesn't leave entries behind.

@itz4blitz itz4blitz mentioned this pull request Nov 11, 2026
1 of 11 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants