The userlist starts duplicating users, likely because we're just appending and not deduping users as status changes change from online to offline over time.
Expected behavior: Each user is unique and should only have one listing.

The userlist starts duplicating users, likely because we're just appending and not deduping users as status changes change from online to offline over time.
Expected behavior: Each user is unique and should only have one listing.
The cause was index alignment rather than appending. Discord's member list interleaves group headers - Online, Offline, and every role with its own section - among the people, and its incremental INSERT/UPDATE/DELETE ops address that list. We dropped the headers on SYNC, so every index we applied was short by the number of headers above it: the DELETE half of a status change removed whoever happened to sit at that position instead, and the INSERT half added a second copy of the person who had moved, whose old row was still there. One duplicate per status change, which is why it only shows after a channel has been left open a while.
Headers now take their slot in the window and are filtered out when the roster is emitted. An op that still does not fit means the window has drifted from Discord's, so it is discarded and a fresh SYNC requested rather than applied half-aligned. The roster also de-dupes by user id on the way out, so the symptom cannot return by another route.
nobilis 276bbb0, moho 80d53ed. Five tests cover it, including one that replays the exact DELETE/INSERT pair a status change sends across a section boundary.
Finished.
The cause was index alignment rather than appending. Discord's member list interleaves group headers - Online, Offline, and every role with its own section - among the people, and its incremental INSERT/UPDATE/DELETE ops address *that* list. We dropped the headers on SYNC, so every index we applied was short by the number of headers above it: the DELETE half of a status change removed whoever happened to sit at that position instead, and the INSERT half added a second copy of the person who had moved, whose old row was still there. One duplicate per status change, which is why it only shows after a channel has been left open a while.
Headers now take their slot in the window and are filtered out when the roster is emitted. An op that still does not fit means the window has drifted from Discord's, so it is discarded and a fresh SYNC requested rather than applied half-aligned. The roster also de-dupes by user id on the way out, so the symptom cannot return by another route.
nobilis [276bbb0](https://git.salastil.com/Salastil/nobilis/commit/276bbb0), moho [80d53ed](https://git.salastil.com/Salastil/moho/commit/80d53ed). Five tests cover it, including one that replays the exact DELETE/INSERT pair a status change sends across a section boundary.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The userlist starts duplicating users, likely because we're just appending and not deduping users as status changes change from online to offline over time.
Expected behavior: Each user is unique and should only have one listing.
Finished.
The cause was index alignment rather than appending. Discord's member list interleaves group headers - Online, Offline, and every role with its own section - among the people, and its incremental INSERT/UPDATE/DELETE ops address that list. We dropped the headers on SYNC, so every index we applied was short by the number of headers above it: the DELETE half of a status change removed whoever happened to sit at that position instead, and the INSERT half added a second copy of the person who had moved, whose old row was still there. One duplicate per status change, which is why it only shows after a channel has been left open a while.
Headers now take their slot in the window and are filtered out when the roster is emitted. An op that still does not fit means the window has drifted from Discord's, so it is discarded and a fresh SYNC requested rather than applied half-aligned. The roster also de-dupes by user id on the way out, so the symptom cannot return by another route.
nobilis 276bbb0, moho 80d53ed. Five tests cover it, including one that replays the exact DELETE/INSERT pair a status change sends across a section boundary.