Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MSC1840: Typed rooms #1840

Closed
112 changes: 112 additions & 0 deletions proposals/1840-room-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
- **Author**: Jonathan Frederickson
- **Created**: 2019-02-03

# Room Types

## Problem

The Matrix protocol currently has no mechanism to differentiate rooms
from each other based on their intended use case. There have been
proposals such as
[MSC1769](https://github.com/matrix-org/matrix-doc/pull/1769) and
[MSC1772](https://github.com/matrix-org/matrix-doc/pull/1772) that use
rooms for purposes other than the traditional messaging
use-case. Without a mechanism to differentiate them from messaging
rooms, clients will display them as they do any other room unless they
work around this limitation on a case-by-case basis.

## Solution

The proposal is to add a new state event, `m.room.type`, to define the
Copy link
Contributor

Choose a reason for hiding this comment

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

I realise this may bloat the proposal, but I feel like we should define a few common types in the spec and how clients should react to them, at least at a high level. I.e. m.room_type.messaging should present users with a chat-room like interface, wheras m.room_type.iot.* may just show a simplified view.

Copy link

Choose a reason for hiding this comment

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

Maybe a type like m.room_type.nsfw could be used to filter out explicit content. In that case, would it make sense to allow public directory filtering by room type?

Copy link
Contributor

Choose a reason for hiding this comment

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

Marking something as nsfw is more like a tag than a type IMO, because you can have nsfw content in different types of room. I think nsfw tagging (or content notices/warnings to be more generic) are a separate topic.

Choose a reason for hiding this comment

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

Counter-examples are useful too. It's worth included a counter-example like this in the spec to illustrate one of the boundaries of applicability.

Copy link
Author

@jfrederickson jfrederickson Oct 28, 2020

Choose a reason for hiding this comment

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

Added a few examples.

For what it's worth... nsfw might still be a useful type to have if it's possible to have multiple types associated with a room? In other words, rather than:

"content": {
    "type": "m.messaging"
}

Use an array:

"content": {
    "types": ["m.messaging", "m.nsfw"]
}

...though regardless of the types in particular, I'd like to consider the option of a types array. @jcgruenhage brought this up outside of a thread, and I think I agree with it:

What do people think about having multi purpose rooms? For example if a room is used for hosting a git project in matrix, using the same room for discussion about that project would be desirable, because it allows us to use the same alias there.

Copy link
Member

Choose a reason for hiding this comment

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

Allowing multiple types at once would cause massive confusion especially in clients which denormalize data. Imagine a room marked as IoT, Messaging, a Matrix Space and a User Profile room, how do you store anything and what do you even render?

Copy link

Choose a reason for hiding this comment

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

It was suggested in #matrix-spec:matrix.org that I use org.matrix.msc1840 as an unstable state event type until this PR is merged. Should this be noted somewhere in this document?

Copy link
Member

Choose a reason for hiding this comment

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

Yes please, typically in an Unstable Prefix section.

Copy link
Contributor

Choose a reason for hiding this comment

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

As a client developer, I would strongly argue to make room types immutable after room creation (e.g. putting it in /createRoom / m.room.create). Needing to anticipate that a community or profile room can be turned into a conversation room is just going to be a source for a lot of complexity. I also can't see any use case for this, we even want the DM-status of a conversation to be immutable in their new incarnation. And if we would want some type in the future that is mutable, we can always use a separate sub_type state event then.

The way to implement communities and profiles on Hydrogen for example would be to have a specialized storage model for those room types, which can't be turned back into a conversation room without resyncing that one room. I would argue that the spec should not exclude clients from making these kinds of optimizations, or at least burdening them with an unreasonable amount of complexity with no good use-case.

Copy link
Contributor

@Sorunome Sorunome Oct 21, 2020

Choose a reason for hiding this comment

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

I also can't see any use case for this, we even want the DM-status of a conversation to be immutable in their new incarnation.

Soru has had multiple usecases already where she invited people into a DM making it a "normal" room and vice versa. The usecase for that does exist and it makes it way harder now that element removed the UI for it :(

Needing to anticipate that a community or profile room can be turned into a conversation room is just going to be a source for a lot of complexity.

How so? With fluffychat at least it just builds up all the views of the current state, and does not tag anything permanently. The only exception here is not allowing to disable e2ee

Copy link
Contributor

Choose a reason for hiding this comment

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

Soru has had multiple usecases already where she invited people into a DM making it a "normal" room and vice versa. The usecase for that does exist and it makes it way harder now that element removed the UI for it :(

As mentioned, if the DM-flag needs to be mutable, maybe there is a case for an immutable type as well as a mutable (sub)type.

Needing to anticipate that a community or profile room can be turned into a conversation room is just going to be a source for a lot of complexity.

How so? With fluffychat at least it just builds up all the views of the current state, and does not tag anything permanently. The only exception here is not allowing to disable e2ee

Hydrogen for example persists things in a denormalized state, and for a community room likely won't be storing the timeline. Apart from that, it seems nonsensical to allow a community room to be converted into a conversation room. Even if it would be easy to implement, it is something that will not be well tested (and therefore handled) and might not be expected by some clients.

Copy link
Member

Choose a reason for hiding this comment

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

Apart from that, it seems nonsensical to allow a community room to be converted into a conversation room.

converting DMs to general rooms and back again is something we have today. Designing it out of the protocol feels like a big decision to me.

Copy link
Contributor

Choose a reason for hiding this comment

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

Apart from that, it seems nonsensical to allow a community room to be converted into a conversation room. Even

But maybe the other way round :)

Copy link
Contributor

Choose a reason for hiding this comment

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

room version upgrade is a bad example as that is a non-linear structure. One "low-level" room can have multiple parents. Which is exactly why UX is hard

Copy link
Contributor

@bwindels bwindels Nov 18, 2020

Choose a reason for hiding this comment

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

Apart from that, it seems nonsensical to allow a community room to be converted into a conversation room.

converting DMs to general rooms and back again is something we have today. Designing it out of the protocol feels like a big decision to me.

Agreed, so I'd say we need two kinds of types: a immutable one and a mutable one, e.g. "type": "m.messaging" with "sub_type": "m.dm", or "type": "m.space" for a #1772 space.

This may feel less elegant, but this really feels like madness otherwise, turning a space into conversation being akin to taking a sqlite file created by one application and trying to load it into another.

Copy link
Member

Choose a reason for hiding this comment

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

fwiw, there's no reason why a DM room needs to be its own type. Canonical DMs and associated MSCs can figure out how to represent it differently (like using m.kind in the current proposal).

Copy link
Contributor

@bwindels bwindels Nov 18, 2020

Choose a reason for hiding this comment

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

fwiw, there's no reason why a DM room needs to be its own type. Canonical DMs and associated MSCs can figure out how to represent it differently (like using m.kind in the current proposal).

Right, but we might want to adjust the naming to make clear that the (mutable) kind is scoped within the (immutable) type? Having a type and a kind on a room might be confusing if their relationship is not clear. In any case, the main point being there is a place for both an immutable and mutable flag, so we should have both.

Copy link
Member

Choose a reason for hiding this comment

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

yea, kind is badly named regardless of this MSC or not - the Canonical DMs MSC might be the one to figure out what mutable looks like. This MSC shouldn't be mutable imo.

intended usage of the room. Some example use cases for this:
Copy link

@joepie91 joepie91 Jan 3, 2021

Choose a reason for hiding this comment

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

I have a feeling that a lot of the discussions surrounding the exact semantics of this feature, revolve around the same problem: the premise of the MSC is wrong in a subtle but important way.

This MSC presents the room type as representing the "intended usage" - but is that really what anyone cares about?

  • Users will infer the intended usage from context (title, description, existing content, what they have been told by others, etc.). They don't need a room type property.
  • Client developers don't care about the intended usage, exactly, rather they care about how the room should be presented to the user and/or what additional features and capabilities should be attached to it.
  • Bot developers don't care about "intended usage" at all, they just care about whether there is actionable content in the room. That's usually pretty close to "how should it be presented to the user", since the purpose of bots is typically to assist users in their desired usage of a room.
  • Homeserver developers don't care about "intended usage" either. They only care about the event types contained therein, and whether there are special processing rules or storage optimizations for those event types.

"What a room contains" is already appropriately addressed by the event types themselves, so should be out-of-scope for this MSC. Likewise, human context is out-of-scope for MSCs entirely. This leaves one thing that people do actually care about: how should a room be presented to the user?

This perspective also makes the question of "multiple types" (ie. room tags) easier to address: yes, supporting multiple tags makes sense, because rooms may benefit from multiple representations. For example, a room for a hackerspace may contain both:

  1. Conversation and chatter between members of the hackerspace, and
  2. Sensor data for the environmental sensors in the corresponding physical space

It would conceptually make sense to group these messages together into a single room that represents "the hackerspace" as a physical space in a virtual environment. Yet there are multiple ways to represent this room; either as a stream of (visualized?) sensor data, or as a chatroom.

In this situation, some clients may only care about the sensor data, some only about the chatroom, some about both. A client can freely pick those tags which it can support in terms of representation to the end-user, and where necessary, make a contextual determination of which representation it considers the "primary" one (eg. chat by default, sensor data in a separate panel).

(Such a determination could be made easier by considering the tags to be ordered, so that a room can - on a protocol level - express a priority order for its tags, if it has multiple.)

As another example of multiple-tag application, communicating that nested/threaded rendering is desirable if possible can be done with an additional tag, without needing to give up whichever tag a 'normal' Matrix client would be looking for to render a chatroom. Ordering-wise, that would likely go before the normal messaging tag to express a preference for nested view.

It also addresses the question of type mutability: yes, the intended representations of a room can change. The hypothetical hackerspace members in aforementioned example might decide that they actually hate sensors (Internet of Shit, right?), and stop publishing sensor data and remove the corresponding room tag. In that case, a client might decide to no longer (prominently) offer the sensor view from that point onwards.

And to address upfront how "intended representation" is not already handled by event types: while there is relative freedom in choice of event type for custom non-spec usecases, this is not true for usecases that are covered by the spec.

For example, regular messages are supposed to be represented with m.message and probably an m.text kind, even if they should get a special representation such as in an e-mail thread. The ability to apply "room representation tags" to this end would help to resolve this ambiguity.

It would also help to communicate to clients that they should expect a certain kind of content, rather than needing to infer this from whatever events are currently in the client's buffer, which might result in additional representations suddenly popping up when the user navigates back through the room history.

Copy link

Choose a reason for hiding this comment

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

Addendum: while the "multiple representations" requirement could also be implemented by declaring that each representation should have its own dedicated room, I feel that that solution would be inferior:

  1. It does not really simplify things at all. You would still want to link together the representations semantically, so you would need some sort of 'room link'. Now, instead of a flat array of (string) tags, the client needs to deal with an array of room references and correlate cross-room state.
  2. Having separate representations as separate rooms actually introduces more complexity; not only would it raise questions of handling shared membership state (like are being encountered in the Spaces proposal), it would also make it difficult to represent eg. references between events that belong to different representations, share events between representations, and just overall introduce more need for cross-referencing logic in clients.

Aside from those points, I feel that the broader concept of multiple room representations could neatly complement Widgets; whereas Widgets are suitable for wholesale-embeddable 'applets' without long-term Matrix-side state, this design would work well for usecases where the client is expected to do the representation itself, and it is desirable to persist/replicate the state in the same way as any other Matrix event.


- A long-form email-style client wants to provide a UI for sending
longer (possibly threaded) messages, but doesn't want those threads
to be overwhelmed by users sending short IM-style messages
(`m.messaging.mail` perhaps?)
- A blogging app built on Matrix wants to define and use custom "blog
post" and "comment" message types, but doesn't want Element users to
join with a client that doesn't understand any of the messages
- A project wants to use Matrix to allow a user to interact with an
IoT lightbulb, but doesn't want the rooms and control messages used
for this to clutter up the user's Element room list
(`com.example.manufacturer.iot.light`)

The list of possible values of `type` is user-extensible; this
proposal defines `m.messaging`, but other types may be used by
client developers as desired. Grammar of values must conform to
[MSC2758](https://github.com/matrix-org/matrix-doc/blob/master/proposals/2758-textual-id-grammar.md)
rules for textual identifiers.

This proposal defines `m.messaging` as the (thus far) traditional
instant-messaging style room found in Element and most other Matrix
clients today. Client developers may handle rooms without a type in a
way that makes sense for each client; for example, it is expected that
an IM client would list both untyped rooms (for backwards
compatibility) and rooms of type `m.messaging` in the room
list. However, clients that are aware of room types should add the
relevant room type state event when creating new rooms.

This by itself could be used by a client to properly display rooms
based on their intended usage. However, to optimize the use of
bandwidth for an account used for varying purposes, the filter API
could then be extended to allow for filtering the rooms that are
returned from a sync based on room type. (A client meant for receiving
IoT device data, for example, has no need to receive messages destined
for that account, nor to be aware at all that messaging rooms exist.)

N.B. There's an opportunity here to additionally scope access tokens
to specific room types, but that feels like it's beyond the scope of
this proposal at this point.

## Examples
Copy link
Contributor

Choose a reason for hiding this comment

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

If the type is omitted, would we consider m.room_type.messaging to be the default type given Matrix's history.

Choose a reason for hiding this comment

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

It would be wrong for this part of the spec to state a default value unconditionally. Concretely, it would be wrong for a general purpose library or SDK to report an unconditionally specified default value when the type is omitted.

A typical IM client, working with typical existing IM rooms, will presumably by default (when the type is unspecified) assume it's an IM messaging room; whereas the default assumption in an IoT client will be something else; and there could be deployment scenarios where all rooms have an explicit room type and no default is needed and the client software developed for that scenario reports an error or ignores the room if no type is provided.

A default value is in the eye of the beholder, not absolute.


### m.room.type

Choose a reason for hiding this comment

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

The MSC should give examples of non-messaging room types; either hypothetical or real ones will do.

The current single example of "messaging" is not really useful except to demonstrate syntax, because in the current ecosystem there's hardly anything else so it's hard to deduce anything about the scope and boundaries of applicability of this type.

Copy link
Author

Choose a reason for hiding this comment

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

Added a few examples - does that sufficiently answer this?


```json
{
"content": {
"type": "m.messaging"
},
"event_id": "$143273582443PhrSn:example.com",
"origin_server_ts": 1432735824653,
"room_id": "!jEsUZKDJdhlrceRyVU:example.com",
"sender": "@user:example.com",
"state_key": "",
"type": "m.room.type",
"unsigned": {
"age": 1234
}
}
```

### Filter API Changes

```
POST /_matrix/client/r0/user/%40alice%3Aexample.com/filter HTTP/1.1
Content-Type: application/json

{
"room": {
"state": {
"types": [
"m.room.*"
],
"not_rooms": [
"!726s6s6q:example.com"
],
"room_types": [
"m.room_type.messaging"
],
"not_room_types": [
"m.room_type.iot.*"
],
},
"event_format": "client",
"event_fields": [
"type",
"content",
"sender"
]
}
```