Stop an in-flight poll undoing a cursor reset - #2016
Merged
mpretty-cyro merged 1 commit intoSep 28, 2026
Merged
Conversation
A group's poll cursor is reset so the device re-fetches its history: on
promotion to admin, on removal or deletion, and when a missing group dump is
recreated. A poll of that swarm still in flight wrote its newest hash back
afterwards and undid the reset, so the history was never fetched.
The check meant to catch this could never fire: it tested the
{namespace, lastHash} objects, which are always truthy, rather than their
lastHash. Comparing values would still miss a reset of an already empty
cursor, so each reset now bumps a per-conversation count. A poll that sees the
count change since it started drops its results and writes no cursor, and the
count is checked again before each part of the cursor write.
mpretty-cyro
marked this pull request as ready for review
September 28, 2026 06:00
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
A group's poll cursor (its per-snode last hashes) is reset so this device re-fetches the group's
history. If a poll of that swarm is in flight when the reset happens, it finishes afterwards and
writes its newest hash back as the cursor. That undoes the reset, and the history is never fetched.
The window is one poll round trip. It is real because promotion arrives in our own swarm while the
group is polled on its own schedule.
pollNodeForKeyalready had a check for this, but it could never fire. It tested the{ namespace, lastHash }objects, which are always truthy, instead of theirlastHash:Fixing it to read
lastHashwould still miss two cases:Reset sites
All three go through
SwarmPolling.resetLastHashesForConversation, which is where the guard sits,so a future caller is covered too:
handleGroupUpdatePromoteMessage,handleGroupV2Message.ts:621.createInitialDumpsMissingForGroups,libsession_utils.ts:735.clearFetchedHashes:ConvoHub.deleteGroup,ConversationController.ts:442. It is reached from:useShowLeaveGroup.ts);configMessage.ts:706);handleLibSessionMessage.ts:60);swarmPolling.ts:825);SwarmPollingGroupConfig.ts:58);metaGroups.ts:283.The guard
it writes no cursor and drops its results.
A reset landing during those awaits is therefore not undone either.
Dropping the in-flight poll's messages keeps the discard the old check intended. The next poll
fetches them again from the start, and seen-message dedupe absorbs the overlap.
A reset that happens after the poll's cursor write has landed is outside this fix.
Testing
SwarmPolling_cursorReset_test.tsdrivespollOnceForKeywith both polled snodes' retrieves heldopen, resets the cursor, then lets them complete. The cases:
Each reset case asserts that no cursor was written and that the next poll asks from the beginning.
957 passing, 0 failing,
tsc0 errors, eslint clean at7e87828d4.Mutation results:
lastHashfixed, in place of the count