From 3f7290095f609ebfbe1e99110ff6e95d03232e31 Mon Sep 17 00:00:00 2001 From: Narasimha-sc <166327228+Narasimha-sc@users.noreply.github.com> Date: Sat, 26 Sep 2026 18:44:15 +0000 Subject: [PATCH] core: never fail a sent message on the support member re-read --- plans/member-support-list-events.md | 3 ++- src/Simplex/Chat/Library/Commands.hs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plans/member-support-list-events.md b/plans/member-support-list-events.md index c493697594..32cec1598e 100644 --- a/plans/member-support-list-events.md +++ b/plans/member-support-list-events.md @@ -32,7 +32,7 @@ Load the list once per open group, then keep it current from what arrives. - `updateGroupScopeUnreadStats` returns the updated `GroupChatScopeInfo` together with `GroupInfo`. - `APIChatItemsRead` returns `GroupChat gInfo' chatScopeInfo'`. - `deleteGroupCIs` puts the updated scope member into each deletion's chat info. -- The group send response re-reads the support scope member after `saveSndChatItems` has updated `support_chat_ts`, instead of returning the member from before the send. If that read returns a store error, it falls back to the pre-send member rather than failing a send that has already happened. +- The group send response re-reads the support scope member after `saveSndChatItems` has updated `support_chat_ts`, instead of returning the member from before the send. If that read fails, it falls back to the pre-send member rather than failing a send that has already happened. - Internal items go through `createChatItems`, for example "new member pending review" (unread and attention +1). It now builds its items from the `ChatInfo` returned by `updateChatTsStats`, as `saveRcvChatItem'` already does, instead of the pre-update `toChatInfo cd`. Otherwise a new pending member would appear without a badge. This applies to every chat type: direct and main group chats now carry the updated `chatTs`, as received items already did. - A moderation that arrives before its message creates the item and marks it deleted. The `ChatItemsDeleted` event now carries the group info and scope returned by creating the item, not those from before it. - Opening a member's support chat for the first time sets `support_chat_ts` and now returns the re-read member, so the new chat appears in the list. @@ -60,6 +60,7 @@ A member's first support message arrives as a `NewChatItems` event with that mem ## Known limitations +- A reset of `membersLoaded` that lands between the load's result write and clearing the in-progress flag (one dispatch hop) is skipped. For example, an Android configuration change or an iOS resume at that exact moment. The list then stays unloaded until it is next returned to. - A failed member load (`apiListMembers` error) is not retried while the list stays open; it is retried when the list is reopened. - A full member load that is in flight when a support-chat update arrives overwrites that update with its snapshot. For example, the first list load can race a member's first support message. The member then reappears on their next message, when their chat is opened, or when the group is reopened. - Support stats snapshots from different events and responses are applied in arrival order, so a rare reordering can briefly show an older count until the next update for that member. diff --git a/src/Simplex/Chat/Library/Commands.hs b/src/Simplex/Chat/Library/Commands.hs index 3ca56d6367..dfc72349cf 100644 --- a/src/Simplex/Chat/Library/Commands.hs +++ b/src/Simplex/Chat/Library/Commands.hs @@ -4877,7 +4877,8 @@ processChatCommand cxt nm = \case startProximateTimedItemThread user (ChatRef CTGroup groupId scope, chatItemId' ci) deleteAt chatScopeInfo' <- case chatScopeInfo of Just GCSIMemberSupport {groupMember_ = Just sentScopeMem} -> - Just . GCSIMemberSupport . Just . fromRight sentScopeMem <$> withFastStore' (\db -> runExceptT $ getGroupMemberById db cxt user (groupMemberId' sentScopeMem)) + Just . GCSIMemberSupport . Just + <$> (withFastStore (\db -> getGroupMemberById db cxt user (groupMemberId' sentScopeMem)) `catchAllErrors` \_ -> pure sentScopeMem) _ -> pure chatScopeInfo pure $ CRNewChatItems user (map (AChatItem SCTGroup SMDSnd (GroupChat gInfo chatScopeInfo')) cis) where