diff --git a/changelogs/appendices/newsfragments/2193.feature b/changelogs/appendices/newsfragments/2193.feature
new file mode 100644
index 00000000..317f317f
--- /dev/null
+++ b/changelogs/appendices/newsfragments/2193.feature
@@ -0,0 +1 @@
+Room IDs can now appear without a domain component in [room version 12](/rooms/v12), as per [MSC4291](https://github.com/matrix-org/matrix-spec-proposals/pull/4291).
diff --git a/changelogs/client_server/newsfragments/2193.feature.1 b/changelogs/client_server/newsfragments/2193.feature.1
new file mode 100644
index 00000000..befb76d2
--- /dev/null
+++ b/changelogs/client_server/newsfragments/2193.feature.1
@@ -0,0 +1 @@
+When upgrading rooms to [room version 12](/rooms/v12), `additional_creators` may be specified on the [`POST /_matrix/client/v3/rooms/{roomId}/upgrade`](/client-server-api/#post_matrixclientv3roomsroomidupgrade) endpoint, as per [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289).
diff --git a/changelogs/client_server/newsfragments/2193.feature.2 b/changelogs/client_server/newsfragments/2193.feature.2
new file mode 100644
index 00000000..280a83e6
--- /dev/null
+++ b/changelogs/client_server/newsfragments/2193.feature.2
@@ -0,0 +1 @@
+When creating rooms with [room version 12](/rooms/v12), the `trusted_private_chat` preset should merge the invitees into the supplied `content.additional_creators` in the resulting room, as per [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289).
diff --git a/changelogs/client_server/newsfragments/2193.feature.3 b/changelogs/client_server/newsfragments/2193.feature.3
new file mode 100644
index 00000000..5f8b1fab
--- /dev/null
+++ b/changelogs/client_server/newsfragments/2193.feature.3
@@ -0,0 +1 @@
+In [room version 12](/rooms/v12), the power level of room creators is now infinitely high as per [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289).
diff --git a/changelogs/client_server/newsfragments/2193.feature.4 b/changelogs/client_server/newsfragments/2193.feature.4
new file mode 100644
index 00000000..98d8f126
--- /dev/null
+++ b/changelogs/client_server/newsfragments/2193.feature.4
@@ -0,0 +1 @@
+In [room version 12](/rooms/v12), room IDs no longer have a domain component as per [MSC4291](https://github.com/matrix-org/matrix-spec-proposals/pull/4291).
diff --git a/changelogs/client_server/newsfragments/2193.feature.5 b/changelogs/client_server/newsfragments/2193.feature.5
new file mode 100644
index 00000000..e1b54e80
--- /dev/null
+++ b/changelogs/client_server/newsfragments/2193.feature.5
@@ -0,0 +1 @@
+When creating rooms with [room version 12](/rooms/v12), the initial power levels will restrict the ability to upgrade rooms by default, as per [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289).
diff --git a/changelogs/internal/newsfragments/2193.feature b/changelogs/internal/newsfragments/2193.feature
new file mode 100644
index 00000000..43972665
--- /dev/null
+++ b/changelogs/internal/newsfragments/2193.feature
@@ -0,0 +1 @@
+TODO: Placeholder
\ No newline at end of file
diff --git a/changelogs/room_versions/newsfragments/2193.clarification b/changelogs/room_versions/newsfragments/2193.clarification
new file mode 100644
index 00000000..39e25b5a
--- /dev/null
+++ b/changelogs/room_versions/newsfragments/2193.clarification
@@ -0,0 +1 @@
+In room versions 1 through 12, an event's `auth_events` have always needed to belong to the same room as per [MSC4307](https://github.com/matrix-org/matrix-spec-proposals/pull/4307).
diff --git a/changelogs/room_versions/newsfragments/2193.feature.1 b/changelogs/room_versions/newsfragments/2193.feature.1
new file mode 100644
index 00000000..88e57469
--- /dev/null
+++ b/changelogs/room_versions/newsfragments/2193.feature.1
@@ -0,0 +1 @@
+Add [room version 12](/rooms/v12) as per [MSC4304](https://github.com/matrix-org/matrix-spec-proposals/pull/4304).
diff --git a/changelogs/room_versions/newsfragments/2193.feature.2 b/changelogs/room_versions/newsfragments/2193.feature.2
new file mode 100644
index 00000000..995fe87b
--- /dev/null
+++ b/changelogs/room_versions/newsfragments/2193.feature.2
@@ -0,0 +1 @@
+Room IDs in room version 12 are now the event ID of the create event with the normal room ID sigil (`!`), as per [MSC4291](https://github.com/matrix-org/matrix-spec-proposals/pull/4291).
diff --git a/changelogs/room_versions/newsfragments/2193.feature.3 b/changelogs/room_versions/newsfragments/2193.feature.3
new file mode 100644
index 00000000..2a396a3e
--- /dev/null
+++ b/changelogs/room_versions/newsfragments/2193.feature.3
@@ -0,0 +1 @@
+Room creators are formalized in room version 12 and have infinitely high power level, as per [MSC4289](https://github.com/matrix-org/matrix-spec-proposals/pull/4289).
diff --git a/changelogs/room_versions/newsfragments/2193.feature.4 b/changelogs/room_versions/newsfragments/2193.feature.4
new file mode 100644
index 00000000..c9f22df1
--- /dev/null
+++ b/changelogs/room_versions/newsfragments/2193.feature.4
@@ -0,0 +1 @@
+State Resolution is updated in room version 12 to reduce the opportunity for "state resets", as per [MSC4297](https://github.com/matrix-org/matrix-spec-proposals/pull/4297).
diff --git a/changelogs/room_versions/newsfragments/2193.feature.5 b/changelogs/room_versions/newsfragments/2193.feature.5
new file mode 100644
index 00000000..6c1ee1fc
--- /dev/null
+++ b/changelogs/room_versions/newsfragments/2193.feature.5
@@ -0,0 +1 @@
+The default room version is now room version 12, though servers SHOULD keep using room version 11 for a little while, as per [MSC4304](https://github.com/matrix-org/matrix-spec-proposals/pull/4304).
diff --git a/content/appendices.md b/content/appendices.md
index 349b05e9..923f9315 100644
--- a/content/appendices.md
+++ b/content/appendices.md
@@ -657,27 +657,48 @@ provides no way to encode ASCII punctuation).
#### Room IDs
-A room has exactly one room ID. A room ID has the format:
+{{% changed-in v="1.16" %}} Room IDs can now appear without a domain depending on
+the room version.
+
+A room has exactly one room ID. Room IDs take the form:
+
+ !opaque_id
+
+However, the precise format depends upon the [room version specification](/rooms):
+some room versions included a `domain` component, whereas more recent room versions
+omit the domain and use a base64-encoded hash instead.
+
+Room IDs are case-sensitive and not meant to be human-readable. They are intended
+to be used as fully opaque strings by clients, even when a `domain` component is
+present.
+
+If the room version requires a `domain` component, room IDs take the following
+form:
!opaque_id:domain
-The `domain` of a room ID is the [server name](#server-name) of the
-homeserver which created the room. The domain is used only for
-namespacing to avoid the risk of clashes of identifiers between
-different homeservers. There is no implication that the room in
-question is still available at the corresponding homeserver.
+In such a form, the `opaque_id` is a localpart. The localpart MUST only contain
+valid non-surrogate Unicode code points, including control characters, except `:`
+and `NUL` (U+0000). The localpart SHOULD only consist of alphanumeric characters
+(`A-Z`, `a-z`, `0-9`) when generating them. The `domain` is the [server name](#server-name)
+of the homeserver which created the room - it is only used to reduce namespace
+collisions. There is no implication that the room in question is still available
+at the corresponding homeserver. Combined, the localpart, domain, and `!` sigil
+MUST NOT exceed 255 bytes.
-Room IDs are case-sensitive. They are not meant to be
-human-readable. They are intended to be treated as fully opaque strings
-by clients.
+When a room version requires the `domain`-less format, room IDs are simply the
+[event ID](#event-ids) of the `m.room.create` event using `!` as the sigil instead
+of `$`. The grammar is otherwise inherited verbatim.
-The localpart of a room ID (`opaque_id` above) may contain any valid
-non-surrogate Unicode code points, including control characters, except `:` and `NUL`
-(U+0000), but it is recommended to only include ASCII letters and
-digits (`A-Z`, `a-z`, `0-9`) when generating them.
+{{% boxes/note %}}
+Applications which previously relied upon the `domain` in a room ID can instead
+parse the [user IDs](#user-identifiers) found in the `m.room.create` event's `sender`.
-The length of a room ID, including the `!` sigil and the domain, MUST
-NOT exceed 255 bytes.
+Though the `m.room.create` event's `additional_creators` (in `content`) may be
+used when present, applications should take care when parsing or interpreting the
+list. The user IDs in `additional_creators` will have correct grammar, but may
+not be real users or may not belong to actual Matrix homeservers.
+{{% /boxes/note %}}
#### Room Aliases
diff --git a/content/client-server-api/_index.md b/content/client-server-api/_index.md
index 173769c9..18a9cc27 100644
--- a/content/client-server-api/_index.md
+++ b/content/client-server-api/_index.md
@@ -2506,7 +2506,7 @@ and the client is not permitted to make any changes.
When `enabled` is `true`, clients are permitted to modify profile fields,
subject to the restrictions implied by the OPTIONAL lists `allowed` and
-`disallowed`.
+`disallowed`.
If `allowed` is present, clients can modify only the fields
listed. They SHOULD assume all other fields to be managed by
@@ -2546,7 +2546,7 @@ This capability is now deprecated. Clients SHOULD use the
[`m.profile_fields`](/client-server-api/#mprofile_fields-capability)
capability instead.
-For backwards compatibility, servers that forbid setting the
+For backwards compatibility, servers that forbid setting the
`displayname` profile field in the `m.profile_fields` capability
MUST still present this capability with `"enabled": false`.
{{% /boxes/note %}}
@@ -2581,7 +2581,7 @@ This capability is now deprecated. Clients SHOULD use the
[`m.profile_fields`](/client-server-api/#mprofile_fields-capability)
capability instead.
-For backwards compatibility, servers that forbid setting the
+For backwards compatibility, servers that forbid setting the
`avatar_url` profile field in the `m.profile_fields` capability
MUST still present this capability with `"enabled": false`.
{{% /boxes/note %}}
@@ -3414,27 +3414,49 @@ request.
### Permissions
-{{% boxes/note %}}
-This section is a work in progress.
-{{% /boxes/note %}}
+{{% changed-in v="1.16" %}} Updated section to discuss creator power level
+in room version 12 and beyond.
Permissions for rooms are done via the concept of power levels - to do
any action in a room a user must have a suitable power level. Power
levels are stored as state events in a given room. The power levels
-required for operations and the power levels for users are defined in
-`m.room.power_levels`, where both a default and specific users' power
-levels can be set. By default all users have a power level of 0, other
-than the room creator whose power level defaults to 100. Users can grant
-other users increased power levels up to their own power level. For
-example, user A with a power level of 50 could increase the power level
-of user B to a maximum of level 50. Power levels for users are tracked
-per-room even if the user is not present in the room. The keys contained
-in `m.room.power_levels` determine the levels required for certain
-operations such as kicking, banning and sending state events. See
-[m.room.power\_levels](#room-events) for more information.
-
-Clients may wish to assign names to particular power levels. A suggested
-mapping is as follows: - 0 User - 50 Moderator - 100 Admin
+required for operations and the power levels assigned to specific users
+are defined in the `m.room.power_levels` state event. The `m.room.power_levels`
+state event additionally defines some defaults, though room creators
+are special in that:
+
+* In [room versions](/rooms) 1 through 11, room creators by default
+ have power level 100 but still can have that level changed by power level
+ events, by the same rules as other members.
+* In [room version 12](/rooms/v12) (and beyond), room creators are
+ *not* specified in the power levels event and have an infinitely high
+ power level that is immutable. After room creation, users
+ cannot be given this same infinitely high power level.
+
+Users can grant other users increased power levels up to their own
+power level (or the maximum allowable integer for the room when their
+power level is infinitely high). For example, user A with a power level
+of 50 could increase the power level of user B to a maximum of level 50.
+Power levels for users are tracked per-room even if the user is not
+present in the room. The keys contained in `m.room.power_levels` determine
+the levels required for certain operations such as kicking, banning, and
+sending state events. See [`m.room.power_levels`](#mroompower_levels) for more
+information.
+
+Clients may wish to assign names to particular power levels. Most rooms
+will use the default power level hierarchy assigned during room creation,
+but rooms may still deviate slightly.
+
+A suggested mapping is as follows:
+
+* 0 to `state_default-1` (typically 49): User
+* `state_default` to the level required to send `m.room.power_levels` events
+ minus 1 (typically 99): Moderator
+* The level required send `m.room.power_levels` events and above: Administrator
+* Creators of the room, in room version 12 and beyond: Creator
+
+Clients may also wish to distinguish "above admin" power levels based on the
+level required to send `m.room.tombstone` events.
### Room membership
diff --git a/content/client-server-api/modules/room_upgrades.md b/content/client-server-api/modules/room_upgrades.md
index 647fb377..0950b34f 100644
--- a/content/client-server-api/modules/room_upgrades.md
+++ b/content/client-server-api/modules/room_upgrades.md
@@ -36,6 +36,17 @@ server:
previous room, no `type` is specified on the new room's create event
either.
+{{% boxes/note %}}
+{{% added-in v="1.16" %}} If both the new and old [room version](/rooms) support
+additional creators, the server will not transfer those additional creators automatically.
+They must be explicitly set during the `/upgrade` call.
+{{% /boxes/note %}}
+
+{{% boxes/note %}}
+{{% added-in v="1.16" %}} When upgrading to room version 12 or later, the `predecessor` field MAY NOT contain
+an `event_id`.
+{{% /boxes/note %}}
+
3. Replicates transferable state events to the new room. The exact
details for what is transferred is left as an implementation detail,
however the recommended state events to transfer are:
diff --git a/content/rooms/_index.md b/content/rooms/_index.md
index d970bfe7..3e7aec72 100644
--- a/content/rooms/_index.md
+++ b/content/rooms/_index.md
@@ -36,11 +36,12 @@ Alternatively, consider flipping the column/row organization to be features
up top and versions on the left.
-->
-| Feature \ Version | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
-|-------------------|---|---|---|---|---|---|---|---|---|----|----|
-| **Knocking** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ |
-| **Restricted join rules** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ |
-| **`knock_restricted` join rule** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ |
+| Feature \ Version | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
+|-------------------|---|---|---|---|---|---|---|---|---|----|----|----|
+| **Knocking** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| **Restricted join rules** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ | ✔ | ✔ |
+| **`knock_restricted` join rule** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ | ✔ | ✔ |
+| **Additional room creators** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✔ |
## Complete list of room versions
@@ -52,9 +53,22 @@ stable and unstable periodically for a variety of reasons, including
discovered security vulnerabilities and age.
Clients should not ask room administrators to upgrade their rooms if the
-room is running a stable version. Servers SHOULD use **room version 11** as
+room is running a stable version. Servers SHOULD use **room version 12** as
the default room version when creating new rooms.
+{{% boxes/note %}}
+
+{{% added-in v="1.16" %}}
+
+Room version 12 is introduced and made default in this specification release.
+Servers are encouraged to continue using room version 11 as the default room
+version for the early days and weeks following this specification release,
+and then gradually switch the default over when they deem appropriate.
+
+
+
+{{% /boxes/note %}}
+
The available room versions are:
- [Version 1](/rooms/v1) - **Stable**. The initial room version.
@@ -76,6 +90,9 @@ The available room versions are:
- [Version 10](/rooms/v10) - **Stable**. Enforces integer-only power levels
and adds `knock_restricted` join rule.
- [Version 11](/rooms/v11) - **Stable**. Clarifies the redaction algorithm.
+- [Version 12](/rooms/v12) - **Stable**. Changes room IDs to be hashes of the
+ create event, formalizes room creators with infinite power level, and iterates
+ on state resolution.
## Room version grammar
diff --git a/content/rooms/fragments/v1-auth-rules.md b/content/rooms/fragments/v1-auth-rules.md
index 3ea09982..ba637beb 100644
--- a/content/rooms/fragments/v1-auth-rules.md
+++ b/content/rooms/fragments/v1-auth-rules.md
@@ -30,10 +30,14 @@ The rules are as follows:
specified by the [auth events
selection](/server-server-api#auth-events-selection)
algorithm described in the server specification, reject.
+
+ **Note**: This room version requires an `m.room.create` event to be selected.
3. If there are entries which were themselves rejected under the [checks
performed on receipt of a
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
4. If there is no `m.room.create` event among the entries, reject.
+ 5. If any event in `auth_events` has a `room_id` which does not match that of
+ the event being authorised, reject.
3. If the `content` of the `m.room.create` event in the room state has the
property `m.federate` set to `false`, and the `sender` domain of the event
does not match the `sender` domain of the create event, reject.
diff --git a/content/rooms/fragments/v12-event-format.md b/content/rooms/fragments/v12-event-format.md
new file mode 100644
index 00000000..ca596638
--- /dev/null
+++ b/content/rooms/fragments/v12-event-format.md
@@ -0,0 +1,4 @@
+
+Events in rooms of this version have the following structure:
+
+{{% definition path="api/server-server/definitions/pdu_v12" %}}
diff --git a/content/rooms/fragments/v3-auth-rules.md b/content/rooms/fragments/v3-auth-rules.md
index 577dfe4e..6b7f294e 100644
--- a/content/rooms/fragments/v3-auth-rules.md
+++ b/content/rooms/fragments/v3-auth-rules.md
@@ -38,10 +38,14 @@ The complete list of rules, as of room version 3, is as follows:
specified by the [auth events
selection](/server-server-api#auth-events-selection)
algorithm described in the server specification, reject.
+
+ **Note**: This room version requires an `m.room.create` event to be selected.
3. If there are entries which were themselves rejected under the [checks
performed on receipt of a
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
4. If there is no `m.room.create` event among the entries, reject.
+ 5. If any event in `auth_events` has a `room_id` which does not match that of
+ the event being authorised, reject.
3. If the `content` of the `m.room.create` event in the room state has the
property `m.federate` set to `false`, and the `sender` domain of the event
does not match the `sender` domain of the create event, reject.
diff --git a/content/rooms/fragments/v8-auth-rules.md b/content/rooms/fragments/v8-auth-rules.md
index 8da010ef..9e267e53 100644
--- a/content/rooms/fragments/v8-auth-rules.md
+++ b/content/rooms/fragments/v8-auth-rules.md
@@ -44,10 +44,14 @@ The rules are as follows:
specified by the [auth events
selection](/server-server-api#auth-events-selection)
algorithm described in the server specification, reject.
+
+ **Note**: This room version requires an `m.room.create` event to be selected.
3. If there are entries which were themselves rejected under the [checks
performed on receipt of a
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
4. If there is no `m.room.create` event among the entries, reject.
+ 5. If any event in `auth_events` has a `room_id` which does not match that of
+ the event being authorised, reject.
3. If the `content` of the `m.room.create` event in the room state has the
property `m.federate` set to `false`, and the `sender` domain of the event
does not match the `sender` domain of the create event, reject.
diff --git a/content/rooms/v10.md b/content/rooms/v10.md
index 81daf4d6..3cfe1998 100644
--- a/content/rooms/v10.md
+++ b/content/rooms/v10.md
@@ -120,10 +120,14 @@ The rules are as follows:
specified by the [auth events
selection](/server-server-api#auth-events-selection)
algorithm described in the server specification, reject.
+
+ **Note**: This room version requires an `m.room.create` event to be selected.
3. If there are entries which were themselves rejected under the [checks
performed on receipt of a
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
4. If there is no `m.room.create` event among the entries, reject.
+ 5. If any event in `auth_events` has a `room_id` which does not match that of
+ the event being authorised, reject.
3. If the `content` of the `m.room.create` event in the room state has the
property `m.federate` set to `false`, and the `sender` domain of the event
does not match the `sender` domain of the create event, reject.
diff --git a/content/rooms/v11.md b/content/rooms/v11.md
index 1be3a405..db1b1928 100644
--- a/content/rooms/v11.md
+++ b/content/rooms/v11.md
@@ -127,10 +127,14 @@ The rules are as follows:
specified by the [auth events
selection](/server-server-api#auth-events-selection)
algorithm described in the server specification, reject.
+
+ **Note**: This room version requires an `m.room.create` event to be selected.
3. If there are entries which were themselves rejected under the [checks
performed on receipt of a
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
4. If there is no `m.room.create` event among the entries, reject.
+ 5. If any event in `auth_events` has a `room_id` which does not match that of
+ the event being authorised, reject.
3. If the `content` of the `m.room.create` event in the room state has the
property `m.federate` set to `false`, and the `sender` domain of the event
does not match the `sender` domain of the create event, reject.
diff --git a/content/rooms/v12.md b/content/rooms/v12.md
new file mode 100644
index 00000000..992488f0
--- /dev/null
+++ b/content/rooms/v12.md
@@ -0,0 +1,502 @@
+---
+title: Room Version 12
+type: docs
+weight: 100
+version: 12
+---
+
+This room version builds on [version 11](/rooms/v11), iterating on the state resolution
+algorithm, giving room creators infinite power level, and changing the format of room
+IDs to be a hash of the create event.
+
+## Client considerations
+
+### Event format
+
+Clients SHOULD observe the following changes to events in this room version:
+
+* Room IDs no longer include a domain component and are instead a hash of the
+ `m.room.create` event, per below. See the [room ID grammar](/appendices#room-ids)
+ for more information.
+
+* A concept of "room creators" is formally defined as the `sender` of the `m.room.create`
+ event *plus* any `additional_creators` from the `m.room.create` event's `content`,
+ if present. In prior room versions, the only creator was the `sender` of the
+ `m.room.create` event (or `creator` in much older room versions).
+
+* Room creators have infinitely high power level and cannot be specified in the
+ `m.room.power_levels` event, nor can they be changed after the room is created.
+
+## Server implementation components
+
+{{% boxes/warning %}}
+The information contained in this section is strictly for server
+implementors. Applications which use the Client-Server API are generally
+unaffected by the intricacies contained here. The section above
+regarding client considerations is the resource that Client-Server API
+use cases should reference.
+{{% /boxes/warning %}}
+
+Room version 12 is based upon room version 11 with the following considerations.
+
+### Event format
+
+{{% rver-fragment name="v12-event-format" %}}
+
+### Authorization rules
+
+Events must be signed by the server denoted by the `sender` property.
+
+The types of state events that affect authorization are:
+
+- [`m.room.create`](/client-server-api#mroomcreate)
+- [`m.room.member`](/client-server-api#mroommember)
+- [`m.room.join_rules`](/client-server-api#mroomjoin_rules)
+- [`m.room.power_levels`](/client-server-api#mroompower_levels)
+- [`m.room.third_party_invite`](/client-server-api#mroomthird_party_invite)
+
+{{% boxes/note %}}
+Power levels are inferred from defaults when not explicitly supplied.
+For example, mentions of the `sender`'s power level can also refer to
+the default power level for users in the room.
+{{% /boxes/note %}}
+
+{{% boxes/note %}}
+{{% added-in v=12 %}} The power level of "room creators" is infinitely high.
+
+Room creators include:
+* The user ID denoted by the `sender` of the `m.room.create` event in the room.
+* Any user IDs contained in the `additional_creators` array in `content` of the
+ `m.room.create` event in the room, if `additional_creators` is present.
+
+Room creators cannot be demoted to a lower power level, even through `m.room.power_levels`.
+This is reflected in rule 10.4 below.
+{{% /boxes/note %}}
+
+{{% boxes/note %}}
+`m.room.redaction` events are subject to auth rules in the same way as any other event.
+In practice, that means they will normally be allowed by the auth rules, unless the
+`m.room.power_levels` event sets a power level requirement for `m.room.redaction`
+events via the `events` or `events_default` properties. In particular, the _redact
+level_ is **not** considered by the auth rules.
+
+The ability to send a redaction event does not mean that the redaction itself should
+be performed. Receiving servers must perform additional checks, as described in
+the [Handling redactions](#handling-redactions) section.
+{{% /boxes/note %}}
+
+{{% boxes/note %}}
+The `m.room.create` event MUST NOT be selected for `auth_events` on events. The
+`room_id` (being the `m.room.create` event's ID) implies this instead. This is
+reflected in a change to rule 3.2 below.
+{{% /boxes/note %}}
+
+The rules are as follows:
+
+1. If type is `m.room.create`:
+ 1. If it has any `prev_events`, reject.
+ 2. {{% changed-in v=12 %}} If the event has a `room_id`, reject.
+
+ **Note**: The room ID is the event ID of the event with sigil `!` instead
+ of `$`.
+ 3. If `content.room_version` is present and is not a recognised
+ version, reject.
+ 4. {{% added-in v=12 %}} If `additional_creators` is present in `content` and
+ is not an array of strings where each string passes the same [user ID](/appendices#user-identifiers)
+ validation applied to `sender`, reject.
+ 5. Otherwise, allow.
+2. {{% added-in v=12 %}} If the event's `room_id` is not an event ID for an accepted
+ (not rejected) `m.room.create` event, with the sigil `!` instead of `$`, reject.
+3. Considering the event's `auth_events`:
+ 1. If there are duplicate entries for a given `type` and `state_key` pair,
+ reject.
+ 2. {{% changed-in v=12 %}} If there are entries whose `type` and `state_key`
+ don't match those specified by the [auth events selection](/server-server-api#auth-events-selection)
+ algorithm described in the server specification, reject.
+
+ **Note**: In this room version, `m.room.create` MUST NOT be selected.
+ 3. If there are entries which were themselves rejected under the [checks
+ performed on receipt of a
+ PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
+ 5. If any event in `auth_events` has a `room_id` which does not match that of
+ the event being authorised, reject.
+4. If the `content` of the `m.room.create` event in the room state has the
+ property `m.federate` set to `false`, and the `sender` domain of the event
+ does not match the `sender` domain of the create event, reject.
+5. If type is `m.room.member`:
+ 1. If there is no `state_key` property, or no `membership` property in
+ `content`, reject.
+ 2. If `content` has a `join_authorised_via_users_server`
+ key:
+ 1. If the event is not validly signed by the homeserver of the user ID denoted
+ by the key, reject.
+ 3. If `membership` is `join`:
+ 1. {{% changed-in v=11 %}}
+ If the only previous event is an `m.room.create` and the
+ `state_key` is the sender of the `m.room.create`, allow.
+ 2. If the `sender` does not match `state_key`, reject.
+ 3. If the `sender` is banned, reject.
+ 4. If the `join_rule` is `invite` or `knock` then allow if
+ membership state is `invite` or `join`.
+ 5. If the `join_rule` is `restricted` or `knock_restricted`:
+ 1. If membership state is `join` or `invite`, allow.
+ 2. If the `join_authorised_via_users_server` key in `content`
+ is not a user with sufficient permission to invite other
+ users, reject.
+ 3. Otherwise, allow.
+ 6. If the `join_rule` is `public`, allow.
+ 7. Otherwise, reject.
+ 4. If `membership` is `invite`:
+ 1. If `content` has a `third_party_invite` property:
+ 1. If *target user* is banned, reject.
+ 2. If `content.third_party_invite` does not have a `signed`
+ property, reject.
+ 3. If `signed` does not have `mxid` and `token` properties,
+ reject.
+ 4. If `mxid` does not match `state_key`, reject.
+ 5. If there is no `m.room.third_party_invite` event in the
+ current room state with `state_key` matching `token`,
+ reject.
+ 6. If `sender` does not match `sender` of the
+ `m.room.third_party_invite`, reject.
+ 7. If any signature in `signed` matches any public key in
+ the `m.room.third_party_invite` event, allow. The public
+ keys are in `content` of `m.room.third_party_invite` as:
+ 1. A single public key in the `public_key` property.
+ 2. A list of public keys in the `public_keys` property.
+ 8. Otherwise, reject.
+ 2. If the `sender`'s current membership state is not `join`,
+ reject.
+ 3. If *target user*'s current membership state is `join` or
+ `ban`, reject.
+ 4. If the `sender`'s power level is greater than or equal to
+ the *invite level*, allow.
+ 5. Otherwise, reject.
+ 5. If `membership` is `leave`:
+ 1. If the `sender` matches `state_key`, allow if and only if
+ that user's current membership state is `invite`, `join`,
+ or `knock`.
+ 2. If the `sender`'s current membership state is not `join`,
+ reject.
+ 3. If the *target user*'s current membership state is `ban`,
+ and the `sender`'s power level is less than the *ban level*,
+ reject.
+ 4. If the `sender`'s power level is greater than or equal to
+ the *kick level*, and the *target user*'s power level is
+ less than the `sender`'s power level, allow.
+ 5. Otherwise, reject.
+ 6. If `membership` is `ban`:
+ 1. If the `sender`'s current membership state is not `join`,
+ reject.
+ 2. If the `sender`'s power level is greater than or equal to
+ the *ban level*, and the *target user*'s power level is less
+ than the `sender`'s power level, allow.
+ 3. Otherwise, reject.
+ 7. If `membership` is `knock`:
+ 1. If the `join_rule` is anything other than `knock` or
+ `knock_restricted`, reject.
+ 2. If `sender` does not match `state_key`, reject.
+ 3. If the `sender`'s current membership is not `ban`, `invite`,
+ or `join`, allow.
+ 4. Otherwise, reject.
+ 8. Otherwise, the membership is unknown. Reject.
+6. If the `sender`'s current membership state is not `join`, reject.
+7. If type is `m.room.third_party_invite`:
+ 1. Allow if and only if `sender`'s current power level is greater
+ than or equal to the *invite level*.
+8. If the event type's *required power level* is greater than the
+ `sender`'s power level, reject.
+9. If the event has a `state_key` that starts with an `@` and does not
+ match the `sender`, reject.
+10. If type is `m.room.power_levels`:
+ 1. If any of the properties `users_default`, `events_default`, `state_default`,
+ `ban`, `redact`, `kick`, or `invite` in `content` are present and
+ not an integer, reject.
+ 2. If either of the properties `events` or `notifications` in `content`
+ are present and not an object with values that are integers,
+ reject.
+ 3. If the `users` property in `content` is not an object with keys that
+ are valid user IDs with values that are integers, reject.
+ 4. {{% added-in v=12 %}} If the `users` property in `content` contains the
+ `sender` of the `m.room.create` event or any of the `additional_creators`
+ array (if present) from the `content` of the `m.room.create` event, reject.
+ 5. If there is no previous `m.room.power_levels` event in the room,
+ allow.
+ 6. For the properties `users_default`, `events_default`, `state_default`,
+ `ban`, `redact`, `kick`, `invite` check if they were added,
+ changed or removed. For each found alteration:
+ 1. If the current value is higher than the `sender`'s current
+ power level, reject.
+ 2. If the new value is higher than the `sender`'s current power
+ level, reject.
+ 7. For each entry being changed in, or removed from, the `events` or
+ `notifications` properties:
+ 1. If the current value is greater than the `sender`'s current
+ power level, reject.
+ 8. For each entry being added to, or changed in, the `events` or
+ `notifications` properties:
+ 1. If the new value is greater than the `sender`'s current power
+ level, reject.
+ 9. For each entry being changed in, or removed from, the `users` property,
+ other than the `sender`'s own entry:
+ 1. If the current value is greater than or equal to the `sender`'s
+ current power level, reject.
+ 10. For each entry being added to, or changed in, the `users` property:
+ 1. If the new value is greater than the `sender`'s current power
+ level, reject.
+ 10. Otherwise, allow.
+11. Otherwise, allow.
+
+{{% boxes/note %}}
+Some consequences of these rules:
+
+- Unless you are a member of the room, the only permitted operations
+ (apart from the initial create/join) are: joining a public room;
+ accepting or rejecting an invitation to a room.
+- To unban somebody, you must have power level greater than or equal
+ to both the kick *and* ban levels, *and* greater than the target
+ user's power level.
+{{% /boxes/note %}}
+
+### State resolution
+
+{{% boxes/note %}}
+{{% added-in v=12 %}} This state resolution algorithm is largely the same as the
+algorithm found in [room version 2](/rooms/v2) with the following modifications:
+
+1. The *iterative auth checks algorithm* in the [Algorithm](#algorithm) subsection
+ now starts with an *empty* state map instead of the unconflicted state map.
+
+2. A new [definition](#definitions) for *conflicted state subgraph* has been added
+ which describes events that are required to authorize events during iterative
+ auth checks.
+
+3. To ensure the new conflicted state subgraph is actually referenced, the definition
+ for *full conflicted set* additionally includes the subgraph.
+{{% /boxes/note %}}
+
+The room state *S′(E)* after an event *E* is defined in terms of the
+room state *S(E)* before *E*, and depends on whether *E* is a state
+event or a message event:
+
+- If *E* is a message event, then *S′(E)* = *S(E)*.
+- If *E* is a state event, then *S′(E)* is *S(E)*, except that its
+ entry corresponding to the `event_type` and `state_key` of *E* is
+ replaced by the `event_id` of *E*.
+
+The room state *S(E)* before *E* is the *resolution* of the set of
+states {*S′(E*1*)*, *S′(E*2*)*, …}
+after the `prev_event`s {*E*1, *E*2, …} of *E*.
+The resolution of a set of states is given in the algorithm below.
+
+#### Definitions
+
+The state resolution algorithm for version 2 rooms uses the following
+definitions, given the set of room states
+{*S*1, *S*2, …}:
+
+**Power events.**
+A *power event* is a state event with type `m.room.power_levels` or
+`m.room.join_rules`, or a state event with type `m.room.member` where
+the `membership` is `leave` or `ban` and the `sender` does not match the
+`state_key`. The idea behind this is that power events are events that
+might remove someone's ability to do something in the room.
+
+**Unconflicted state map and conflicted state set.**
+The keys of the state maps *Si* are 2-tuples of strings of the form
+*K* = `(event_type, state_key)`. The values *V* are state events.
+The key-value pairs (*K*, *V*) across all state maps *Si* can be
+divided into two collections.
+If a given key *K* is present in every *Si* with the same value *V*
+in each state map, then the pair (*K*, *V*) belongs to the *unconflicted state map*.
+Otherwise, *V* belongs to the *conflicted state set*.
+
+Note that the unconflicted state map only has one event for each key *K*,
+whereas the conflicted state set may contain multiple events with the same key.
+
+**Auth chain.**
+The *auth chain* of an event *E* is the set containing all of *E*'s auth events,
+all of *their* auth events, and so on recursively, stretching back to the
+start of the room. Put differently, these are the events reachable by walking
+the graph induced by an event's `auth_events` links.
+
+**Auth difference.**
+The *auth difference* is calculated by first calculating the full auth
+chain for each state *S**i*, that is the union of the auth
+chains for each event in *S**i*, and then taking every event
+that doesn't appear in every auth chain. If *C**i* is the
+full auth chain of *S**i*, then the auth difference is
+∪ *C**i* − ∩ *C**i*.
+
+{{% added-in v=12 %}} **Conflicted state subgraph.**
+Starting from an event in the *conflicted state set* and following `auth_events`
+edges may lead to another event in the conflicted state set. The union of all
+such paths between any pair of events in the conflicted state set (including
+endpoints) forms a subgraph of the original `auth_event` graph, called the
+*conflicted state subgraph*.
+
+{{% changed-in v=12 %}} **Full conflicted set.**
+The *full conflicted set* is the union of the conflicted state set, the conflicted
+state subgraph, and the auth difference.
+
+**Reverse topological power ordering.**
+The *reverse topological power ordering* of a set of events is the
+lexicographically smallest topological ordering based on the DAG formed
+by auth events. The reverse topological power ordering is ordered from
+earliest event to latest. For comparing two topological orderings to
+determine which is the lexicographically smallest, the following
+comparison relation on events is used: for events *x* and *y*,
+*x* < *y* if
+
+1. *x*'s sender has *greater* power level than *y*'s sender, when
+ looking at their respective `auth_event`s; or
+2. the senders have the same power level, but *x*'s `origin_server_ts`
+ is *less* than *y*'s `origin_server_ts`; or
+3. the senders have the same power level and the events have the same
+ `origin_server_ts`, but *x*'s `event_id` is *less* than *y*'s
+ `event_id`.
+
+The reverse topological power ordering can be found by sorting the
+events using Kahn's algorithm for topological sorting, and at each step
+selecting, among all the candidate vertices, the smallest vertex using
+the above comparison relation.
+
+**Mainline ordering.**
+Let *P* = *P*0 be an `m.room.power_levels` event.
+Starting with *i* = 0, repeatedly fetch *P**i*+1, the
+`m.room.power_levels` event in the `auth_events` of *Pi*.
+Increment *i* and repeat until *Pi* has no `m.room.power_levels`
+event in its `auth_events`.
+The *mainline of P*0 is the list of events
+ [*P*0 , *P*1, ... , *Pn*],
+fetched in this way.
+
+Let *e* = *e0* be another event (possibly another
+`m.room.power_levels` event). We can compute a similar list of events
+ [*e*1, ..., *em*],
+where *e**j*+1 is the `m.room.power_levels` event in the
+`auth_events` of *ej* and where *em* has no
+`m.room.power_levels` event in its `auth_events`. (Note that the event we
+started with, *e0*, is not included in this list. Also note that it
+may be empty, because *e* may not cite an `m.room.power_levels` event in its
+`auth_events` at all.)
+
+Now compare these two lists as follows.
+* Find the smallest index *j* ≥ 1 for which *ej* belongs to the
+ mainline of *P*.
+* If such a *j* exists, then *ej* = *Pi* for some unique
+ index *i* ≥ 0. Otherwise set *i* = ∞, where ∞ is a sentinel value greater
+ than any integer.
+* In both cases, the *mainline position* of *e* is *i*.
+
+Given mainline positions calculated from *P*, the *mainline ordering based on* *P* of a set of events is the ordering,
+from smallest to largest, using the following comparison relation on
+events: for events *x* and *y*, *x* < *y* if
+
+1. the mainline position of *x* is **greater** than
+ the mainline position of *y* (i.e. the auth chain of
+ *x* is based on an earlier event in the mainline than *y*); or
+2. the mainline positions of the events are the same, but *x*'s
+ `origin_server_ts` is *less* than *y*'s `origin_server_ts`; or
+3. the mainline positions of the events are the same and the events have the
+ same `origin_server_ts`, but *x*'s `event_id` is *less* than *y*'s
+ `event_id`.
+
+**Iterative auth checks.**
+The *iterative auth checks algorithm* takes as input an initial room
+state and a sorted list of state events, and constructs a new room state
+by iterating through the event list and applying the state event to the
+room state if the state event is allowed by the [authorization
+rules](/server-server-api#authorization-rules).
+If the state event is not allowed by the authorization rules, then the
+event is ignored. If a `(event_type, state_key)` key that is required
+for checking the authorization rules is not present in the state, then
+the appropriate state event from the event's `auth_events` is used if
+the auth event is not rejected.
+
+#### Algorithm
+
+The *resolution* of a set of states is obtained as follows:
+
+1. Select the set *X* of all *power events* that appear in the *full
+ conflicted set*. For each such power event *P*, enlarge *X* by adding
+ the events in the auth chain of *P* which also belong to the full
+ conflicted set. Sort *X* into a list using the *reverse topological
+ power ordering*.
+2. {{% changed-in v=12 %}} Apply the *iterative auth checks algorithm*,
+ starting from an *empty* state map, to the list of events from the previous
+ step to get a partially resolved state.
+3. Take all remaining events that weren't picked in step 1 and order
+ them by the mainline ordering based on the power level in the
+ partially resolved state obtained in step 2.
+4. Apply the *iterative auth checks algorithm* on the partial resolved
+ state and the list of events from the previous step.
+5. Update the result by replacing any event with the event with the
+ same key from the *unconflicted state map*, if such an event exists,
+ to get the final resolved state.
+
+#### Rejected events
+
+Events that have been rejected due to failing auth based on the state at
+the event (rather than based on their auth chain) are handled as usual
+by the algorithm, unless otherwise specified.
+
+Note that no events rejected due to failure to auth against their auth
+chain should appear in the process, as they should not appear in state
+(the algorithm only uses events that appear in either the state sets or
+in the auth chain of the events in the state sets).
+
+{{% boxes/rationale %}}
+This helps ensure that different servers' view of state is more likely
+to converge, since rejection state of an event may be different. This
+can happen if a third server gives an incorrect version of the state
+when a server joins a room via it (either due to being faulty or
+malicious). Convergence of state is a desirable property as it ensures
+that all users in the room have a (mostly) consistent view of the state
+of the room. If the view of the state on different servers diverges it
+can lead to bifurcation of the room due to e.g. servers disagreeing on
+who is in the room.
+
+Intuitively, using rejected events feels dangerous, however:
+
+1. Servers cannot arbitrarily make up state, since they still need to
+ pass the auth checks based on the event's auth chain (e.g. they
+ can't grant themselves power levels if they didn't have them
+ before).
+2. For a previously rejected event to pass auth there must be a set of
+ state that allows said event. A malicious server could therefore
+ produce a fork where it claims the state is that particular set of
+ state, duplicate the rejected event to point to that fork, and send
+ the event. The duplicated event would then pass the auth checks.
+ Ignoring rejected events would therefore not eliminate any potential
+ attack vectors.
+{{% /boxes/rationale %}}
+
+Rejected auth events are deliberately excluded from use in the iterative
+auth checks, as auth events aren't re-authed (although non-auth events
+are) during the iterative auth checks.
+
+## Unchanged from v11
+
+The following sections have not been modified since v11, but are included for
+completeness.
+
+### Redactions
+
+{{% rver-fragment name="v11-redactions" %}}
+
+### Handling redactions
+
+{{% rver-fragment name="v3-handling-redactions" %}}
+
+### Event IDs
+
+{{% rver-fragment name="v4-event-ids" %}}
+
+### Canonical JSON
+
+{{% rver-fragment name="v6-canonical-json" %}}
+
+### Signing key validity period
+
+{{% rver-fragment name="v5-signing-requirements" %}}
diff --git a/content/rooms/v6.md b/content/rooms/v6.md
index 2f728587..5c061073 100644
--- a/content/rooms/v6.md
+++ b/content/rooms/v6.md
@@ -102,10 +102,14 @@ The rules are as follows:
specified by the [auth events
selection](/server-server-api#auth-events-selection)
algorithm described in the server specification, reject.
+
+ **Note**: This room version requires an `m.room.create` event to be selected.
3. If there are entries which were themselves rejected under the [checks
performed on receipt of a
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
4. If there is no `m.room.create` event among the entries, reject.
+ 5. If any event in `auth_events` has a `room_id` which does not match that of
+ the event being authorised, reject.
3. If the `content` of the `m.room.create` event in the room state has the
property `m.federate` set to `false`, and the `sender` domain of the event
does not match the `sender` domain of the create event, reject.
diff --git a/content/rooms/v7.md b/content/rooms/v7.md
index 34e2a8eb..100e1c74 100644
--- a/content/rooms/v7.md
+++ b/content/rooms/v7.md
@@ -81,10 +81,14 @@ The rules are as follows:
specified by the [auth events
selection](/server-server-api#auth-events-selection)
algorithm described in the server specification, reject.
+
+ **Note**: This room version requires an `m.room.create` event to be selected.
3. If there are entries which were themselves rejected under the [checks
performed on receipt of a
PDU](/server-server-api/#checks-performed-on-receipt-of-a-pdu), reject.
4. If there is no `m.room.create` event among the entries, reject.
+ 5. If any event in `auth_events` has a `room_id` which does not match that of
+ the event being authorised, reject.
3. If the `content` of the `m.room.create` event in the room state has the
property `m.federate` set to `false`, and the `sender` domain of the event
does not match the `sender` domain of the create event, reject.
diff --git a/content/server-server-api.md b/content/server-server-api.md
index 2c52c0e3..e98d2e4c 100644
--- a/content/server-server-api.md
+++ b/content/server-server-api.md
@@ -119,7 +119,7 @@ to send. The process overall is as follows:
server must present a valid certificate for the hostname.
3. If the hostname is not an IP literal, a regular HTTPS request is
- made to `https:///.well-known/matrix/server` (according to
+ made to `https:///.well-known/matrix/server` (according to
[RFC 8615](https://datatracker.ietf.org/doc/html/rfc8615)), expecting
the schema defined later in this section. 30x redirects should be
followed, however redirection loops should be avoided. Responses
@@ -461,9 +461,12 @@ specification](/rooms).
Whenever a server receives an event from a remote server, the receiving
server must ensure that the event:
-1. Is a valid event, otherwise it is dropped. For an event to be valid, it
- must contain a `room_id`, and it must comply with the event format of
- that [room version](/rooms).
+1. {{% changed-in v="1.16" %}} Is a valid event, otherwise it is dropped. For
+ an event to be valid, it must comply with the event format of that [room version](/rooms).
+ For some room versions, a `room_id` may also be required on the event in order
+ to determine the room version to check the event against. See the event format
+ section of the [room version specifications](/rooms) for details on when it
+ is required.
2. Passes signature checks, otherwise it is dropped.
3. Passes hash checks, otherwise it is redacted before being processed
further.
@@ -529,7 +532,8 @@ the sender permission to send the event. The `auth_events` for the
`m.room.create` event in a room is empty; for other events, it should be
the following subset of the room state:
-- The `m.room.create` event.
+- {{% changed-in v="1.16" %}} Depending on the [room version](/rooms), the
+ `m.room.create` event.
- The current `m.room.power_levels` event, if any.
@@ -1050,7 +1054,7 @@ from the user owning the invited third-party identifier.
## Published Room Directory
-To complement the [room directory in the Client-Server API](/client-server-api#published-room-directory),
+To complement the [room directory in the Client-Server API](/client-server-api#published-room-directory),
homeservers need a way to query the published rooms of another server.
This can be done by making a request to the `/publicRooms` endpoint for
the server the room directory should be retrieved for.
diff --git a/data/api/client-server/create_room.yaml b/data/api/client-server/create_room.yaml
index 339217c5..2f9d3449 100644
--- a/data/api/client-server/create_room.yaml
+++ b/data/api/client-server/create_room.yaml
@@ -33,9 +33,23 @@ paths:
2. An `m.room.member` event for the creator to join the room. This is
needed so the remaining events can be sent.
- 3. A default `m.room.power_levels` event, giving the room creator
- (and not other members) permission to send state events. Overridden
- by the `power_level_content_override` parameter.
+ 3. A default `m.room.power_levels` event. Overridden by the
+ `power_level_content_override` parameter.
+
+ In [room versions](/rooms) 1 through 11, the room creator (and not
+ other members) will be given permission to send state events.
+
+ In room versions 12 and later, the room creator is given infinite
+ power level and cannot be specified in the `users` field of
+ `m.room.power_levels`, so is not listed explicitly.
+
+ **Note**: For `trusted_private_chat`, the users specified in the
+ `invite` parameter SHOULD also be appended to `additional_creators`
+ by the server, per the `creation_content` parameter.
+
+ If the room's version is 12 or higher, the power level for sending
+ `m.room.tombstone` events MUST explicitly be higher than `state_default`.
+ For example, set to 150 instead of 100.
4. An `m.room.canonical_alias` event if `room_alias_name` is given.
@@ -61,8 +75,10 @@ paths:
The server will create a `m.room.create` event in the room with the
requesting user as the creator, alongside other keys provided in the
- `creation_content`.
+ `creation_content` or implied by behaviour of `creation_content`.
operationId: createRoom
+ x-changedInMatrixVersion:
+ "1.16": Added server behaviour for how the initial power levels change depending on room version.
security:
- accessTokenQuery: []
- accessTokenBearer: []
@@ -142,11 +158,20 @@ paths:
creation_content:
title: CreationContent
type: object
+ x-changedInMatrixVersion:
+ "1.16": Added server behaviour for how to handle `trusted_private_chat` and invited users.
description: |-
Extra keys, such as `m.federate`, to be added to the content
- of the [`m.room.create`](/client-server-api/#mroomcreate) event. The server will overwrite the following
+ of the [`m.room.create`](/client-server-api/#mroomcreate) event.
+
+ The server will overwrite the following
keys: `creator`, `room_version`. Future versions of the specification
may allow the server to overwrite other keys.
+
+ When using the `trusted_private_chat` preset, the server SHOULD combine
+ `additional_creators` specified here and the `invite` array into the
+ eventual `m.room.create` event's `additional_creators`, deduplicating
+ between the two parameters.
initial_state:
type: array
description: |-
@@ -225,7 +250,7 @@ paths:
}
"400":
description: |-
-
+
The request is invalid. A meaningful `errcode` and description
error text will be returned. Example reasons for rejection include:
diff --git a/data/api/client-server/room_upgrades.yaml b/data/api/client-server/room_upgrades.yaml
index 5109a9b7..7e3ceff9 100644
--- a/data/api/client-server/room_upgrades.yaml
+++ b/data/api/client-server/room_upgrades.yaml
@@ -41,6 +41,23 @@ paths:
new_version:
type: string
description: The new version for the room.
+ additional_creators:
+ type: array
+ items:
+ type: string
+ description: Additional user ID to consider a room creator, if the room version supports it.
+ x-addedInMatrixVersion: "1.16"
+ description: |-
+ When upgrading to a [room version](/rooms) which supports additional creators,
+ the [user IDs](/appendices#user-identifiers) which should be considered room
+ creators in addition to the user performing the upgrade.
+
+ If the room being upgraded has additional creators, they are *not* automatically
+ copied to the new room. The full set of additional creators needs to be set to
+ retain (or add/remove) more room creators.
+
+ When upgrading to a room version which doesn't support additional creators, this
+ field is ignored and has no effect during the upgrade process.
example: {
"new_version": "2"
}
diff --git a/data/api/server-server/definitions/components/depth_v6.yaml b/data/api/server-server/definitions/components/depth_v6.yaml
new file mode 100644
index 00000000..e8ef28c1
--- /dev/null
+++ b/data/api/server-server/definitions/components/depth_v6.yaml
@@ -0,0 +1,25 @@
+# Copyright 2025 The Matrix.org Foundation C.I.C.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+type: object
+description: |-
+ The depth field of PDUs for room version 6 and beyond.
+properties:
+ # v6 enforces Canonical JSON and therefore needs a depth limit change
+ depth:
+ type: integer
+ description: |-
+ The maximum depth of the `prev_events`, plus one. Must be less than the
+ maximum value for an integer (2^53 - 1). If the room's depth is already at
+ the limit, the depth must be set to the limit.
+ example: 12
\ No newline at end of file
diff --git a/data/api/server-server/definitions/components/pdu_base.yaml b/data/api/server-server/definitions/components/pdu_base.yaml
index be275611..0bb3a34c 100644
--- a/data/api/server-server/definitions/components/pdu_base.yaml
+++ b/data/api/server-server/definitions/components/pdu_base.yaml
@@ -14,10 +14,6 @@
type: object
description: Common fields for all PDU versions
properties:
- room_id:
- type: string
- description: Room identifier.
- example: "!abc123:matrix.org"
sender:
type: string
description: The ID of the user sending the event.
@@ -69,7 +65,6 @@ properties:
description: The number of milliseconds that have passed since this message was sent.
example: 4612
required:
- - room_id
- sender
- origin_server_ts
- type
diff --git a/data/api/server-server/definitions/components/room_id_before_v12.yaml b/data/api/server-server/definitions/components/room_id_before_v12.yaml
new file mode 100644
index 00000000..d51adb12
--- /dev/null
+++ b/data/api/server-server/definitions/components/room_id_before_v12.yaml
@@ -0,0 +1,23 @@
+# Copyright 2025 The Matrix.org Foundation C.I.C.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+type: object
+description: |-
+ The room_id field of PDUs for room version 11 and prior.
+properties:
+ room_id:
+ type: string
+ description: Room identifier.
+ example: "!abc123:matrix.org"
+required:
+ - room_id
diff --git a/data/api/server-server/definitions/components/room_id_v12.yaml b/data/api/server-server/definitions/components/room_id_v12.yaml
new file mode 100644
index 00000000..5ad69800
--- /dev/null
+++ b/data/api/server-server/definitions/components/room_id_v12.yaml
@@ -0,0 +1,23 @@
+# Copyright 2025 The Matrix.org Foundation C.I.C.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+type: object
+description: |-
+ The room_id field of PDUs for room version 12 and beyond.
+properties:
+ room_id:
+ type: string
+ description: Room identifier. Omitted from `m.room.create` events.
+ example: "!Nhcu5BS-UMnFX7hBVfVSoXiD7OgH6iRT-xyIuqDnpYQ"
+required:
+ - room_id
diff --git a/data/api/server-server/definitions/pdu_v1.yaml b/data/api/server-server/definitions/pdu_v1.yaml
index d2fb2ef9..7936b629 100644
--- a/data/api/server-server/definitions/pdu_v1.yaml
+++ b/data/api/server-server/definitions/pdu_v1.yaml
@@ -18,6 +18,7 @@ example:
$ref: "../examples/pdu_v1.json"
allOf:
- $ref: "components/pdu_base.yaml"
+ - $ref: "components/room_id_before_v12.yaml"
- type: object
properties:
event_id:
diff --git a/data/api/server-server/definitions/pdu_v11.yaml b/data/api/server-server/definitions/pdu_v11.yaml
index 409b99c6..172d0c1e 100644
--- a/data/api/server-server/definitions/pdu_v11.yaml
+++ b/data/api/server-server/definitions/pdu_v11.yaml
@@ -13,20 +13,12 @@
# limitations under the License.
type: object
title: Persistent Data Unit
-description: A persistent data unit (event) for room version 11 and beyond.
+description: A persistent data unit (event) for room version 11.
example:
$ref: "../examples/pdu_v11.json"
allOf:
# v11 is the v6 event, but without redacts.
- $ref: "components/pdu_base.yaml"
- $ref: "components/auth_events_prev_events_v4.yaml"
- - type: object
- properties:
- # v6 enforces Canonical JSON and therefore needs a depth limit change
- depth:
- type: integer
- description: |-
- The maximum depth of the `prev_events`, plus one. Must be less than the
- maximum value for an integer (2^53 - 1). If the room's depth is already at
- the limit, the depth must be set to the limit.
- example: 12
\ No newline at end of file
+ - $ref: "components/room_id_before_v12.yaml"
+ - $ref: "components/depth_v6.yaml"
diff --git a/data/api/server-server/definitions/pdu_v12.yaml b/data/api/server-server/definitions/pdu_v12.yaml
new file mode 100644
index 00000000..51cbe5a2
--- /dev/null
+++ b/data/api/server-server/definitions/pdu_v12.yaml
@@ -0,0 +1,24 @@
+# Copyright 2025 The Matrix.org Foundation C.I.C.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+type: object
+title: Persistent Data Unit
+description: A persistent data unit (event) for room version 12 and beyond.
+example:
+ $ref: "../examples/pdu_v12.json"
+allOf:
+ # v12 is the v11 event, but with special room ID requirements.
+ - $ref: "components/pdu_base.yaml"
+ - $ref: "components/auth_events_prev_events_v4.yaml"
+ - $ref: "components/depth_v6.yaml"
+ - $ref: "components/room_id_v12.yaml" # this is the v12 change
\ No newline at end of file
diff --git a/data/api/server-server/definitions/pdu_v3.yaml b/data/api/server-server/definitions/pdu_v3.yaml
index ccca717b..44402bea 100644
--- a/data/api/server-server/definitions/pdu_v3.yaml
+++ b/data/api/server-server/definitions/pdu_v3.yaml
@@ -18,6 +18,7 @@ example:
$ref: "../examples/pdu_v3.json"
allOf:
- $ref: "components/pdu_base.yaml"
+ - $ref: "components/room_id_before_v12.yaml"
- type: object
properties:
redacts:
diff --git a/data/api/server-server/definitions/pdu_v4.yaml b/data/api/server-server/definitions/pdu_v4.yaml
index 2edf1b31..1fc8c9b2 100644
--- a/data/api/server-server/definitions/pdu_v4.yaml
+++ b/data/api/server-server/definitions/pdu_v4.yaml
@@ -20,6 +20,7 @@ example:
allOf:
- $ref: "components/pdu_base.yaml"
- $ref: "components/auth_events_prev_events_v4.yaml"
+ - $ref: "components/room_id_before_v12.yaml"
- type: object
properties:
redacts:
diff --git a/data/api/server-server/definitions/pdu_v6.yaml b/data/api/server-server/definitions/pdu_v6.yaml
index 1278a6e3..0ea83b50 100644
--- a/data/api/server-server/definitions/pdu_v6.yaml
+++ b/data/api/server-server/definitions/pdu_v6.yaml
@@ -20,17 +20,11 @@ example:
allOf:
- $ref: "components/pdu_base.yaml"
- $ref: "components/auth_events_prev_events_v4.yaml"
+ - $ref: "components/room_id_before_v12.yaml"
+ - $ref: "components/depth_v6.yaml"
- type: object
properties:
redacts:
type: string
description: For redaction events, the ID of the event being redacted.
example: "$def_456-oldevent"
- # v6 enforces Canonical JSON and therefore needs a depth limit change
- depth:
- type: integer
- description: |-
- The maximum depth of the `prev_events`, plus one. Must be less than the
- maximum value for an integer (2^53 - 1). If the room's depth is already at
- the limit, the depth must be set to the limit.
- example: 12
diff --git a/data/api/server-server/examples/pdu_v12.json b/data/api/server-server/examples/pdu_v12.json
new file mode 100644
index 00000000..9d7120e3
--- /dev/null
+++ b/data/api/server-server/examples/pdu_v12.json
@@ -0,0 +1,9 @@
+{
+ "allOf": [
+ { "$ref": "components/pdu_base.json" },
+ { "$ref": "components/auth_events_prev_events_v4.json" },
+ {
+ "room_id": "!Nhcu5BS-UMnFX7hBVfVSoXiD7OgH6iRT-xyIuqDnpYQ"
+ }
+ ]
+}
diff --git a/data/event-schemas/schema/m.room.create.yaml b/data/event-schemas/schema/m.room.create.yaml
index 19b2bae4..2db5fd57 100644
--- a/data/event-schemas/schema/m.room.create.yaml
+++ b/data/event-schemas/schema/m.room.create.yaml
@@ -33,8 +33,36 @@ properties:
description: The ID of the old room.
event_id:
type: string
- description: The event ID of the last known event in the old room.
- required: [room_id, event_id]
+ deprecated: true
+ x-changedInMatrixVersion:
+ "1.16": |-
+ This field became deprecated and may not be present in all cases. It SHOULD still
+ be populated where possible/practical. Previously, it was required.
+ description: |-
+ The event ID of the last known event in the old room, if known.
+
+ If not set, clients SHOULD search for the `m.room.tombstone` state event to navigate to
+ when directing the user to the old room (potentially after joining the room, if requested
+ by the user).
+ required: [room_id]
+ additional_creators:
+ type: array
+ items:
+ type: string
+ description: Additional user ID to consider a creator of the room, if supported by the room version.
+ x-addedInMatrixVersion: "1.16"
+ description: |-
+ Starting with room version 12, the other user IDs to consider as creators for the room in
+ addition to the `sender` of this event. Each string MUST be a valid [user ID](/appendices#user-identifiers)
+ for the room version.
+
+ When not present or empty, the `sender` of the event is the only creator.
+
+ In room versions 1 through 11, this field serves no purpose and is not validated. Clients
+ SHOULD NOT attempt to parse or understand this field in these room versions.
+
+ **Note**: Because `creator` was removed in room version 11, the field is not used to determine
+ which user(s) are room creators in room version 12 and beyond either.
type: object
state_key:
description: A zero-length string.
diff --git a/data/event-schemas/schema/m.room.power_levels.yaml b/data/event-schemas/schema/m.room.power_levels.yaml
index 858c5274..9c9cf6fd 100644
--- a/data/event-schemas/schema/m.room.power_levels.yaml
+++ b/data/event-schemas/schema/m.room.power_levels.yaml
@@ -44,7 +44,15 @@ properties:
events:
additionalProperties:
type: integer
- description: The level required to send specific event types. This is a mapping from event type to power level required.
+ description: |-
+ The level required to send specific event types. This is a mapping from event type to power level required.
+
+ Though not a default, when the server sends the initial power levels event during [room creation](/client-server-api#creation)
+ in [room versions](/rooms) 12 and higher, the `m.room.tombstone` event MUST be explicitly defined and given
+ a power level higher than `state_default`. For example, power level 150. Clients may override this using the
+ described `power_level_content_override` field.
+ x-changedInMatrixVersion:
+ "1.16": Described `m.room.tombstone` defaults during creation of a room version 12 or higher room.
title: Event power levels
type: object
events_default:
@@ -71,16 +79,28 @@ properties:
"^@":
x-pattern-format: mx-user-id
type: integer
- description: The power levels for specific users. This is a mapping from `user_id` to power level for that user.
+ description: |-
+ The power levels for specific users. This is a mapping from `user_id` to power level for that user.
+
+ **Note**: In [room versions](/rooms) 12 and higher it is not permitted to specify the room creators here.
+ x-changedInMatrixVersion:
+ "1.16": Added a note that room creators cannot be specified here in room versions 12 and higher.
title: User power levels
type: object
users_default:
+ x-changedInMatrixVersion:
+ "1.16": The room creator power level now changes depending on room version.
description: |-
The power level for users in the room whose `user_id` is not mentioned in the `users` key. Defaults to 0 if
unspecified.
- **Note**: When there is no `m.room.power_levels` event in the room, the room creator has
- a power level of 100, and all other users have a power level of 0.
+ **Note**: In [room versions](/rooms) 1 through 11, when there is no `m.room.power_levels`
+ event in the room, the room creator has a power level of 100, and all other users have a
+ power level of 0.
+
+ **Note**: In room versions 12 and higher, room creators have infinite power level regardless
+ of the existence of `m.room.power_levels` in the room. When `m.room.power_levels` is not
+ in the room however, all other users have a power level of 0.
type: integer
notifications:
properties: