Skip to content

MSC4390: Room Blocking API#4390

Open
nexy7574 wants to merge 6 commits intomatrix-org:mainfrom
nexy7574:nexy7574/room-blocking
Open

MSC4390: Room Blocking API#4390
nexy7574 wants to merge 6 commits intomatrix-org:mainfrom
nexy7574:nexy7574/room-blocking

Conversation

@nexy7574
Copy link
Contributor

@nexy7574 nexy7574 commented Dec 17, 2025

@nexy7574 nexy7574 changed the title MSCXXXX: Room Blocking API MSC4390: Room Blocking API Dec 17, 2025
@turt2live turt2live added proposal A matrix spec change proposal client-server Client-Server API kind:feature MSC for not-core and not-maintenance stuff needs-implementation This MSC does not have a qualifying implementation for the SCT to review. The MSC cannot enter FCP. safety labels Dec 17, 2025
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation requirements:

  • Server
  • Client using endpoint(s)

Comment on lines +80 to +134
#### Response

**200 OK**: The server successfully processed the request and could retrieve relevant details:

```jsonc
{
// The room's full room ID. MUST always be present.
"room_id": "!example",
// Whether this room is blocked. MUST always be present
"blocked": false,
// The name of this room, if available.
"name": "Example Room",
// The entire contents of the m.topic state event.
// The entire event body is provided as topics may have more than one textual representation form
"topic": {"topic": "hello orld"},
// The MXC URI for this room's avatar, if set
"avatar": "mxc://foo.bar",
// The canonical alias of this room, if set.
"canonical_alias": "#foo:example.org",
// Any alternative aliases in the canonical alias event.
// This SHOULD also include aliases set by local users that aren't in the canonical alias event.
"alt_aliases": ["#foo:example.com", "#foo:example.net"],
// The total number of members that are joined to this room.
"joined_members": 0,
// The total number of members that have pending invites to this room.
"invited_members": 0,
// The number of local members that are joined to this room.
"local_members": 0,
// The number of local members that have pending invites to this room.
"invited_local_members": 0,
// The room version, if known.
"room_version": "12",
// The room creators. The `sender` of `m.room.create` MUST be the first element in the array,
// additional creators (in room versions that support such) MUST come after. See below for
// justification.
"creators": ["@example:example.org"],
// Whether this room is encrypted.
"encrypted": false,
// Whether this room allowed federation when it was created.
"federated": true,
// The `m.room.join_rules` event body for this room, if known.
"join_rules": {"join_rule": "restricted", "allow": []},
// The history visibility (world_readable/shared/invited/joined) for this room.
"history_visibility": "shared",
// The m.room.power_levels event body for this room
"power_levels": {"users": {}},
// The m.room.server_acl event body for this room
"acl": {"allow": ["*"]}
}
```

> [!IMPORTANT]
> The **only** REQUIRED keys in this body are `room_id` and `blocked`. The implementation MAY omit
> unknown values, values that resolve to empty arrays, values that resolve to false, values that
> resolve to zero, however event bodies that themselves are found but empty SHOULD NOT be omitted.
Copy link
Contributor

@Gnuxie Gnuxie Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per the comments on the previous MSC #4375 (comment), #4375 (comment) it would be good to have some forward thinking here to keep the response from this endpoint consistent with the details provided in a future specified room list api. That would also compartmentalise details that are specific to server admin, summaries of the room state (unstable and mutable properties), and the create event. Specifically so that they can be filtered more easily and generally (during pagination) rather than guessing what information clients might need from the room state.

I can contribute this format if you want me to.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I was adjusting the response a bit, I was wondering whether it might just be a better idea to instead suggest that servers should just allow administrators to fetch /_matrix/client/v3/rooms/<roomID>/state[/...] directly, and instead leave this endpoint to just return the block status. As noted in the latest commit, we've already got the wheels, no need to make them square. What do you think about that instead?

Copy link
Contributor

@Gnuxie Gnuxie Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll want the generic endpoint for providing information like whether the room is also marked delete and whether the server was able to action the deletion yet (#4390 (comment)). Other than that only the create event and block status is strictly necessary. However, /state isn't really an alternative to an overview unless there's an MSC that clarifies that a system admin user can always call it even when not joined to the room.

Copy link
Contributor

@Gnuxie Gnuxie Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd also caution against throwing stuff out for the sake of simplicity, there are enough tools that use synapse admin endpoints to have the implementation experience necessary to be able to design and specify the room list and details apis. Again I can contribute this.

}
```

## Potential issues
Copy link
Contributor

@Gnuxie Gnuxie Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a discussion yesterday regarding the design of the delete endpoint https://matrix.to/#/!nD4Jy1hp0We0VmIM9ubjqWLBX_uV8YlTBBPa3a_v2uk/%24nKAMh6AaheBqbxriI7my_ghTOighlvXSwL2g5tcHI6U?via=matrix.org&via=element.io&via=beeper.com.

There were a few use cases identified for the endpoint:

  • To temporarily delete a room and rejoin the room afterwards
  • To delete various rooms as part of a maintenance routine before scheduling a vacuum or backup (and potentially allow rejoining the rooms later)
  • To delete rooms containing abuse with the intention to prevent any future room joins (until the restriction is manually lifted). Which may happen from an admin interface or from a policy application engine ie *nirs.

For the use case of abuse handling, the following invariant needs to be true for safety and consistency:

  • Deletion needs to be idempotent, and so the endpoint would instead mark a room with the state delete i.e. { "delete": true }. Once a room has been marked delete, the server is responsible for scheduling the deletion and seeing it through. And the delete state has to be manually recalled. A task like abstraction as provided by synapse room deletion does not work here because if the deletion task "fails", the client is responsible for retrying, which is highly error prone and inappropriate for this context.

For maintenance:

  • A deletion is a one-time occurrence, users are permitted to rejoin after the operation has completed

For all use cases the following invariant applies:

  • Clients optionally need to be able to track the progress of scheduled deletion once a room has been marked delete

Copy link
Contributor

@Gnuxie Gnuxie Dec 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For maintenance in order for the endpoint to be sound, the endpoint will still need to be idempotent and mark the room delete. Imagine that a server admin schedules a deletion to reduce the backup size via an endpoint with the same semantics as synapse room delete. Once the deletion task has finished, they will go ahead and pgdump a backup. During processing of the deletion task, or immediately afterwards and before the pgdump can start, a user rejoins the room. The room's data is then stored in the backup.

What really needs to happen here is that the room is unmarked delete once the backup/vaccuming/other maintenance activities have completed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated this to emphasise that the server is responsible for fulfilling the request and how it removes that responsibility from the client instead, in a way that effectively drapes a lock over the room while it's being worked on. What are your thoughts on the new wording?

Copy link
Contributor

@Gnuxie Gnuxie Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The delete endpoint you created isn't idempotent and is buggy. It's not possible to enforce this restriction because the API design makes it impossible:

Servers MUST take responsibility for ensuring the request is fulfilled eventually. Situations like mid-operation restarts cannot be allowed to permanently destroy the task, it must resume at the next available opportunity. Only once the task has completed should the room become available again. This removes the responsibility for ensuring this from the client.

Without delete being a distinct persistent state that has the same properties as block. This is because unblocking the room alone in your version (where delete does not imply the same semantics as block) can fail the fragile task to delete. So the client is still responsible for checking the room is actually deleted instead of just checking the room is in the persistent state of delete.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you need is to mirror the block / unblock endpoints but with a delete endpoint. For clients that need to check up on whether the room was deleted they can just source that from the room information endpoint.

Copy link
Contributor

@Gnuxie Gnuxie Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in response to GET /_matrix/client/v1/admin/rooms/{roomID}

{ 
    // Block is a distinct state
    "block": false,
    // Room is marked for delete, delete has the semantics of block but is stronger in that the room will be deleted from the db
    "delete": true,
    // Homeserver hasn't removed the room from its database yet
    "deleted": false,
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

client-server Client-Server API kind:feature MSC for not-core and not-maintenance stuff needs-implementation This MSC does not have a qualifying implementation for the SCT to review. The MSC cannot enter FCP. proposal A matrix spec change proposal safety

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants