Clarify using parent/child language

This commit is contained in:
Travis Ralston 2022-05-26 21:00:10 -06:00
parent 0d35037f14
commit 532b06b25d
3 changed files with 87 additions and 64 deletions

View file

@ -1849,47 +1849,58 @@ In some cases it is desirable to logically associate one event's contents with
another event's contents. For example, when replying to a message, editing an another event's contents. For example, when replying to a message, editing an
event, or simply looking to add context for an event's purpose. event, or simply looking to add context for an event's purpose.
Relationships are defined as part of an event's `content`. Any event can relate Events are related to each other in a parent/child structure, where any event can
to any other event, however the relationship itself might have restrictions become a parent by simply having a child event point at it. Parent events do not
depending on its `rel_type`. Those restrictions are described by the relationship define their children, instead relying on the children to describe their parent.
type in this specification, if any exist.
The relationship is stored under the `m.relates_to` key of `content`, referencing The relationship between a child and it's parent event is described in the child
the "parent" event. Both the event with `m.relates_to` and the event targeted by event's `content` as `m.relates_to` (defined below). A child event can point at
`m.relates_to` MUST exist in the same room. any other event, including another child event, to build the relationship so long
as both events are in the same room, however additional restrictions might be imposed
by the `rel_type` itself.
{{% boxes/note %}} {{% boxes/note %}}
For simplicity, a single type of relationship is permitted on an event at a time. Child events can point at other child events, forming a chain of events. These chains
A future MSC might change this if a use case arises. can naturally take the shape of a tree if two independent children point at a single
parent event, for example.
{{% /boxes/note %}} {{% /boxes/note %}}
{{% boxes/note %}} To allow the server to aggregate and find child events for a parent, the `m.relates_to`
An event with `m.relates_to` can relate to another event with `m.relates_to`, key of an event MUST be included in the plaintext copy of the event. It cannot be
forming a sort of chain of events. exclusively recorded in the encrypted payload as the server cannot decrypt the event
{{% /boxes/note %}} for processing.
{{% boxes/note %}}
To allow the server to aggregate and find relations on events, the `m.relates_to`
key of an event must be included in the plaintext copy of the event. It cannot
be exclusively recorded in the encrypted payload of an event.
{{% /boxes/note %}}
{{% boxes/warning %}} {{% boxes/warning %}}
If an encrypted event contains an `m.relates_to` in its payload, it should be If an encrypted event contains an `m.relates_to` in its payload, it should be
ignored and instead favour the plaintext `m.relates_to` copy (including when there ignored and instead favour the plaintext `m.relates_to` copy (including when there
is no plaintext copy). is no plaintext copy). This is to ensure the client's behaviour matches the server's
capability to handle relationships.
{{% /boxes/warning %}} {{% /boxes/warning %}}
Improperly formed or structured relationships are simply ignored. For example, the
child and parent events being in different rooms or the relationship missing fields
required by the schema below. The events would appear independent of each other or
optionally with an error message (if rendered/handled by the client exclusively).
`m.relates_to` is described as follows: `m.relates_to` is described as follows:
{{% definition path="api/client-server/definitions/m.relates_to" %}} {{% definition path="api/client-server/definitions/m.relates_to" %}}
#### Relationship types #### Relationship types
{{% boxes/note %}}
While this specification describes an `m.relates_to` object containing a `rel_type`, there
is not currently any relationship type which uses this structure. Replies, described below,
form their relationship outside of the `rel_type` in order to allow other, future, relationship
types to make use of replies in addition to their normal behaviour.
Custom `rel_type`s can, and should, still use the schema described above for relevant
behaviour.
{{% /boxes/note %}}
This specification describes the following relationship types: This specification describes the following relationship types:
* [Rich replies](#rich-replies) (**Note**: uses a different relations structure than * [Rich replies](#rich-replies) (**Note**: does not use `rel_type`).
described here)
{{% boxes/note %}} {{% boxes/note %}}
This specification does not currently define any relation type which requires This specification does not currently define any relation type which requires
@ -1904,17 +1915,18 @@ or aggregation of related events.
{{% added-in v="1.3" %}} {{% added-in v="1.3" %}}
Some events are "aggregated" by the server depending on their relationships. Some child events can be "aggregated" or "bundled" by the server, depending on their
This can allow a set of related events to be summarised. `rel_type`. This can allow a set of child events to be summarised to the client without
the client needing the child events themselves.
For example, a relationship might define an extra `key` field which, when used with An example of this might be that a `rel_type` requires an extra `key` field which, when
the appropriate `rel_type`, would mean that the client receives a total count for appropriately specified, would mean that the client receives a total count for the number
the number of times that `key` was used in a relationship. of times that `key` was used by child events.
The actual aggregation format depends on the relationship type. The actual aggregation format depends on the `rel_type`.
{{% boxes/note %}} {{% boxes/note %}}
This specification does not currently describe any relation types which require This specification does not currently describe any `rel_type` which require
aggregation, however [namespaced](/appendices#identifier-grammar) relationship aggregation, however [namespaced](/appendices#identifier-grammar) relationship
types might have aggregation behaviour. types might have aggregation behaviour.
{{% /boxes/note %}} {{% /boxes/note %}}
@ -1922,9 +1934,10 @@ types might have aggregation behaviour.
When aggregations are summarised on an event, it is known as a "bundled aggregation" When aggregations are summarised on an event, it is known as a "bundled aggregation"
or "bundle" for simplicity. The act of doing this is "bundling". or "bundle" for simplicity. The act of doing this is "bundling".
The bundle for an event is found under the `unsigned` field of the event, when that When an event is served to the client through the APIs listed below, a `m.relations` field
event is served to the client through the APIs listed below. The field, `m.relations`, is included under `unsigned` if the event has child events which point at it. The `m.relations`
is an object with a key of the relationship type and value being the bundle itself. field is an object keyed by `rel_type` and value being the type-specific format for that
`rel_type`, also known as the bundle.
For example (unimportant fields not included): For example (unimportant fields not included):
@ -1963,7 +1976,7 @@ For example (unimportant fields not included):
Note how the `org.example.possible_annotations` bundle is an array compared to the Note how the `org.example.possible_annotations` bundle is an array compared to the
`org.example.possible_thread` bundle where the server is summarising the state of `org.example.possible_thread` bundle where the server is summarising the state of
the relationship in a single object. Both are valid bundles, and their exact types the relationship in a single object. Both are valid bundles, and their exact types
depend on the relationship type. depend on the `rel_type`.
The endpoints where the server *should* include the `m.relations` unsigned field are: The endpoints where the server *should* include the `m.relations` unsigned field are:
@ -1983,7 +1996,7 @@ such as `/initialSync`.
While this functionality allows the client to see what was known to the server at the While this functionality allows the client to see what was known to the server at the
time of handling, the client should continue to aggregate locally if it is aware of time of handling, the client should continue to aggregate locally if it is aware of
the relationship type's behaviour. For example, a client might increment a `count` the relationship type's behaviour. For example, a client might increment a `count`
on a related event's bundle if it saw a new event which referenced that event. on a parent event's bundle if it saw a new child event which referenced that parent.
{{% boxes/warning %}} {{% boxes/warning %}}
The bundle provided by the server only includes events which were known at the time The bundle provided by the server only includes events which were known at the time
@ -1996,27 +2009,26 @@ its own, as the server will not have considered them.
{{% boxes/note %}} {{% boxes/note %}}
Events from [ignored users](#ignoring-users) do not appear in the bundle or aggregation Events from [ignored users](#ignoring-users) do not appear in the bundle or aggregation
from the server, however clients might still have events from ignored users cached. Like from the server, however clients might still have events from ignored users cached. Like
with normal events, clients will need to de-aggregate events sent by ignored users to with normal events, clients will need to de-aggregate child events sent by ignored users to
avoid them being considered in counts. Servers must additionally ensure they do not avoid them being considered in counts. Servers must additionally ensure they do not
consider events from ignored users when preparing a bundle for the client. consider child events from ignored users when preparing a bundle for the client.
{{% /boxes/note %}} {{% /boxes/note %}}
When a parent event is redacted, the events which pointed to that parent remain, however When a parent event is redacted, the child events which pointed to that parent remain, however
when an event which points at a parent is redacted then the relationship is broken. when a child event is redacted then the relationship is broken. Therefore, the server needs
Therefore, the server needs to de-aggregate or disassociate the event once the relationship to de-aggregate or disassociate the event once the relationship is lost. Clients with local
is lost. Clients with local aggregation or which handle redactions locally should do the aggregation or which handle redactions locally should do the same.
same.
It is suggested that clients perform local echo on aggregations. For instance, aggregating It is suggested that clients perform local echo on aggregations. For instance, aggregating
the event into a bundle optimistically until the server returns a failure or the client a new child event into a bundle optimistically until the server returns a failure or the client
gives up on sending the event, at which point the event should be de-aggregated and an gives up on sending the event, at which point the event should be de-aggregated and an
error or similar shown. The client should be cautious to not aggregate an event twice if error or similar shown. The client should be cautious to not aggregate an event twice if
it has already optimistically aggregated the event. Clients are encouraged to take this it has already optimistically aggregated the event. Clients are encouraged to take this
a step further to additionally track related events which target unsent/pending events, a step further to additionally track child events which target unsent/pending events,
likely using the transaction ID as a temporary event ID until a proper event ID is known. likely using the transaction ID as a temporary event ID until a proper event ID is known.
{{% boxes/warning %}} {{% boxes/warning %}}
Due to history visibility restrictions, related events might not be visible to the user Due to history visibility restrictions, child events might not be visible to the user
if they are in a section of history the user cannot see. This can mean inaccurate bundles if they are in a section of history the user cannot see. This can mean inaccurate bundles
for events that are "out of range". for events that are "out of range".
@ -2024,14 +2036,20 @@ Additionally, if the server is missing portions of the room history then it may
able to accurately aggregate the events. able to accurately aggregate the events.
{{% /boxes/warning %}} {{% /boxes/warning %}}
#### API #### Relationships API
To retrieve relations for an event from the server, the client can call the following To retrieve the child events for a parent from the server, the client can call the
endpoint with relevant information. The endpoint does not aggregate the events and is following endpoint with relevant inforamtion. This endpoint does not aggregate the child
instead paginated: clients can perform local aggregation if needed. events and is instead paginated: clients can perform local aggregation if needed. This
allows clients to retrieve child events which do not require aggregation but still make
use of `rel_type`.
This endpoint is particularly useful if the client has lost context on the bundle for This endpoint is particularly useful if the client has lost context on the bundle for
an event and needs to rebuild/verify it. a parent event and needs to rebuild/verify it.
{{% boxes/note %}}
Because replies do not use `rel_type`, they will not be accessible via this API.
{{% /boxes/note %}}
{{% http-api spec="client-server" api="relations" %}} {{% http-api spec="client-server" api="relations" %}}

View file

@ -15,8 +15,8 @@
type: object type: object
title: m.relates_to title: m.relates_to
description: |- description: |-
A description of a valid `m.relates_to` definition on an event. This is contained A description of a valid `m.relates_to` definition on a child event. This is contained
within the event's `content` alongside other fields for that event type. within the event's `content` alongside other fields for the relevant event type.
example: { example: {
# We deliberately "break" the example by including the top-level field so it renders # We deliberately "break" the example by including the top-level field so it renders
# sensibly for readers of the spec. # sensibly for readers of the spec.
@ -35,9 +35,9 @@ properties:
The relationship type determines how clients should perceive the event, and in what The relationship type determines how clients should perceive the event, and in what
context. Some relationship types are processed server-side for "bundling", though not context. Some relationship types are processed server-side for "bundling", though not
all relationships require such behaviour. For example, an `m.thread` relationship type all relationships require such behaviour. For example, an `m.thread` relationship type
denotes that the event is part of a "thread" of messages and should be rendered as might denote that the event is part of a "thread" of messages and should be rendered as
such. such.
event_id: event_id:
type: string type: string
description: The event ID in the same room this event relates to. description: The parent event ID in the same room this event points/relates to.
required: ['rel_type', 'event_id'] required: ['rel_type', 'event_id']

View file

@ -29,16 +29,19 @@ securityDefinitions:
paths: paths:
"/rooms/{roomId}/relations/{eventId}/{relType}/{eventType}": "/rooms/{roomId}/relations/{eventId}/{relType}/{eventType}":
get: get:
summary: Get the related events for a given event, with optional filter. summary: Get the cgukd events for a given parent event, with optional filter.
description: |- description: |-
Retrieve all of the related events for a given event, optionally filtering Retrieve all of the chikd events for a given parent event, optionally filtering
down by relationship type and related event type. down by relationship type and related event type.
Note that while this endpoint indicates `relType` and `eventType` being Note that while this endpoint indicates `relType` and `eventType` being
required, they can be individually omitted to retrieve all matching events. required, they can be individually omitted to retrieve all matching events.
When omitting the path parameters, a trailing slash must not be included When omitting the path parameters, a trailing slash must not be included
(otherwise the search will be for an empty string). (otherwise the search will be for an empty string).
operationId: getEventsRelatingToEvent
When combining the use of `relType` and `eventType`, the server will return
child events which match *both* conditions rather than *either*.
operationId: getChildEventsForParentEvent
security: security:
- accessToken: [] - accessToken: []
parameters: parameters:
@ -59,7 +62,7 @@ paths:
name: relType name: relType
description: |- description: |-
The [relationship type](/client-server-api/#relationship-types) to search The [relationship type](/client-server-api/#relationship-types) to search
for, if any. Exclude to find all events which relate to the supposed parent for, if any. Exclude to find all child events which point to the supposed parent
event with any `rel_type`. event with any `rel_type`.
required: true # we can't say false, annoyingly required: true # we can't say false, annoyingly
x-example: "org.example.my_relation" x-example: "org.example.my_relation"
@ -67,8 +70,8 @@ paths:
type: string type: string
name: eventType name: eventType
description: |- description: |-
The event type of related events to search for, if any. Exclude to find all The event type of child events to search for, if any. Exclude to find all
events of any type which relate to the supposed parent event. child events of any type which point to the supposed parent event.
Note that in encrypted rooms this will typically always be `m.room.encrypted` Note that in encrypted rooms this will typically always be `m.room.encrypted`
regardless of the event type contained within the encrypted payload. regardless of the event type contained within the encrypted payload.
@ -114,8 +117,8 @@ paths:
200: 200:
description: |- description: |-
The paginated events which relate to the supposed parent. If no events are The paginated child events which point to the supposed parent. If no events are
related to the parent, an empty `chunk` is returned. pointing to the parent, an empty `chunk` is returned.
examples: examples:
application/json: { application/json: {
"chunk": [{ "chunk": [{
@ -135,10 +138,10 @@ paths:
type: object type: object
properties: properties:
chunk: chunk:
title: "RelatedEventsChunk" title: "ChildEventsChunk"
type: array type: array
description: |- description: |-
The events which relate to the parent event, after applicable filters. The child events which point to the parent event, after applicable filters.
items: items:
allOf: allOf:
- "$ref": "definitions/client_event.yaml" - "$ref": "definitions/client_event.yaml"
@ -153,7 +156,9 @@ paths:
An opaque string representing a pagination token. The absence of this token An opaque string representing a pagination token. The absence of this token
means there are no prior results to fetch, i.e. this is the first batch. means there are no prior results to fetch, i.e. this is the first batch.
404: 404:
description: The supposed parent event was not found or you do not have permission to read this event. description: |-
The supposed parent event was not found or the user does not have permission to read
this event (it might be contained in history that is not accessible to the user).
examples: examples:
application/json: { application/json: {
"errcode": "M_NOT_FOUND", "errcode": "M_NOT_FOUND",