Conversation
Add DM one-pager to document the simplified design for private DMs from group conversations in dm-from-group.mdAdd a planning doc covering user flows, consent logic, XMTP 📍Where to StartStart with the planning overview in dm-from-group.md. Macroscope summarized ab97797. |
0dce6ea to
ab97797
Compare
|
Claude finished @yewreeka's task —— View job PR Review: DM One-Pager DesignI've reviewed the DM design document against the existing codebase architecture, XMTP patterns, and security considerations. Overall, this is a well-thought-out design that integrates cleanly with existing infrastructure. Below are my findings organized by category. ✅ Strengths1. Excellent infrastructure reuse
2. Strong privacy design
3. Clear consent model
🔍 Technical Concerns1. Missing proto definition for Recommendation:
2. Conversation locking mechanism not specified Questions:
Recommendation:
3. DM tag storage unclear Options:
Recommendation:
4. Select members list sync race condition Scenario:
Recommendation:
5. Origin context display might leak metadata 🔒 Example:
Recommendation:
6. Stale Scenario:
Recommendation:
📋 Design CompletenessMissing specification: DM request validation flow
Recommendation: Add a "DM Request Validation" section covering edge cases. Missing: Multi-device coordination Questions:
Recommendation:
Group spinoffs: Invite acceptance UX unclear Question: How does the sender know if recipients actually joined vs. ignored the invite? Recommendation:
🛡️ Security Considerations1. Invite slug reuse attack (Group Spinoffs) Attack:
Mitigation: Spinoff invites should be single-use OR tied to specific inbox IDs. Not clear if XMTP invite system supports this. Recommendation:
2. DM request replay attack Scenario:
Recommendation:
3. Sender can correlate DM to group via timing Attack:
This is probably acceptable (sender initiated the DM, so they know who it's with), but worth noting. 🎨 UX/Clarity Suggestions1. "From select members" is ambiguous Recommendation: Change to "From specific members" or "Custom allow list" 2. Expiration duration needs user testing Consideration:
Recommendation: Consider making expiration configurable per-conversation (e.g., match group's explode timer?) 3. "Send DM" button placement Recommendation:
📝 Documentation Gaps
🚀 Overall AssessmentQuality: High. This design integrates well with existing architecture and shows strong privacy consciousness. Readiness: Needs clarification on ~6 technical details before implementation (see bolded items above). Recommendation: Approve with revisions. Address the proto definition, locking mechanism, and validation flow before cutting code. Next Steps
|
One-pager describing the feature for starting private DMs with people you've met in group conversations. Covers the mutual consent flow, fresh identities for both parties, and ephemeral connection between group and DM identities. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Captures feedback from Notion comments about the green glow potentially not being visible enough when someone isn't actively chatting. Documents constraints (no badges) and ideas to explore (sorted members list, temporary element, info island treatment). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace intent/accept flow with per-convo "Allow DMs" toggle (off/everyone/select members). Remove green circle UI, add silent filtering so senders never know if they're approved. Ephemeral context shows origin conversation. Inline member picker for select members management. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- allowsDMs flag stored as ProfileUpdate field (not appData) - DM request sent via 1:1 back channel (same as join requests) - Select members list synced via self-addressed XMTP messages - Add group spinoffs section (subset of members, sender creates group) - Proto changes showing allows_dms on ProfileUpdate and MemberProfile
ApprovabilityVerdict: Approved This PR adds only a markdown documentation file (design one-pager for DMs) with no code changes. Documentation-only changes have no runtime impact and are safe to merge. You can customize Macroscope's approvability policy. Learn more. |
Dismissing prior approval to re-evaluate f8702b6
Profile architecture has changed since the original plan was written. Profiles now use custom XMTP content types (profile_update and profile_snapshot) from the ConvosProfiles package instead of appData fields. The allows_dms flag uses the existing metadata map on ProfileUpdate/MemberProfile rather than a dedicated proto field. No schema changes needed — the map already supports bool values and is the extension point for new profile features.
- Clarify DM context in conversations list: sender label area shows '[name] from [convo name]' with flexibility for origin convo image - Mark group spinoffs as deferred until after DMs ship - Add open questions for spinoffs (UI entry point, admin permissions, naming, pending state, abuse prevention)
The only difference is the entry point — created from within an existing group rather than from an invite link. Once created, they look and behave like any other conversation.
- UI: 'Spinoff new Convo' button in convo settings, member picker, toast confirmation - Permissions: sender is super admin, joiners are admins - Naming: '[origin name] spinoff' display convention, not stored - Pending state: none, sender sees normal conversation view - Sender DM flag: not required, only recipients - Unified content type: convo_request with optional invite slug (absent = DM, present = group spinoff) - Abuse: gated by allows_dms filtering on receiving end
Dismissing prior approval to re-evaluate 61975d4
Adds docs/plans/dm-single-inbox.md — v1 plan for private DMs rebuilt on the single-inbox identity model (PR #713 / ADR 011). Core shift from #398: - No `convos.org/convo_request` content type. Origin signal rides on `ConversationCustomMetadata.originGroupId` (immutable, sender-set at DM creation, spoof-protected by membership verification on receive). - No back-channel DM between group inboxes. Peer DMs are native XMTP DMs between stable single-inbox inboxIds. - No new custom consent primitive. Uses `XMTPiOS.PrivatePreferences` for per-conversation and per-inboxId consent, which streams across the user's devices for free. Requires extending `XMTPClientProvider` to expose `client.preferences` (Convos today only uses conversation-level consent). - `allows_dms: bool` public bit still rides on `ProfileUpdate` metadata, same mechanism as #398, unchanged. - Select-members allow-list still private via self-addressed XMTP DMs. Policy model: - App-level toggle = default for newly joined groups. - Per-group tri-state: off / everyone / select-members. - New members never auto-populate the select-list. Product decision baked in: no Requests bucket. Every DM resolves to `.allowed` or silent `.denied`; `.unknown` is transient only. Home-list query excludes both `.unknown` and `.denied` to avoid flicker. Six UAQs left to debate before leaving Draft; v2 deferrals called out (group spinoffs, explicit profile-choice sheet).
Adds docs/plans/dm-single-inbox.md — v1 plan for private DMs rebuilt on the single-inbox identity model (PR #713 / ADR 011). Core shift from #398: - No `convos.org/convo_request` content type. Origin signal rides on `ConversationCustomMetadata.originGroupId` (immutable, sender-set at DM creation, spoof-protected by membership verification on receive). - No back-channel DM between group inboxes. Peer DMs are native XMTP DMs between stable single-inbox inboxIds. - No new custom consent primitive. Uses `XMTPiOS.PrivatePreferences` for per-conversation and per-inboxId consent, which streams across the user's devices for free. Requires extending `XMTPClientProvider` to expose `client.preferences` (Convos today only uses conversation-level consent). - `allows_dms: bool` public bit still rides on `ProfileUpdate` metadata, same mechanism as #398, unchanged. - Select-members allow-list still private via self-addressed XMTP DMs. Policy model: - App-level toggle = default for newly joined groups. - Per-group tri-state: off / everyone / select-members. - New members never auto-populate the select-list. Product decision baked in: no Requests bucket. Every DM resolves to `.allowed` or silent `.denied`; `.unknown` is transient only. Home-list query excludes both `.unknown` and `.denied` to avoid flicker. Six UAQs left to debate before leaving Draft; v2 deferrals called out (group spinoffs, explicit profile-choice sheet).
Adds docs/plans/dm-single-inbox.md — v1 plan for private DMs rebuilt on the single-inbox identity model (PR #713 / ADR 011). Core shift from #398: - No `convos.org/convo_request` content type. Origin signal rides on `ConversationCustomMetadata.originGroupId` (immutable, sender-set at DM creation, spoof-protected by membership verification on receive). - No back-channel DM between group inboxes. Peer DMs are native XMTP DMs between stable single-inbox inboxIds. - No new custom consent primitive. Uses `XMTPiOS.PrivatePreferences` for per-conversation and per-inboxId consent, which streams across the user's devices for free. Requires extending `XMTPClientProvider` to expose `client.preferences` (Convos today only uses conversation-level consent). - `allows_dms: bool` public bit still rides on `ProfileUpdate` metadata, same mechanism as #398, unchanged. - Select-members allow-list still private via self-addressed XMTP DMs. Policy model: - App-level toggle = default for newly joined groups. - Per-group tri-state: off / everyone / select-members. - New members never auto-populate the select-list. Product decision baked in: no Requests bucket. Every DM resolves to `.allowed` or silent `.denied`; `.unknown` is transient only. Home-list query excludes both `.unknown` and `.denied` to avoid flicker. Six UAQs left to debate before leaving Draft; v2 deferrals called out (group spinoffs, explicit profile-choice sheet).
Adds docs/plans/dm-single-inbox.md — v1 plan for private DMs rebuilt on the single-inbox identity model (PR #713 / ADR 011). Core shift from #398: - No `convos.org/convo_request` content type. Origin signal rides on `ConversationCustomMetadata.originGroupId` (immutable, sender-set at DM creation, spoof-protected by membership verification on receive). - No back-channel DM between group inboxes. Peer DMs are native XMTP DMs between stable single-inbox inboxIds. - No new custom consent primitive. Uses `XMTPiOS.PrivatePreferences` for per-conversation and per-inboxId consent, which streams across the user's devices for free. Requires extending `XMTPClientProvider` to expose `client.preferences` (Convos today only uses conversation-level consent). - `allows_dms: bool` public bit still rides on `ProfileUpdate` metadata, same mechanism as #398, unchanged. - Select-members allow-list still private via self-addressed XMTP DMs. Policy model: - App-level toggle = default for newly joined groups. - Per-group tri-state: off / everyone / select-members. - New members never auto-populate the select-list. Product decision baked in: no Requests bucket. Every DM resolves to `.allowed` or silent `.denied`; `.unknown` is transient only. Home-list query excludes both `.unknown` and `.denied` to avoid flicker. Six UAQs left to debate before leaving Draft; v2 deferrals called out (group spinoffs, explicit profile-choice sheet).
Adds docs/plans/dm-single-inbox.md — v1 plan for private DMs rebuilt on the single-inbox identity model (PR #713 / ADR 011). Core shift from #398: - No `convos.org/convo_request` content type. Origin signal rides on `ConversationCustomMetadata.originGroupId` (immutable, sender-set at DM creation, spoof-protected by membership verification on receive). - No back-channel DM between group inboxes. Peer DMs are native XMTP DMs between stable single-inbox inboxIds. - No new custom consent primitive. Uses `XMTPiOS.PrivatePreferences` for per-conversation and per-inboxId consent, which streams across the user's devices for free. Requires extending `XMTPClientProvider` to expose `client.preferences` (Convos today only uses conversation-level consent). - `allows_dms: bool` public bit still rides on `ProfileUpdate` metadata, same mechanism as #398, unchanged. - Select-members allow-list still private via self-addressed XMTP DMs. Policy model: - App-level toggle = default for newly joined groups. - Per-group tri-state: off / everyone / select-members. - New members never auto-populate the select-list. Product decision baked in: no Requests bucket. Every DM resolves to `.allowed` or silent `.denied`; `.unknown` is transient only. Home-list query excludes both `.unknown` and `.denied` to avoid flicker. Six UAQs left to debate before leaving Draft; v2 deferrals called out (group spinoffs, explicit profile-choice sheet).
Adds docs/plans/dm-single-inbox.md — v1 plan for private DMs rebuilt on the single-inbox identity model (PR #713 / ADR 011). Core shift from #398: - No `convos.org/convo_request` content type. Origin signal rides on `ConversationCustomMetadata.originGroupId` (immutable, sender-set at DM creation, spoof-protected by membership verification on receive). - No back-channel DM between group inboxes. Peer DMs are native XMTP DMs between stable single-inbox inboxIds. - No new custom consent primitive. Uses `XMTPiOS.PrivatePreferences` for per-conversation and per-inboxId consent, which streams across the user's devices for free. Requires extending `XMTPClientProvider` to expose `client.preferences` (Convos today only uses conversation-level consent). - `allows_dms: bool` public bit still rides on `ProfileUpdate` metadata, same mechanism as #398, unchanged. - Select-members allow-list still private via self-addressed XMTP DMs. Policy model: - App-level toggle = default for newly joined groups. - Per-group tri-state: off / everyone / select-members. - New members never auto-populate the select-list. Product decision baked in: no Requests bucket. Every DM resolves to `.allowed` or silent `.denied`; `.unknown` is transient only. Home-list query excludes both `.unknown` and `.denied` to avoid flicker. Six UAQs left to debate before leaving Draft; v2 deferrals called out (group spinoffs, explicit profile-choice sheet).
Adds docs/plans/dm-single-inbox.md — v1 plan for private DMs rebuilt on the single-inbox identity model (PR #713 / ADR 011). Core shift from #398: - No `convos.org/convo_request` content type. Origin signal rides on `ConversationCustomMetadata.originGroupId` (immutable, sender-set at DM creation, spoof-protected by membership verification on receive). - No back-channel DM between group inboxes. Peer DMs are native XMTP DMs between stable single-inbox inboxIds. - No new custom consent primitive. Uses `XMTPiOS.PrivatePreferences` for per-conversation and per-inboxId consent, which streams across the user's devices for free. Requires extending `XMTPClientProvider` to expose `client.preferences` (Convos today only uses conversation-level consent). - `allows_dms: bool` public bit still rides on `ProfileUpdate` metadata, same mechanism as #398, unchanged. - Select-members allow-list still private via self-addressed XMTP DMs. Policy model: - App-level toggle = default for newly joined groups. - Per-group tri-state: off / everyone / select-members. - New members never auto-populate the select-list. Product decision baked in: no Requests bucket. Every DM resolves to `.allowed` or silent `.denied`; `.unknown` is transient only. Home-list query excludes both `.unknown` and `.denied` to avoid flicker. Six UAQs left to debate before leaving Draft; v2 deferrals called out (group spinoffs, explicit profile-choice sheet).
Replace intent/accept flow with per-convo "Allow DMs" toggle (off/everyone/select members). Removes green circle UI, adds silent filtering so senders never know if they're approved. Ephemeral context shows origin conversation. Inline member picker for select members management.
Updated Notion doc and local one-pager with new flow.
Note
Add planning document for private DMs initiated from group conversations
Adds dm-from-group.md, a design document covering the UX flow, XMTP content types, consent logic, identity creation, and conversation lifecycle for private DMs started from group chats.
Macroscope summarized 61975d4.