Claiming an invite grants relay membership but no channel membership — new members land in an empty community
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
### Summary
Claiming an invite makes you a **relay** member but adds you to **no channel**. A brand-new member can *read* channel messages, yet appears in no channel's member list, so the client lands them in a community that looks empty. On mobile it reliably reads as "the join didn't work."
There is also a **default-value mismatch between desktop and mobile** for the same missing field, which is a plausible reason this looks worse on Android than on desktop.
### Reproduction
Against a live hosted community (`creatormagic.communities.buzz.xyz`), with a freshly generated key:
1. `GET /api/join-policy` → policy version
2. `POST /api/invites/accept-policy` → receipt
3. `POST /api/invites/claim` (NIP-98, receipt included) → **HTTP 200 `{"status":"joined"}`**
4. Open a relay socket, NIP-42 AUTH with that same key, then subscribe
Observed:
| Query | Result |
|---|---|
| `kinds:[39000]` (channel metadata) | **9 channels** visible (`general`, `welcome-everyone`, `roast-me`, `buzz-docs`, …) |
| `kinds:[39002] #d:[]` (member list) | **254 members listed — the new joiner is NOT among them** |
| `kinds:[9] #h:[]` (messages) | **10 messages received** |
So the new member can enumerate channels and read their messages, but is a member of none of them.
### Why this is confusing for users
A user taps an invite link, the claim returns success, and the app opens on an empty community with no channel to land in. From the user's point of view a successful join is indistinguishable from a failed one. Every new member of a community hits this, not an edge case.
### The desktop/mobile default mismatch
When a channel payload omits the membership flag, the two clients disagree:
- `desktop/src/shared/api/tauriChannels.ts:76` → `isMember: channel.is_member ?? true`
- `mobile/lib/features/channels/channel.dart:40` → `this.isMember = false`
Desktop assumes membership when the field is absent; mobile assumes non-membership. Given identical relay data the two platforms reach opposite conclusions, which matches user reports of "works on desktop, looks broken on Android."
I have not traced how far that flag propagates into list filtering, so treat the mismatch as a strong lead rather than a confirmed root cause. The membership finding above is directly measured.
### Environment
- Android emulator (API 33), source build of `mobile/` at `dcd74a2`
- Relay behaviour measured directly over `wss://` with NIP-42 auth, independent of any client
### Possible directions
Sharing observations rather than prescribing a fix:
1. Admit new relay members to a default/welcome channel on claim, so there is somewhere to land.
2. Or have clients list readable channels even when the viewer is not a member, with an explicit join affordance per channel.
3. Independently, align the `is_member` default across desktop and mobile so one platform is not silently hiding channels the other shows.
Happy to provide the exact probe scripts or test another community if useful.
Contributor guide
Research direction
Start by reproducing the documented join-policy, invite-claim, relay AUTH, and channel queries, then trace how the claim result reaches the clients. Compare desktop/src/shared/api/tauriChannels.ts:76 with mobile/lib/features/channels/channel.dart:40 and follow the isMember value into channel filtering. Done means the membership behavior and intended client handling are established with regression coverage for the observed case.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- tauri, typescript
- Domain
- api, backend, mobile
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100