The test only checked that a non-member does not get the announcer's
device change, so it would also pass if the change produced no device
list update at all. A user sharing a regular room with the announcer now
gets that same change in the same test.
A sender removed before anything was announced gets the synthetic join,
then the room is left out of their lists until the first announcement.
It was dropped from the rooms checked for updates outside the lists, so
the connection kept it as sent up to its last token: when the
announcement listed it again, only that announcement went down and any
change made in between, such as a new room name, was lost.
The rooms left out are now kept among the rooms checked for updates,
without being listed. A change while they are left out marks them as
only partly sent, and they come back with everything since. This reuses
the existing tracking of rooms outside the list ranges, instead of
resending the room from scratch when it is listed again, which would
need its own bookkeeping.
Nobody is banned from an announcement room in practice: senders are
removed from the config, which kicks them. Only a leave now gives way to
the synthetic join again.
An announcement room the user is not a member of is now listed when it
holds an announcement, or when the user left, was kicked or was banned
within the request's window, and otherwise left out. A user removed
before anything was announced no longer gets the room on a new
connection, and a user leaving on their own before any announcement gets
the synthetic join in the same response instead of their leave.
The room is then never sent with the user's real leave, so resending it
from scratch afterwards is no longer needed.
A user banned from an announcement room kept their real ban, so they
stopped getting announcements. As in legacy sync, a ban now gives way to
the synthetic join like a kick does, and is left out of `required_state`
and the timeline.
A member removed from the configured senders before anything was
announced got their kick, and the room only came back as joined with the
first announcement. Their room now gets the synthetic join straight away,
at the position of the kick until there is an announcement.
Only kicks count: both paths always keep them in the user's memberships,
while the new tables leave out the user's own past leaves.
Also test that a removed member added back gets their real join and the
power levels that let them post again.
A member who left or was removed from an announcement room first got
their leave, then the synthetic join on the next sync. They now get the
synthetic join instead of their leave in the same sync, as in legacy
sync, once the room has had an announcement. Before that, the leave
still goes down and the room is sent again from scratch later.
A timeline reaching back to the user's leave or kick ended with that
membership after the synthetic join in `required_state`, so clients saw
the user as having left. The user's own membership events are now dropped
from the timeline of a server announcement room, as they already are from
its `required_state`.
A user who left or was kicked while their connection was open never got
the synthetic join afterwards, since only state changes were sent. When a
response sends the user's new leave in an announcement room, the room is
now recorded as never sent, so its next delivery holds the full
`required_state` with the synthetic join.
A user removed from the configured senders is kicked, and both paths
kept the kick as their membership, so they never got the synthetic join.
Only a leave that isn't newly left now gives way to the synthetic join.
On an existing connection, the synthetic join is still not sent after
the kick, as `test_removed_member_existing_connection` shows.
The fallback path kept the self-leave in the membership map, so the
announcement room was skipped and then filtered out of the lists. Only
memberships the lists keep now prevent the synthetic join.
Also test that the room stays in the list, is ordered like the user's
other rooms, and can be subscribed to directly.
This includes the following:
- Implements ['Implicit Forward
Pagination'](https://github.com/matrix-org/matrix-spec/issues/2378).
Remove the extension's `since` and `next_batch` fields. The position is
now tracked via the global `pos`, with per-room connection state
recording how far each room has been sent so that `limit` paginates
without holding `pos` back and lost responses are re-delivered.
- Discussed in
https://github.com/matrix-org/matrix-spec-proposals/pull/4480#discussion_r4165887827
- Honour the `lists` and `rooms` fields.
- Send all unexpired sticky events when a room enters scope for the
first time or is newly joined, and catch up on events sent while a room
was out of scope when it re-enters.
- Enabling the extension partway through a connection returns all
unexpired sticky events for in-scope rooms, and re-enabling it after
disabling it returns the unexpired sticky events sent in the meantime.
I tried to split this up into standalone commits though the bulk of the
change is in the third commit.
---------
Co-authored-by: Olivier 'reivilibre <git.oo@emunest.net>