Skip to content

Commit d26794e

Browse files
authored
Clarify terminology around aggregations (#1424)
I've done my best to remove the word "bundle", because I feel like it causes more confusion than it provides. Instead I have favoured "aggregated child events" which I think is clearer. Some general clarification around these parts of the spec.
1 parent d6f38f1 commit d26794e

File tree

6 files changed

+69
-52
lines changed

6 files changed

+69
-52
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Clarify the sections of the specification concerning aggregation of child events.

content/client-server-api/_index.md

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,7 +1999,7 @@ This specification describes the following relationship types:
19991999
* [Threads](#threading).
20002000
* [References](#reference-relations)
20012001

2002-
#### Aggregations
2002+
#### Aggregations of child events
20032003

20042004
{{% added-in v="1.3" %}}
20052005

@@ -2013,14 +2013,12 @@ of times that `key` was used by child events.
20132013

20142014
The actual aggregation format depends on the `rel_type`.
20152015

2016-
Aggregations are sometimes automatically included by a server alongside the parent
2017-
event. This is known as a "bundled aggregation" or "bundle" for simplicity. The
2018-
act of doing this is "bundling".
2019-
2020-
When an event is served to the client through the APIs listed below, a `m.relations` property
2021-
is included under `unsigned` if the event has child events which can be aggregated and point
2022-
at it. The `m.relations` property is an object keyed by `rel_type` and value being the type-specific
2023-
aggregated format for that `rel_type`, also known as the bundle.
2016+
When an event is served to the client through the APIs listed below, a
2017+
`m.relations` property is included under `unsigned` if the event has child
2018+
events which can be aggregated and point at it. The `m.relations` property is
2019+
an object keyed by `rel_type` and value being the type-specific aggregated
2020+
format for that `rel_type`. This `m.relations` property is known as a "bundled
2021+
aggregation".
20242022

20252023
For example (unimportant fields not included):
20262024

@@ -2056,10 +2054,10 @@ For example (unimportant fields not included):
20562054
}
20572055
```
20582056

2059-
Note how the `org.example.possible_annotations` bundle is an array compared to the
2060-
`org.example.possible_thread` bundle where the server is summarising the state of
2061-
the relationship in a single object. Both are valid ways to aggregate, and their
2062-
exact types depend on the `rel_type`.
2057+
Note how the `org.example.possible_annotations` aggregation is an array, while in the
2058+
`org.example.possible_thread` aggregation where the server is summarising the state of
2059+
the relationship in a single object. Both are valid ways to aggregate: the format of an
2060+
aggregation depends on the `rel_type`.
20632061

20642062
{{% boxes/warning %}}
20652063
State events do not currently receive bundled aggregations. This is not
@@ -2086,11 +2084,11 @@ such as `/initialSync`.
20862084

20872085
While this functionality allows the client to see what was known to the server at the
20882086
time of handling, the client should continue to aggregate locally if it is aware of
2089-
the relationship type's behaviour. For example, a client might increment a `count`
2090-
on a parent event's bundle if it saw a new child event which referenced that parent.
2087+
the relationship type's behaviour. For example, a client might internally increment a `count`
2088+
in a parent event's aggregation data if it saw a new child event which referenced that parent.
20912089

2092-
The bundle provided by the server only includes child events which were known at the
2093-
time the client would receive the bundle. For example, in a single `/sync` response
2090+
The aggregation provided by the server only includes child events which were known at the
2091+
time the client would receive the aggregation. For example, in a single `/sync` response
20942092
with the parent and multiple child events the child events would have already been
20952093
included on the parent's `m.relations` field. Events received in future syncs would
20962094
need to be aggregated manually by the client.
@@ -2100,7 +2098,7 @@ Events from [ignored users](#ignoring-users) do not appear in the aggregation
21002098
from the server, however clients might still have events from ignored users cached. Like
21012099
with normal events, clients will need to de-aggregate child events sent by ignored users to
21022100
avoid them being considered in counts. Servers must additionally ensure they do not
2103-
consider child events from ignored users when preparing a bundle for the client.
2101+
consider child events from ignored users when preparing an aggregation for the client.
21042102
{{% /boxes/note %}}
21052103

21062104
When a parent event is redacted, the child events which pointed to that parent remain, however
@@ -2109,7 +2107,7 @@ to de-aggregate or disassociate the event once the relationship is lost. Clients
21092107
aggregation or which handle redactions locally should do the same.
21102108

21112109
It is suggested that clients perform local echo on aggregations — for instance, aggregating
2112-
a new child event into a bundle optimistically until the server returns a failure or the client
2110+
a new child event into a parent event optimistically until the server returns a failure or the client
21132111
gives up on sending the event, at which point the event should be de-aggregated and an
21142112
error or similar shown. The client should be cautious to not aggregate an event twice if
21152113
it has already optimistically aggregated the event. Clients are encouraged to take this
@@ -2118,7 +2116,7 @@ likely using the transaction ID as a temporary event ID until a proper event ID
21182116

21192117
{{% boxes/warning %}}
21202118
Due to history visibility restrictions, child events might not be visible to the user
2121-
if they are in a section of history the user cannot see. This means any bundles which would
2119+
if they are in a section of history the user cannot see. This means any aggregations which would
21222120
normally include those events will be lacking them and the client will not be able to
21232121
locally aggregate the events either — relating events of importance (such as votes) should
21242122
take into consideration history visibility.

content/client-server-api/modules/event_replacements.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ replacement event.
192192

193193
Note that there can be multiple events with an `m.replace` relationship to a
194194
given event (for example, if an event is edited multiple times). These should
195-
be [aggregated](#aggregations) by the homeserver.
195+
be [aggregated](#aggregations-of-child-events) by the homeserver.
196196

197197
The aggregation format of `m.replace` relationships gives the **most recent**
198198
replacement event, formatted [as normal](#room-event-format).
@@ -201,8 +201,9 @@ The most recent event is determined by comparing `origin_server_ts`; if two or
201201
more replacement events have identical `origin_server_ts`, the event with the
202202
lexicographically largest `event_id` is treated as more recent.
203203

204-
This aggregation is bundled under the `unsigned` property as `m.relations` for any
205-
event that is the target of an `m.replace` relationship. For example:
204+
As with any other aggregation of child events, the `m.replace` aggregation is
205+
included under the `m.relations` property in `unsigned` for any event that is
206+
the target of an `m.replace` relationship. For example:
206207

207208
```json
208209
{
@@ -288,8 +289,9 @@ subsequent edits, from the visible timeline. In this situation, homeservers
288289
will return an empty `content` for the original event as with any other
289290
redacted event, and as
290291
[above](#server-side-aggregation-of-mreplace-relationships) the replacement
291-
events will not be bundled with the original event. Note that the subsequent edits are
292-
not actually redacted themselves: they simply serve no purpose within the visible timeline.
292+
events will not be included in the aggregation bundled with the original
293+
event. Note that the subsequent edits are not actually redacted themselves:
294+
they simply serve no purpose within the visible timeline.
293295

294296
#### Edits of replies
295297

content/client-server-api/modules/reference_relations.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ messages.
1919

2020
##### Server-side aggregation of `m.reference`
2121

22-
The aggregation format of `m.reference` relations consists of a single `chunk` property,
23-
which lists all the events which `m.reference` the event (the parent). Currently,
24-
only a single `event_id` field is present on the events in the `chunk`.
22+
The [aggregation](#aggregations-of-child-events) format of `m.reference`
23+
relations consists of a single `chunk` property, which lists all the events
24+
which `m.reference` the event (the parent). Currently, only a single `event_id`
25+
field is present on the events in the `chunk`.
2526

26-
An example `m.reference` would be:
27+
For example, given an event with the following `m.reference` relationship:
2728

2829
```json
2930
{
@@ -38,7 +39,7 @@ An example `m.reference` would be:
3839
}
3940
```
4041

41-
The [bundle](#aggregations) under `m.relations` would appear similar to the following:
42+
The aggregation would appear similar to the following:
4243

4344
```json
4445
{

content/client-server-api/modules/threading.md

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ Clients SHOULD render threads differently to regular messages or replies in the
1111
as by providing some context to what is going on in the thread but keeping the full conversation
1212
history behind a disclosure.
1313

14-
Threads are established using a `rel_type` of `m.thread` and reference the *thread root* (the
15-
first event in a thread). It is not possible to create a thread from an event with a `rel_type`,
16-
which includes not being able to nest threads. All conversation in a thread reference the thread
17-
root instead of the most recent message, unlike rich reply chains.
14+
Threads are established using a `rel_type` of `m.thread` and reference the
15+
*thread root* (the first event in a thread). It is not possible to create a
16+
thread from an event which itself is the child of an event relationship (i.e.,
17+
one with an `m.relates_to` property). It is therefore also not possible to nest
18+
threads. All events in a thread reference the thread root instead of the
19+
most recent message, unlike rich reply chains.
1820

19-
As a worked example, the following represents a thread and how it'd be formed:
21+
As a worked example, the following represents a thread and how it would be formed:
2022

2123
```json
2224
{
@@ -128,11 +130,11 @@ clients is used to create a reply within a thread: clients should render the eve
128130

129131
##### Validation of `m.thread` relationships
130132

131-
Servers SHOULD reject client requests which attempt to start a thread off an event with a
132-
`rel_type`. If the client attempts to target an event which already has an `m.thread`,
133-
`m.reference`, or any other `rel_type` then it should receive a HTTP 400 error response
134-
with appropriate error message, as per the [standard error response](#standard-error-response)
135-
structure.
133+
Servers SHOULD reject client requests which attempt to start a thread off an
134+
event with an `m.relates_to` property. If the client attempts to target an event which itself
135+
has an `m.relates_to` property, then it should receive a HTTP 400 error
136+
response with appropriate error message, as per the [standard error
137+
response](#standard-error-response) structure.
136138

137139
{{% boxes/note %}}
138140
A specific error code is not currently available for this case: servers should use `M_UNKNOWN`
@@ -141,12 +143,16 @@ alongside the HTTP 400 status code.
141143

142144
##### Server-side aggregation of `m.thread` relationships
143145

144-
Given threads always reference the thread root, an event can have multiple "child" events which
145-
then form the thread itself. These events should be [aggregated](#aggregations) by the server.
146+
Given threads always reference the thread root, an event can have multiple
147+
"child" events which then form the thread itself. These events should be
148+
[aggregated](#aggregations-of-child-events) by the server.
146149

147150
The aggregation for threads includes some information about the user's participation in the thread,
148151
the approximate number of events in the thread (as known to the server), and the most recent event
149-
in the thread (topologically). This is then bundled into the event as `m.thread`:
152+
in the thread (topologically).
153+
154+
As with any other aggregation of child events, the `m.thread` aggregation is
155+
included under the `m.relations` property in `unsigned` for the thread root. For example:
150156

151157
```json
152158
{
@@ -165,6 +171,11 @@ in the thread (topologically). This is then bundled into the event as `m.thread`
165171
"content": {
166172
"msgtype": "m.text",
167173
"body": "Woo! Threads!"
174+
},
175+
"unsigned": {
176+
"m.relations": {
177+
// ...
178+
}
168179
}
169180
},
170181
"count": 7,
@@ -178,15 +189,17 @@ in the thread (topologically). This is then bundled into the event as `m.thread`
178189
`latest_event` is the most recent event (topologically to the server) in the thread sent by an
179190
un-[ignored user](#ignoring-users).
180191

181-
Note that any bundled aggregations on `latest_event` should also be present. The server should be
182-
careful to avoid loops, though loops are not currently possible due to `m.thread` not being possible
183-
to target an event with a `rel_type` already.
192+
Note that, as in the example above, child events of the `latest_event` should
193+
themselves be aggregated and included under `m.relations` for that event. The
194+
server should be careful to avoid loops, though loops are not currently
195+
possible due to `m.thread` not being permitted to target an event with an
196+
`m.relates_to` property.
184197

185198
`count` is simply the number of events using `m.thread` as a `rel_type` pointing to the target event.
186199
It does not include events sent by [ignored users](#ignoring-users).
187200

188201
`current_user_participated` is `true` when the authenticated user is either:
189-
1. The `sender` of the event receiving the bundle (they sent the thread root).
202+
1. The `sender` of the thread root event.
190203
2. The `sender` of an event which references the thread root with a `rel_type` of `m.thread`.
191204

192205
#### Querying threads in a room

data/api/client-server/threads_list.yaml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@ paths:
3030
"/rooms/{roomId}/threads":
3131
get:
3232
x-addedInMatrixVersion: "1.4"
33-
summary: Retrieve a list of threads in a room, with optional filters.
33+
summary: Fetches a list of the threads in a room.
3434
description: |-
35-
Paginates over the thread roots in a room, ordered by the `latest_event` of each thread root
36-
in its bundle.
35+
This API is used to paginate through the list of the thread roots in a given room.
36+
37+
Optionally, the returned list may be filtered according to whether the requesting
38+
user has participated in the thread.
3739
operationId: getThreadRoots
3840
security:
3941
- accessToken: []
@@ -85,8 +87,8 @@ paths:
8587
chunk:
8688
type: array
8789
description: |-
88-
The thread roots, ordered by the `latest_event` in each event's aggregation bundle. All events
89-
returned include bundled [aggregations](/client-server-api/#aggregations).
90+
The thread roots, ordered by the `latest_event` in each event's aggregated children. All events
91+
returned include bundled [aggregations](/client-server-api/#aggregations-of-child-events).
9092
9193
If the thread root event was sent by an [ignored user](/client-server-api/#ignoring-users), the
9294
event is returned redacted to the caller. This is to simulate the same behaviour of a client doing

0 commit comments

Comments
 (0)