updateChannelParticipant carries the account's qts per the MTProto spec, but
the server always sent Qts: 0, so real clients silently discarded it as a
stale duplicate -- the banned/kicked user's channel never vanished locally
and no correct "removed by admin" message showed, even though the update was
delivered successfully at the transport layer.
Add a durable per-device qts queue (channel_participant_event_queue) sharing
its qts number space with the existing secret-chat queue (one qts sequence
per device, per spec), and use it to stamp a correct, monotonically
increasing qts on the update for every device of the affected user -- for
channel bans/kicks, admin promotion/demotion, and ownership transfer. A
device offline when it happened can now recover the event via
updates.getDifference instead of missing it permanently.
After channels.leaveChannel, a client that polls channels.getFullChannel kept
receiving a projection that still showed it as an active member (left=false)
until the per-(viewer,channel) RPC projection cache and the store-level member
cache lapsed on their own or the async read-model NOTIFY landed. The client
therefore kept an open compose box while every send was already rejected with
CHANNEL_PRIVATE - most visible on public forum supergroups, where getFullChannel
keeps succeeding via the preview path instead of tearing the chat down.
Every other membership-mutating path already busts these caches synchronously;
join/leave/invite/request-approval did not. Add:
- store: invalidateChannelMembershipCaches (row + member + dialog caches),
called post-commit from JoinChannel, LeaveChannel, ImportInvite,
InviteToChannel.
- rpc: invalidateChannelMembershipProjection (channelFullProjectionCache pair),
called from the join/leave/invite/hide-requests handlers for every user whose
membership changed.
Sync telesrv 36eda30 (feat(communities): implement Layer 228 community aggregates).
Skipped telesrv docs changes per public sync rules; normalized the public appearance seed label.