Skip to content

feat(chat-list): distinguish whether the local account left or was removed from each group#766

Merged
jgmontoya merged 1 commit into
masterfrom
feat/chat-list-self-membership
Jul 1, 2026
Merged

feat(chat-list): distinguish whether the local account left or was removed from each group#766
jgmontoya merged 1 commit into
masterfrom
feat/chat-list-self-membership

Conversation

@jgmontoya

@jgmontoya jgmontoya commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Open in Stage

Summary by CodeRabbit

  • New Features

    • Chat lists now display your per-group membership state (Member, Left, Removed), including after sync/backfill.
    • The membership state is now exposed over the FFI layer so external clients can read the same Left vs Removed distinction.
  • Bug Fixes

    • Fixed unread-count suppression to correctly ignore groups marked as Left or Removed, while preserving correct counts for Member.
    • Improved projection/sync handling so local membership state stays consistent and repairs correctly if data drifts.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 709ae171-b018-4c31-befe-c642b5cb055c

📥 Commits

Reviewing files that changed from the base of the PR and between 77432b9 and d44677c.

📒 Files selected for processing (18)
  • crates/marmot-app/src/client/mod.rs
  • crates/marmot-app/src/client/sync.rs
  • crates/marmot-app/src/conversions.rs
  • crates/marmot-app/src/groups.rs
  • crates/marmot-app/src/lib.rs
  • crates/marmot-app/src/runtime/tests.rs
  • crates/marmot-app/tests/relay_runtime.rs
  • crates/marmot-uniffi/src/conversions/chat_list.rs
  • crates/marmot-uniffi/src/conversions/common.rs
  • crates/marmot-uniffi/src/conversions/group.rs
  • crates/marmot-uniffi/src/conversions/mod.rs
  • crates/storage-sqlite/src/account_projection.rs
  • crates/storage-sqlite/src/account_projection/tests.rs
  • crates/storage-sqlite/src/chat_list.rs
  • crates/storage-sqlite/src/chat_list/tests.rs
  • crates/storage-sqlite/src/lib.rs
  • crates/storage-sqlite/src/migrations.rs
  • crates/storage-sqlite/src/migrations/0022_chat_list_self_membership.rs
✅ Files skipped from review due to trivial changes (2)
  • crates/storage-sqlite/src/lib.rs
  • crates/marmot-app/src/runtime/tests.rs
🚧 Files skipped from review as they are similar to previous changes (16)
  • crates/storage-sqlite/src/account_projection/tests.rs
  • crates/marmot-app/src/conversions.rs
  • crates/marmot-app/tests/relay_runtime.rs
  • crates/storage-sqlite/src/migrations/0022_chat_list_self_membership.rs
  • crates/marmot-app/src/groups.rs
  • crates/marmot-uniffi/src/conversions/group.rs
  • crates/storage-sqlite/src/migrations.rs
  • crates/marmot-app/src/lib.rs
  • crates/marmot-uniffi/src/conversions/chat_list.rs
  • crates/marmot-app/src/client/mod.rs
  • crates/marmot-uniffi/src/conversions/mod.rs
  • crates/marmot-uniffi/src/conversions/common.rs
  • crates/marmot-app/src/client/sync.rs
  • crates/storage-sqlite/src/chat_list/tests.rs
  • crates/storage-sqlite/src/chat_list.rs
  • crates/storage-sqlite/src/account_projection.rs

Walkthrough

This PR replaces boolean self-membership handling with a SelfMembership enum across storage, app, sync, chat-list projection, migration, and FFI layers. It adds a self_membership column to chat_list_rows, distinguishes voluntary leaves from involuntary removals, and updates related tests and conversions.

Changes

SelfMembership Enum Migration

Layer / File(s) Summary
Storage schema and chat-list projection
crates/storage-sqlite/src/account_projection.rs, crates/storage-sqlite/src/account_projection/tests.rs, crates/storage-sqlite/src/lib.rs, crates/storage-sqlite/src/migrations.rs, crates/storage-sqlite/src/migrations/0022_chat_list_self_membership.rs, crates/storage-sqlite/src/chat_list.rs, crates/storage-sqlite/src/chat_list/tests.rs
Adds SelfMembership, stores it on account and chat-list rows, updates projection queries and unread filtering, adds migration 0022, and extends storage tests.
App group record and conversions
crates/marmot-app/src/groups.rs, crates/marmot-app/src/conversions.rs, crates/marmot-app/src/lib.rs, crates/marmot-app/src/runtime/tests.rs
Adds self_membership to AppGroupRecord, threads it through storage conversions, changes the setter signature to take SelfMembership, and initializes test fixtures with the new field.
Client leave, backfill, and sync membership handling
crates/marmot-app/src/client/mod.rs, crates/marmot-app/src/client/sync.rs, crates/marmot-app/tests/relay_runtime.rs
Records voluntary leaves as Left and backfilled departures as Removed, classifies sync departures with SelfMembership, and extends leave-flow assertions.
UniFFI self-membership conversion
crates/marmot-uniffi/src/conversions/common.rs, crates/marmot-uniffi/src/conversions/chat_list.rs, crates/marmot-uniffi/src/conversions/group.rs, crates/marmot-uniffi/src/conversions/mod.rs
Adds SelfMembershipFfi, exposes the field on FFI group and chat-list records, and adds variant-mapping tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: tracking whether the local account left or was removed from each group.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/chat-list-self-membership

Comment @coderabbitai help to get the list of available commands.

@stage-review

stage-review Bot commented Jun 30, 2026

Copy link
Copy Markdown

Ready to review this PR? Stage has broken it down into 6 individual chapters for you:

Title
1 Define SelfMembership enum and storage schema
2 Implement membership persistence in SQLite
3 Denormalize membership into chat list projection
4 Expose membership state to the App layer
5 Update sync and leave logic to track membership type
6 Expose membership state via UniFFI
Open in Stage

Chapters generated by Stage for commit d44677c on Jun 30, 2026 9:52pm UTC.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
crates/marmot-uniffi/src/conversions/common.rs (1)

8-28: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider deriving PartialEq/Eq on SelfMembershipFfi.

The new self_membership_ffi_preserves_each_variant test in mod.rs uses matches! instead of assert_eq!, likely because SelfMembershipFfi doesn't derive PartialEq. Adding it would simplify call-site comparisons (tests and any FFI-consuming Rust code) without any downside.

♻️ Proposed derive addition
-#[derive(Clone, Copy, Debug, uniffi::Enum)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, uniffi::Enum)]
 pub enum SelfMembershipFfi {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/marmot-uniffi/src/conversions/common.rs` around lines 8 - 28, Add
PartialEq and Eq to SelfMembershipFfi so Rust callers can compare variants
directly instead of relying on matches! in tests like
self_membership_ffi_preserves_each_variant. Update the enum declaration in
common.rs where SelfMembershipFfi is defined, keeping the existing Clone, Copy,
Debug, and uniffi::Enum derives unchanged. This will make equality assertions
and other call-site comparisons simpler across the FFI boundary.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/storage-sqlite/src/account_projection.rs`:
- Around line 469-479: `set_group_self_membership` currently updates only
`account_groups`, leaving the denormalized `chat_list_rows.self_membership`
stale. Update the same storage transaction to also write the new membership into
`chat_list_rows` for the matching `group_id_hex`, using the existing
`self.lock()`/`execute` flow so chat list reads stay consistent after
leave/remove changes.

In `@crates/storage-sqlite/src/chat_list.rs`:
- Line 364: The completeness check in chat list synchronization is comparing the
raw self_membership storage values instead of the normalized membership used
elsewhere, so future unknown values can keep rows looking stale. Update the
comparison in the chat list query logic around the membership check to use the
same normalization path as the rest of the code (the membership mapping used by
chat_list_rows/account_groups processing), so both sides compare normalized
Member values before deciding whether a rebuild is needed.

---

Nitpick comments:
In `@crates/marmot-uniffi/src/conversions/common.rs`:
- Around line 8-28: Add PartialEq and Eq to SelfMembershipFfi so Rust callers
can compare variants directly instead of relying on matches! in tests like
self_membership_ffi_preserves_each_variant. Update the enum declaration in
common.rs where SelfMembershipFfi is defined, keeping the existing Clone, Copy,
Debug, and uniffi::Enum derives unchanged. This will make equality assertions
and other call-site comparisons simpler across the FFI boundary.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8d1d2233-20b3-4aa8-872b-d47a24e22bda

📥 Commits

Reviewing files that changed from the base of the PR and between c38348d and 77432b9.

📒 Files selected for processing (18)
  • crates/marmot-app/src/client/mod.rs
  • crates/marmot-app/src/client/sync.rs
  • crates/marmot-app/src/conversions.rs
  • crates/marmot-app/src/groups.rs
  • crates/marmot-app/src/lib.rs
  • crates/marmot-app/src/runtime/tests.rs
  • crates/marmot-app/tests/relay_runtime.rs
  • crates/marmot-uniffi/src/conversions/chat_list.rs
  • crates/marmot-uniffi/src/conversions/common.rs
  • crates/marmot-uniffi/src/conversions/group.rs
  • crates/marmot-uniffi/src/conversions/mod.rs
  • crates/storage-sqlite/src/account_projection.rs
  • crates/storage-sqlite/src/account_projection/tests.rs
  • crates/storage-sqlite/src/chat_list.rs
  • crates/storage-sqlite/src/chat_list/tests.rs
  • crates/storage-sqlite/src/lib.rs
  • crates/storage-sqlite/src/migrations.rs
  • crates/storage-sqlite/src/migrations/0022_chat_list_self_membership.rs

Comment thread crates/storage-sqlite/src/account_projection.rs
Comment thread crates/storage-sqlite/src/chat_list.rs Outdated
@jgmontoya
jgmontoya force-pushed the feat/chat-list-self-membership branch from 77432b9 to d44677c Compare June 30, 2026 21:52
@jgmontoya
jgmontoya merged commit c9d63de into master Jul 1, 2026
20 checks passed
@jgmontoya
jgmontoya deleted the feat/chat-list-self-membership branch July 1, 2026 14:53
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.

1 participant