As discussed in #synapse-dev:matrix.org,
Description
After purge_history runs over the point in a room's timeline where a user left / was kicked / was banned, Simplified Sliding Sync (MSC4186 / org.matrix.simplified_msc3575) stops returning that user's own m.room.member event in the room's required_state even though the membership is still durably recorded in current-state tables. The room is still returned in the response, just with no $ME membership event.
Steps to reproduce
I created a Complement test which reproduces the problem: https://github.com/codyfinn/synapse/blob/c117852b8aa27ec01996c8cc28690cc268a22203/complement/tests/sliding_sync_purged_membership_regression_test.go
Manual steps:
- Register
@alice (room admin) and @bob.
- As
@alice, create a public room: POST /_matrix/client/v3/createRoom {"preset": "public_chat"} → !room:hs1.
- As
@bob, join: POST /_matrix/client/v3/join/!room:hs1. Wait for the join to sync.
- As
@alice, send a few m.room.message events so there is joined-era history before the departure (gives the purge something to outlier behind).
- Depart
@bob — any of the three reproduces:
- kick:
POST /_matrix/client/v3/rooms/!room:hs1/kick {"user_id": "@bob:hs1"}
- ban:
POST /_matrix/client/v3/rooms/!room:hs1/ban {"user_id": "@bob:hs1"}
- leave:
POST /_matrix/client/v3/rooms/!room:hs1/leave (as @bob)
- As
@alice, send one more m.room.message after the departure and record its event_id ($boundary). This is the purge boundary — everything topologically before it (including bob's m.room.member event) will be purged.
- As admin, purge history up to the boundary:
POST /_synapse/admin/v1/purge_history/!room:hs1 with {"purge_up_to_event_id": "$boundary", "delete_local_events": true}
- poll
GET /_synapse/admin/v1/purge_history_status/{purge_id} until "status": "complete"
- As
@bob, issue a Simplified Sliding Sync request asking for his own membership:
Homeserver
A personal homeserver
Synapse Version
1.155.0
Installation Method
Docker (matrixdotorg/synapse)
Database
PostgreSQL single server. Never ran SQLite. Never restored from a backup
Workers
Multiple workers
Platform
Reproduced on Complement Synapse image — Debian trixie, Python 3.13, running under Docker on macOS
Running in a Kubernetes deployment
Configuration
No response
Relevant log output
I can't share server logs, but it is reproducible with a Complement test found here: https://github.com/codyfinn/synapse/blob/c117852b8aa27ec01996c8cc28690cc268a22203/complement/tests/sliding_sync_purged_membership_regression_test.go
Anything else that would be useful to know?
No response
As discussed in
#synapse-dev:matrix.org,Description
After
purge_historyruns over the point in a room's timeline where a user left / was kicked / was banned, Simplified Sliding Sync (MSC4186 /org.matrix.simplified_msc3575) stops returning that user's ownm.room.memberevent in the room'srequired_stateeven though the membership is still durably recorded in current-state tables. The room is still returned in the response, just with no$MEmembership event.Steps to reproduce
I created a Complement test which reproduces the problem: https://github.com/codyfinn/synapse/blob/c117852b8aa27ec01996c8cc28690cc268a22203/complement/tests/sliding_sync_purged_membership_regression_test.go
Manual steps:
@alice(room admin) and@bob.@alice, create a public room:POST /_matrix/client/v3/createRoom {"preset": "public_chat"}→!room:hs1.@bob, join:POST /_matrix/client/v3/join/!room:hs1. Wait for the join to sync.@alice, send a fewm.room.messageevents so there is joined-era history before the departure (gives the purge something to outlier behind).@bob— any of the three reproduces:POST /_matrix/client/v3/rooms/!room:hs1/kick {"user_id": "@bob:hs1"}POST /_matrix/client/v3/rooms/!room:hs1/ban {"user_id": "@bob:hs1"}POST /_matrix/client/v3/rooms/!room:hs1/leave(as@bob)@alice, send one morem.room.messageafter the departure and record itsevent_id($boundary). This is the purge boundary — everything topologically before it (including bob'sm.room.memberevent) will be purged.POST /_synapse/admin/v1/purge_history/!room:hs1with{"purge_up_to_event_id": "$boundary", "delete_local_events": true}GET /_synapse/admin/v1/purge_history_status/{purge_id}until"status": "complete"@bob, issue a Simplified Sliding Sync request asking for his own membership:Homeserver
A personal homeserver
Synapse Version
1.155.0
Installation Method
Docker (matrixdotorg/synapse)
Database
PostgreSQL single server. Never ran SQLite. Never restored from a backup
Workers
Multiple workers
Platform
Reproduced on Complement Synapse image — Debian trixie, Python 3.13, running under Docker on macOS
Running in a Kubernetes deployment
Configuration
No response
Relevant log output
I can't share server logs, but it is reproducible with a Complement test found here: https://github.com/codyfinn/synapse/blob/c117852b8aa27ec01996c8cc28690cc268a22203/complement/tests/sliding_sync_purged_membership_regression_test.go
Anything else that would be useful to know?
No response