From 4d6ce1b52cfc7a1e3ef94030944f5ef4d29fba7d Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 7 Jul 2020 15:31:29 -0400 Subject: [PATCH 01/14] initial version of reactions proposal --- proposals/xxxx-reactions.md | 280 ++++++++++++++++++++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 proposals/xxxx-reactions.md diff --git a/proposals/xxxx-reactions.md b/proposals/xxxx-reactions.md new file mode 100644 index 00000000000..092fdf931b2 --- /dev/null +++ b/proposals/xxxx-reactions.md @@ -0,0 +1,280 @@ +# MSCxxxx: Annotations and Reactions + +Users sometimes wish to respond to a message using emojis. When such responses +are grouped visually below the message being reacted to, this provides a +(visually) light-weight way for users to react to messages. + +This proposal is one in a series of proposals that defines a mechanism for +events to relate to each other. Together, these proposals replace +[MSC1849](https://github.com/matrix-org/matrix-doc/pull/1849). + +* [MSCxxxx](https://github.com/matrix-org/matrix-doc/pull/xxxx) defines a + standard shape for indicating events which relate to other events. +* [MSCxxxx](https://github.com/matrix-org/matrix-doc/pull/xxxx) defines APIs to + let the server calculate the aggregations on behalf of the client, and so + bundle the related events with the original event where appropriate. +* This proposal defines how users can edit messages using this mechanism. +* [MSCxxxx](https://github.com/matrix-org/matrix-doc/pull/xxxx) defines how + users can annotate events, such as reacting to events with emoji, using this + mechanism. + +## Proposal + +A new `rel_type` of `m.annotation` is defined for use with the `m.relates_to` +field as defined in +[MSCxxxx](https://github.com/matrix-org/matrix-doc/pull/xxxx). This `rel_type` +is intended primarily for handling emoji reactions, these lets you define an +event which annotates an existing event. The annotations are typically +presented alongside the event in the timeline. When used, the `m.relates_to` +field also contains a `key` that indicates the annotation being applied. For +example, when reacting with emojis, the `key` contains the emoji being used. +When aggregated (as in +[MSCxxxx](https://github.com/matrix-org/matrix-doc/pull/xxxx)), it groups +events together based on their `key` and `type` and returns a `count`. Another +usage of an annotation is e.g. for bots, who could use annotations to report +the success/failure or progress of a command. + +A new message type `m.reaction` is defined to indicate that a user is reacting +to a message. + +For example, an `m.reaction` event which annotates an existing event with a 👍 +looks like: + +```json +{ + "type": "m.reaction", + "content": { + "m.relates_to": { + "rel_type": "m.annotation", + "event_id": "$some_event_id", + "key": "👍" + } + } +} +``` + +When sending emoji reactions, the `key` field should include the colourful +variation-16 when applicable. + +### Push rules + +Since reactions are considered "metadata" that annotate an existing event, they +should not by default trigger notifications. Thus a new default override rule +is to be added that ignores reaction events: + +```json +{ + "rule_id": ".m.rule.reaction", + "default": true, + "enabled": true, + "conditions": [ + { + "kind": "event_match", + "key": "type", + "pattern": "m.reaction" + } + ], + "actions": [ + "dont_notify" + ] +} +``` + +### Server support + +When an annotation event is sent to clients via `/sync`, a new field +`annotation_count` is provided in the `unsigned` field of the event, calculated +by the server to provide the current absolute count of the given annotation key +as of that point of the event, to avoid the client having to accurately track +the absolute value itself. + + XXX: is this implemented in Synapse yet? + +For instance, an incremental sync might include the following: + +```json +{ + "type": "m.reaction", + "sender": "@matthew:matrix.org", + "content": { + "m.relates_to": { + "rel_type": "m.annotation", + "event_id": "$some_event_id", + "key": "👍" + } + }, + "unsigned": { + "annotation_count": 1234, + } +} +``` + +...to indicate that Matthew just thumbsupped a given event, bringing the current +total to 1234 thumbsups. + +#### Bundled relations + +When annotations are bundled according to the [Bundled relations section of +MSCxxxx](https://github.com/matrix-org/matrix-doc/pulls/xxxx), the aggregated +value in the bundle provides the `type` of the relation event, the aggregation +`key`, the `origin_server_ts` of the first reaction to that event, and the +`count` of the number of annotations of that `type` and `key` which reference +that event. + +For instance, the below example shows an event with five bundled relations: +three thumbsup reaction annotations, and two thumbsdown reaction annotations. + +```json +{ + ..., + "unsigned": { + "m.relations": { + "m.annotation": { + "chunk": [ + { + "type": "m.reaction", + "key": "👍", + "origin_server_ts": 1562763768320, + "count": 3 + }, + { + "type": "m.reaction", + "key": "👎", + "origin_server_ts": 1562763768320, + "count": 2 + } + ], + "limited": false, + "count": 2 + } + } + } +} +``` + + XXX: is the example correct? + +### Redactions + +When a message using a `rel_type` of `m.annotation` is redacted, this removes +the annotation from the message. + +## Edge Cases + +How do you stop people reacting more than once with the same key? + 1. You error with 400 (M_INVALID_REL_TYPE) if they try to react twice with the same key, locally + 2. You flatten duplicate reactions received over federation from the same user + when calculating your local aggregations + 3. You don't pass duplicate reactions received over federation to your local user. + 4. XXX: does synapse do 2 & 3 yet? + +Can you [edit](https://github.com/matrix-org-matrix-doc/pull/xxxx) a reaction? + * It feels reasonable to say "if you want to edit a reaction, redact it and resend". + `rel_type` is immutable, much like `type`. + +Can you react to a reaction? + * Yes, at the protocol level. But you shouldn't expect clients to do anything + useful with it. + +What happens when you react to an edit? + * You should be able to, but the reaction should be attributed to the edit (or + its contents) rather than the message as a whole. + * Edits gather their own reactions, and the clients should display + the reactions on the most recent edit. + * This provides a social pressure to get your edits in quickly before there + are many reactions, otherwise the reactions will get lost. + * And it avoids us randomly aggregating reactions to potentially very + different contents of messages. + +Which message types are reactable? + * Any. But perhaps we should provide some UI best practice guidelines: + * `m.room.message` must be reactable + * `m.sticker` too + * ...but anything else may not be rendered. + +## Alternatives + +### Extended annotation use case + +In future it might be useful to be able to annotate events with more +information, some examples include: + + * Annotate commit/PR notification messages with their associated CI state, e.g. + pending/passed/failed. + * If a user issues a command to a bot, e.g. `!deploy-site` the bot could + annotate that event with current state, like "acknowledged", + "redeploying...", "success", "failed", etc. + * Other use cases...? + +However, this doesn't really work with the proposed grouping, as the aggregation +key wouldn't contain the right information needed to display it (unlike for +reactions). + +One way to potentially support this is to include the events (or a subset of the +event) when grouping, so that clients have enough information to render them. +However this dramatically inceases the size of the parent event if we bundle the +full events inside, even if limit the number we bundle in. To reduce the +overhead the annotation event could include a `m.result` field which gets +included. + +This would look something like the following, where the annotation is: + +```json +{ + "type": "m.bot_command_response", + "content": { + "m.result": { + "state": "success", + }, + "m.relates_to": { + "type": "m.annotation", + "key": "" + } + } +} +``` + +and gets bundled into an event like: + +```json +{ + "unsigned": { + "m.relations": { + "m.annotation": [ + { + "type": "m.bot_command_response", + "key": "", + "count": 1, + "chunk": [ + { + "m.result": { + "state": "success", + }, + } + ], + "limited": false, + } + ] + } + } +} +``` + +This is something that could be added later on. A few issues with this are: + + * How does this work with E2EE? How do we encrypt the `m.result`? + * We would end up including old annotations that had been superceded, should + these be done via edits instead? + +## Security considerations + +If using reactions for upvoting/downvoting purposes we would almost certainly want to anonymise the +reactor, at least from other users if not server admins, to avoid retribution problems. +This gives an unfair advantage to people who run their own servers however and +can cheat and deanonymise (and publish) reactor details. In practice, reactions may +not be best used for upvote/downvote as at the unbundled level they are intrinsically +private data. + +Or in a MSC1228 world... we could let users join the room under an anonymous +persona from a big public server in order to vote? However, such anonymous personae +would lack any reputation data. From 8762524cb49d0b2f5fcb8e90c7e168c46a3479fa Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Tue, 7 Jul 2020 16:31:01 -0400 Subject: [PATCH 02/14] fix MSC numbers --- .../{xxxx-reactions.md => 2677-reactions.md} | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) rename proposals/{xxxx-reactions.md => 2677-reactions.md} (89%) diff --git a/proposals/xxxx-reactions.md b/proposals/2677-reactions.md similarity index 89% rename from proposals/xxxx-reactions.md rename to proposals/2677-reactions.md index 092fdf931b2..f9bd6636f3d 100644 --- a/proposals/xxxx-reactions.md +++ b/proposals/2677-reactions.md @@ -1,4 +1,4 @@ -# MSCxxxx: Annotations and Reactions +# MSC2677: Annotations and Reactions Users sometimes wish to respond to a message using emojis. When such responses are grouped visually below the message being reacted to, this provides a @@ -8,28 +8,28 @@ This proposal is one in a series of proposals that defines a mechanism for events to relate to each other. Together, these proposals replace [MSC1849](https://github.com/matrix-org/matrix-doc/pull/1849). -* [MSCxxxx](https://github.com/matrix-org/matrix-doc/pull/xxxx) defines a +* [MSC2674](https://github.com/matrix-org/matrix-doc/pull/2674) defines a standard shape for indicating events which relate to other events. -* [MSCxxxx](https://github.com/matrix-org/matrix-doc/pull/xxxx) defines APIs to +* [MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675) defines APIs to let the server calculate the aggregations on behalf of the client, and so bundle the related events with the original event where appropriate. -* This proposal defines how users can edit messages using this mechanism. -* [MSCxxxx](https://github.com/matrix-org/matrix-doc/pull/xxxx) defines how - users can annotate events, such as reacting to events with emoji, using this - mechanism. +* [MSC2676](https://github.com/matrix-org/matrix-doc/pull/2676) defines how + users can edit messages using this mechanism. +* This proposal defines how users can annotate events, such as reacting to + events with emoji, using this mechanism. ## Proposal A new `rel_type` of `m.annotation` is defined for use with the `m.relates_to` field as defined in -[MSCxxxx](https://github.com/matrix-org/matrix-doc/pull/xxxx). This `rel_type` +[MSC2674](https://github.com/matrix-org/matrix-doc/pull/2674). This `rel_type` is intended primarily for handling emoji reactions, these lets you define an event which annotates an existing event. The annotations are typically presented alongside the event in the timeline. When used, the `m.relates_to` field also contains a `key` that indicates the annotation being applied. For example, when reacting with emojis, the `key` contains the emoji being used. When aggregated (as in -[MSCxxxx](https://github.com/matrix-org/matrix-doc/pull/xxxx)), it groups +[MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675)), it groups events together based on their `key` and `type` and returns a `count`. Another usage of an annotation is e.g. for bots, who could use annotations to report the success/failure or progress of a command. @@ -115,11 +115,11 @@ total to 1234 thumbsups. #### Bundled relations When annotations are bundled according to the [Bundled relations section of -MSCxxxx](https://github.com/matrix-org/matrix-doc/pulls/xxxx), the aggregated -value in the bundle provides the `type` of the relation event, the aggregation -`key`, the `origin_server_ts` of the first reaction to that event, and the -`count` of the number of annotations of that `type` and `key` which reference -that event. +MSC2675](https://github.com/uhoreg/matrix-doc/blob/aggregations-helpers/proposals/2675-aggregations-server.md#bundled-relations), +the aggregated value in the bundle provides the `type` of the relation event, +the aggregation `key`, the `origin_server_ts` of the first reaction to that +event, and the `count` of the number of annotations of that `type` and `key` +which reference that event. For instance, the below example shows an event with five bundled relations: three thumbsup reaction annotations, and two thumbsdown reaction annotations. @@ -168,7 +168,7 @@ How do you stop people reacting more than once with the same key? 3. You don't pass duplicate reactions received over federation to your local user. 4. XXX: does synapse do 2 & 3 yet? -Can you [edit](https://github.com/matrix-org-matrix-doc/pull/xxxx) a reaction? +Can you [edit](https://github.com/matrix-org-matrix-doc/pull/2676) a reaction? * It feels reasonable to say "if you want to edit a reaction, redact it and resend". `rel_type` is immutable, much like `type`. From 2e7563965bf242931364b7e4a2be22897e1aff1d Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Wed, 2 Jun 2021 17:49:54 -0400 Subject: [PATCH 03/14] add security consideration --- proposals/2677-reactions.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/proposals/2677-reactions.md b/proposals/2677-reactions.md index f9bd6636f3d..f6c4b39f343 100644 --- a/proposals/2677-reactions.md +++ b/proposals/2677-reactions.md @@ -268,6 +268,9 @@ This is something that could be added later on. A few issues with this are: ## Security considerations +Clients should render reactions that have a long `key` field in a sensible +manner. For example, clients can elide overly-long reactions. + If using reactions for upvoting/downvoting purposes we would almost certainly want to anonymise the reactor, at least from other users if not server admins, to avoid retribution problems. This gives an unfair advantage to people who run their own servers however and From 5852b28651e0a8c07e1706410374dde6f494c929 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 8 Jul 2021 10:37:27 +0200 Subject: [PATCH 04/14] remove event type from aggregation grouping criteria because of e2ee --- proposals/2677-reactions.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/proposals/2677-reactions.md b/proposals/2677-reactions.md index f6c4b39f343..f957b2a6061 100644 --- a/proposals/2677-reactions.md +++ b/proposals/2677-reactions.md @@ -30,11 +30,15 @@ field also contains a `key` that indicates the annotation being applied. For example, when reacting with emojis, the `key` contains the emoji being used. When aggregated (as in [MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675)), it groups -events together based on their `key` and `type` and returns a `count`. Another +events together based on their `key` and returns a `count`. Another usage of an annotation is e.g. for bots, who could use annotations to report the success/failure or progress of a command. -A new message type `m.reaction` is defined to indicate that a user is reacting +The `type` of the annotating event is not taken into account when aggregating +as that would prevent accurate server aggregation in end-to-end encrypted rooms. + +Given this, annotations of any event type should be accepted as a valid reaction, +but a new message type `m.reaction` is suggested to indicate that a user is reacting to a message. For example, an `m.reaction` event which annotates an existing event with a 👍 @@ -132,13 +136,11 @@ three thumbsup reaction annotations, and two thumbsdown reaction annotations. "m.annotation": { "chunk": [ { - "type": "m.reaction", "key": "👍", "origin_server_ts": 1562763768320, "count": 3 }, { - "type": "m.reaction", "key": "👎", "origin_server_ts": 1562763768320, "count": 2 From 121ca149cb397604c6da8a0101b34357109b75d7 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Tue, 14 Feb 2023 17:02:04 +0000 Subject: [PATCH 05/14] Apply suggestions from code review Co-authored-by: David Baker --- proposals/2677-reactions.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/proposals/2677-reactions.md b/proposals/2677-reactions.md index f957b2a6061..e278cdf4a85 100644 --- a/proposals/2677-reactions.md +++ b/proposals/2677-reactions.md @@ -23,7 +23,7 @@ events to relate to each other. Together, these proposals replace A new `rel_type` of `m.annotation` is defined for use with the `m.relates_to` field as defined in [MSC2674](https://github.com/matrix-org/matrix-doc/pull/2674). This `rel_type` -is intended primarily for handling emoji reactions, these lets you define an +is intended primarily for handling emoji reactions, these let you define an event which annotates an existing event. The annotations are typically presented alongside the event in the timeline. When used, the `m.relates_to` field also contains a `key` that indicates the annotation being applied. For @@ -78,9 +78,7 @@ is to be added that ignores reaction events: "pattern": "m.reaction" } ], - "actions": [ - "dont_notify" - ] + "actions": [] } ``` From a0ed8e7eeb7e532ef57d1c32f6ab7b8eb7dd502f Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 14 Feb 2023 17:26:33 +0000 Subject: [PATCH 06/14] Update intro and add background --- proposals/2677-reactions.md | 40 +++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/proposals/2677-reactions.md b/proposals/2677-reactions.md index e278cdf4a85..49d38d88512 100644 --- a/proposals/2677-reactions.md +++ b/proposals/2677-reactions.md @@ -4,19 +4,33 @@ Users sometimes wish to respond to a message using emojis. When such responses are grouped visually below the message being reacted to, this provides a (visually) light-weight way for users to react to messages. -This proposal is one in a series of proposals that defines a mechanism for -events to relate to each other. Together, these proposals replace -[MSC1849](https://github.com/matrix-org/matrix-doc/pull/1849). - -* [MSC2674](https://github.com/matrix-org/matrix-doc/pull/2674) defines a - standard shape for indicating events which relate to other events. -* [MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675) defines APIs to - let the server calculate the aggregations on behalf of the client, and so - bundle the related events with the original event where appropriate. -* [MSC2676](https://github.com/matrix-org/matrix-doc/pull/2676) defines how - users can edit messages using this mechanism. -* This proposal defines how users can annotate events, such as reacting to - events with emoji, using this mechanism. +This proposal was originally part of [MSC1849](https://github.com/matrix-org/matrix-doc/pull/1849). + +## Background + +As with [message +edits](https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/2676-message-editing.md#background), +support for reactions were landed in the Element clients and Synapse in May +2019, following the proposals of +[MSC1849](https://github.com/matrix-org/matrix-doc/pull/1849) and then +presented as being "production-ready", despite them not yet having been adopted +into the Matrix specification. + +Again as with edits, the current situation is therefore that client or server +implementations hoping to interact with Element users must simply follow the +examples of that implementation. + +To rectify the situation, this MSC therefore seeks primarily to formalise the +status quo. Although there is plenty of scope for improvement, we consider +that better done in *future* MSCs, based on a shared understanding of the +*current* implementation. + +In short, this MSC prefers fidelity to the current implementations over +elegance of design. + +On the positive side: this MSC is the last part of the former MSC1849 to be +formalised, and is by far the most significant feature implemented by the +Element clients which has yet to be specified. ## Proposal From 657a7466faf1d99bf28f4b2293c116fdea16bb9e Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 14 Feb 2023 18:28:36 +0000 Subject: [PATCH 07/14] Corrections and clarifications to the main text In particular: we *do* aggregate based on event `type` as well as key. --- proposals/2677-reactions.md | 140 ++++++++++++++++++------------------ 1 file changed, 71 insertions(+), 69 deletions(-) diff --git a/proposals/2677-reactions.md b/proposals/2677-reactions.md index 49d38d88512..4602f32cc77 100644 --- a/proposals/2677-reactions.md +++ b/proposals/2677-reactions.md @@ -34,26 +34,43 @@ Element clients which has yet to be specified. ## Proposal -A new `rel_type` of `m.annotation` is defined for use with the `m.relates_to` -field as defined in -[MSC2674](https://github.com/matrix-org/matrix-doc/pull/2674). This `rel_type` -is intended primarily for handling emoji reactions, these let you define an -event which annotates an existing event. The annotations are typically -presented alongside the event in the timeline. When used, the `m.relates_to` -field also contains a `key` that indicates the annotation being applied. For -example, when reacting with emojis, the `key` contains the emoji being used. -When aggregated (as in -[MSC2675](https://github.com/matrix-org/matrix-doc/pull/2675)), it groups -events together based on their `key` and returns a `count`. Another -usage of an annotation is e.g. for bots, who could use annotations to report -the success/failure or progress of a command. - -The `type` of the annotating event is not taken into account when aggregating -as that would prevent accurate server aggregation in end-to-end encrypted rooms. - -Given this, annotations of any event type should be accepted as a valid reaction, -but a new message type `m.reaction` is suggested to indicate that a user is reacting -to a message. +### `m.annotation` event relationship type + +A new [event relationship type](https://spec.matrix.org/v1.6/client-server-api/#relationship-types) +with a `rel_type` of `m.annotation`. + +This relationship type is intended primarily for handling emoji reactions, allowing clients to +send an event which annotates an existing event. + +Another potential usage of annotations is for bots, which could use them to +report the success/failure or progress of a command. + +The annotations are typically presented alongside the event in the timeline. + +Along with the normal properties `event_id` and `rel_type`, the +[`m.relates_to`](https://spec.matrix.org/v1.6/client-server-api/#definition-mrelates_to) +property should contains a `key` that indicates the annotation being +applied. For example, when reacting with emojis, the `key` contains the emoji +being used. + +An event annotating another with the thumbs-up emoji would therefore have the following `m.relates_to` propperty: + +```json +"m.relates_to": { + "rel_type": "m.annotation", + "event_id": "$some_event_id", + "key": "👍" +} +``` + +When sending emoji reactions, the `key` property should include the colourful +variation-16 when applicable. + +### `m.reaction` event type + +A new message type `m.reaction` is proposed to indicate that a user is reacting +to a message. No `content` properties are defined for this event type: it serves +only to hold a relationship to another event. For example, an `m.reaction` event which annotates an existing event with a 👍 looks like: @@ -71,13 +88,11 @@ looks like: } ``` -When sending emoji reactions, the `key` field should include the colourful -variation-16 when applicable. - ### Push rules Since reactions are considered "metadata" that annotate an existing event, they -should not by default trigger notifications. Thus a new default override rule +should not by default trigger notifications. Thus a new [default override +rule](https://spec.matrix.org/v1.6/client-server-api/#default-override-rules) is to be added that ignores reaction events: ```json @@ -96,77 +111,64 @@ is to be added that ignores reaction events: } ``` -### Server support - -When an annotation event is sent to clients via `/sync`, a new field -`annotation_count` is provided in the `unsigned` field of the event, calculated -by the server to provide the current absolute count of the given annotation key -as of that point of the event, to avoid the client having to accurately track -the absolute value itself. - - XXX: is this implemented in Synapse yet? - -For instance, an incremental sync might include the following: +The rule is added between `.m.rule.tombstone` and `.m.rule.room.server_acl`. -```json -{ - "type": "m.reaction", - "sender": "@matthew:matrix.org", - "content": { - "m.relates_to": { - "rel_type": "m.annotation", - "event_id": "$some_event_id", - "key": "👍" - } - }, - "unsigned": { - "annotation_count": 1234, - } -} -``` +(Synapse implementation: [base_rules.rs](https://github.com/matrix-org/synapse/blob/157c571f3e9d3d09cd763405b6a9eb967f2807e7/rust/src/push/base_rules.rs#L216-L229)) -...to indicate that Matthew just thumbsupped a given event, bringing the current -total to 1234 thumbsups. +### Server support -#### Bundled relations +#### Server-side aggregation of `m.annotation` relationships -When annotations are bundled according to the [Bundled relations section of -MSC2675](https://github.com/uhoreg/matrix-doc/blob/aggregations-helpers/proposals/2675-aggregations-server.md#bundled-relations), -the aggregated value in the bundle provides the `type` of the relation event, -the aggregation `key`, the `origin_server_ts` of the first reaction to that -event, and the `count` of the number of annotations of that `type` and `key` -which reference that event. +Homeservers should +[aggregate](https://spec.matrix.org/v1.6/client-server-api/#aggregations) +events with an `m.annotation` relationship to a given event. -For instance, the below example shows an event with five bundled relations: -three thumbsup reaction annotations, and two thumbsdown reaction annotations. +When aggregating `m.annotation` events, homeservers should group events +together based on their event `type` and `key`, and count the number of each +distinct `type`/`key`. An example aggregation is as follows: ```json { - ..., + "event_id": "$original_event_id", + // irrelevant fields not shown "unsigned": { "m.relations": { "m.annotation": { "chunk": [ { + "type": "m.reaction", "key": "👍", - "origin_server_ts": 1562763768320, "count": 3 }, { + "type": "example.com.test", + "key": "👍", + "count": 1 + }, + { + "type": "m.reaction", "key": "👎", - "origin_server_ts": 1562763768320, "count": 2 } - ], - "limited": false, - "count": 2 + ] } } } } ``` - XXX: is the example correct? +This event has received three thumbsup reactions, two thumbsdown reactions, and +a thumbsup annotation with an event type of `example.com.test` (which will be +ignored by clients which don't understand the `example.com.test` event type). + +As the example shows, the aggregation format has a `chunk` property at the top +level. (This is indended to allow pagination of reactions in a future +extension, though that is not currently specified.) Each entry in the `chunk` is +an object with properties: + + * `type`: the event `type` of the aggregated events. + * `key`: the `key` from the `m.relates_to` properties of the aggregated events. + * `count`: the number of unredacted events with this event `type` and annotation `key`. ### Redactions From dad2b07dc7b720d743624b03515b366615640d9f Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 14 Feb 2023 19:02:10 +0000 Subject: [PATCH 08/14] Clarify counting rules and interactions with edits --- proposals/2677-reactions.md | 70 ++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/proposals/2677-reactions.md b/proposals/2677-reactions.md index 4602f32cc77..1189b929d42 100644 --- a/proposals/2677-reactions.md +++ b/proposals/2677-reactions.md @@ -45,8 +45,6 @@ send an event which annotates an existing event. Another potential usage of annotations is for bots, which could use them to report the success/failure or progress of a command. -The annotations are typically presented alongside the event in the timeline. - Along with the normal properties `event_id` and `rel_type`, the [`m.relates_to`](https://spec.matrix.org/v1.6/client-server-api/#definition-mrelates_to) property should contains a `key` that indicates the annotation being @@ -88,6 +86,50 @@ looks like: } ``` +### Interation with edited events + +It is not considered valid to send an annotation for a [replacement +event](https://spec.matrix.org/v1.6/client-server-api/#event-replacements) +(i.e., a message edit event): any reactions should refer to the original event. + +As an aside, note that it is not possible to edit a reaction, since replacement +events do not change `m.relates_to` (see [Applying +`m.new_content`](https://spec.matrix.org/v1.6/client-server-api/#applying-mnew_content)), +and there is no other meaningful content within `m.reaction`. If a user wishes +to change their reaction, the original reaction should be redacted and a new +one sent in its place. + +### Counting annotations + +The intention of annotations is that they are counted up, rather than being displayed individually. + +Clients must keep count of the number of annotations with a given event `type` +and annotation `key` they observe for each event; these counts are typically +presented alongside the event in the timeline. + +Servers must perform a similar operation to calculate the relationship +aggregation (see +[below](#server-side-aggregation-of-mannotation-relationships)). + +When performing this count: + + * Servers must count each event `type` and annotation `key` + separately. Clients will normally choose to do so to though this is an + implementation decision. + + * Events sent by [ignored users](https://spec.matrix.org/v1.6/client-server-api/#ignoring-users) + should be excluded from the count. + + * Multiple identical annotations (i.e., with the same event `type` and + annotation `key`) from the same user (i.e., events with the same `sender`) should + be treated as a single annotation. + + * It is not considered valid to annotate an event which itself has an + `m.relates_to` with `rel_type: m.annotation` or `rel_type: + m.replace`. Implementations should ignore any such annotation events. + + * When an annotation is redacted, it is removed from the count. + ### Push rules Since reactions are considered "metadata" that annotate an existing event, they @@ -170,10 +212,8 @@ an object with properties: * `key`: the `key` from the `m.relates_to` properties of the aggregated events. * `count`: the number of unredacted events with this event `type` and annotation `key`. -### Redactions - -When a message using a `rel_type` of `m.annotation` is redacted, this removes -the annotation from the message. +When evaluating `count`, servers should respect the guidelines above about +[counting annotations](#counting-annotations). ## Edge Cases @@ -184,24 +224,6 @@ How do you stop people reacting more than once with the same key? 3. You don't pass duplicate reactions received over federation to your local user. 4. XXX: does synapse do 2 & 3 yet? -Can you [edit](https://github.com/matrix-org-matrix-doc/pull/2676) a reaction? - * It feels reasonable to say "if you want to edit a reaction, redact it and resend". - `rel_type` is immutable, much like `type`. - -Can you react to a reaction? - * Yes, at the protocol level. But you shouldn't expect clients to do anything - useful with it. - -What happens when you react to an edit? - * You should be able to, but the reaction should be attributed to the edit (or - its contents) rather than the message as a whole. - * Edits gather their own reactions, and the clients should display - the reactions on the most recent edit. - * This provides a social pressure to get your edits in quickly before there - are many reactions, otherwise the reactions will get lost. - * And it avoids us randomly aggregating reactions to potentially very - different contents of messages. - Which message types are reactable? * Any. But perhaps we should provide some UI best practice guidelines: * `m.room.message` must be reactable From fba3948b85b14de2b9bdab9102f087b6bd6c41fd Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 14 Feb 2023 20:47:29 +0000 Subject: [PATCH 09/14] Error code for deduplicating annotations --- proposals/2677-reactions.md | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/proposals/2677-reactions.md b/proposals/2677-reactions.md index 1189b929d42..b4dc9fbdff6 100644 --- a/proposals/2677-reactions.md +++ b/proposals/2677-reactions.md @@ -159,6 +159,19 @@ The rule is added between `.m.rule.tombstone` and `.m.rule.room.server_acl`. ### Server support +#### Avoiding duplicate annotations + +Homeservers should prevent users from sending a second annotation for a given +event with identical event `type` and annotation `key` (unless the first event +has been redacted). + +Attempts to send such an annotation should be rejected with a 400 error and an +error code of `M_DUPLICATE_ANNOTATION`. + +Note that this does not guarantee that duplicate annotations will not arrive +over federation. Clients and servers are responsible for deduplicating received +annotations when [counting annotations](#counting-annotations). + #### Server-side aggregation of `m.annotation` relationships Homeservers should @@ -217,13 +230,6 @@ When evaluating `count`, servers should respect the guidelines above about ## Edge Cases -How do you stop people reacting more than once with the same key? - 1. You error with 400 (M_INVALID_REL_TYPE) if they try to react twice with the same key, locally - 2. You flatten duplicate reactions received over federation from the same user - when calculating your local aggregations - 3. You don't pass duplicate reactions received over federation to your local user. - 4. XXX: does synapse do 2 & 3 yet? - Which message types are reactable? * Any. But perhaps we should provide some UI best practice guidelines: * `m.room.message` must be reactable From 4031ad4252b8ed36135d3bb83355d85a0aedc545 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 14 Feb 2023 21:05:36 +0000 Subject: [PATCH 10/14] Clarify eligible target events --- proposals/2677-reactions.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/proposals/2677-reactions.md b/proposals/2677-reactions.md index b4dc9fbdff6..e935916af08 100644 --- a/proposals/2677-reactions.md +++ b/proposals/2677-reactions.md @@ -64,6 +64,11 @@ An event annotating another with the thumbs-up emoji would therefore have the fo When sending emoji reactions, the `key` property should include the colourful variation-16 when applicable. +Any `type` of event is eligible for an annotation, though note that, since +state events do not currently receive bundled aggregations (see +[aggregations](https://spec.matrix.org/v1.6/client-server-api/#aggregations)), +the results of annotating a state event may be inconsistent. + ### `m.reaction` event type A new message type `m.reaction` is proposed to indicate that a user is reacting @@ -90,7 +95,9 @@ looks like: It is not considered valid to send an annotation for a [replacement event](https://spec.matrix.org/v1.6/client-server-api/#event-replacements) -(i.e., a message edit event): any reactions should refer to the original event. +(i.e., a message edit event): any reactions should refer to the original +event. Annotations of replacement events will be ignored according to the rules +for [counting annotations](#counting-annotations). As an aside, note that it is not possible to edit a reaction, since replacement events do not change `m.relates_to` (see [Applying @@ -117,7 +124,7 @@ When performing this count: separately. Clients will normally choose to do so to though this is an implementation decision. - * Events sent by [ignored users](https://spec.matrix.org/v1.6/client-server-api/#ignoring-users) + * Annotation events sent by [ignored users](https://spec.matrix.org/v1.6/client-server-api/#ignoring-users) should be excluded from the count. * Multiple identical annotations (i.e., with the same event `type` and @@ -228,14 +235,6 @@ an object with properties: When evaluating `count`, servers should respect the guidelines above about [counting annotations](#counting-annotations). -## Edge Cases - -Which message types are reactable? - * Any. But perhaps we should provide some UI best practice guidelines: - * `m.room.message` must be reactable - * `m.sticker` too - * ...but anything else may not be rendered. - ## Alternatives ### Extended annotation use case From 0d146ca1ecbd3eb87a5ca447444f427706c7c768 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 14 Feb 2023 21:24:53 +0000 Subject: [PATCH 11/14] Notes on encryption --- proposals/2677-reactions.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/proposals/2677-reactions.md b/proposals/2677-reactions.md index e935916af08..3ab12f9f9d6 100644 --- a/proposals/2677-reactions.md +++ b/proposals/2677-reactions.md @@ -91,6 +91,9 @@ looks like: } ``` +Since they contain no `content` other than `m.relates_to`, `m.reaction` events +are normally not encrypted, as there would be no benefit in doing so. + ### Interation with edited events It is not considered valid to send an annotation for a [replacement @@ -237,6 +240,11 @@ When evaluating `count`, servers should respect the guidelines above about ## Alternatives +### Encrypted reactions + +[matrix-spec#660](https://github.com/matrix-org/matrix-spec/issues/660) +discusses the possibility of encrypting message relationships. + ### Extended annotation use case In future it might be useful to be able to annotate events with more From c28c38559ab7f5170818080d7e9fd42b27b5961c Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 14 Feb 2023 23:34:57 +0000 Subject: [PATCH 12/14] Clarify variation-16 --- proposals/2677-reactions.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/proposals/2677-reactions.md b/proposals/2677-reactions.md index 3ab12f9f9d6..e8319876046 100644 --- a/proposals/2677-reactions.md +++ b/proposals/2677-reactions.md @@ -61,8 +61,11 @@ An event annotating another with the thumbs-up emoji would therefore have the fo } ``` -When sending emoji reactions, the `key` property should include the colourful -variation-16 when applicable. +When sending emoji reactions, the `key` property should include the unicode +[emoji presentation +selector](https://www.unicode.org/reports/tr51/#def_emoji_presentation_selector) +(`\uFE0F`) for codepoints which allow it (see the [emoji variation sequences +list](https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-variation-sequences.txt)). Any `type` of event is eligible for an annotation, though note that, since state events do not currently receive bundled aggregations (see From fdbb745c2a4fba20a7dd6d7c8429b53fab9858fa Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Tue, 21 Feb 2023 15:52:34 +0000 Subject: [PATCH 13/14] Update 2677-reactions.md --- proposals/2677-reactions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/2677-reactions.md b/proposals/2677-reactions.md index e8319876046..535f4d60a4b 100644 --- a/proposals/2677-reactions.md +++ b/proposals/2677-reactions.md @@ -195,7 +195,7 @@ When aggregating `m.annotation` events, homeservers should group events together based on their event `type` and `key`, and count the number of each distinct `type`/`key`. An example aggregation is as follows: -```json +```json5 { "event_id": "$original_event_id", // irrelevant fields not shown From 749198fd4a9efa4dc8eb0565ad05746ffa70aa7f Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Tue, 28 Feb 2023 18:46:59 +0000 Subject: [PATCH 14/14] No server-side aggregation for reactions --- proposals/2677-reactions.md | 87 ++++++++++--------------------------- 1 file changed, 22 insertions(+), 65 deletions(-) diff --git a/proposals/2677-reactions.md b/proposals/2677-reactions.md index 535f4d60a4b..97b06c34e26 100644 --- a/proposals/2677-reactions.md +++ b/proposals/2677-reactions.md @@ -67,10 +67,7 @@ selector](https://www.unicode.org/reports/tr51/#def_emoji_presentation_selector) (`\uFE0F`) for codepoints which allow it (see the [emoji variation sequences list](https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-variation-sequences.txt)). -Any `type` of event is eligible for an annotation, though note that, since -state events do not currently receive bundled aggregations (see -[aggregations](https://spec.matrix.org/v1.6/client-server-api/#aggregations)), -the results of annotating a state event may be inconsistent. +Any `type` of event is eligible for an annotation, including state events. ### `m.reaction` event type @@ -95,7 +92,8 @@ looks like: ``` Since they contain no `content` other than `m.relates_to`, `m.reaction` events -are normally not encrypted, as there would be no benefit in doing so. +are normally not encrypted, as there would be no benefit in doing so. (However, +see [Encrypted reactions](#encrypted-reactions) below.) ### Interation with edited events @@ -120,15 +118,10 @@ Clients must keep count of the number of annotations with a given event `type` and annotation `key` they observe for each event; these counts are typically presented alongside the event in the timeline. -Servers must perform a similar operation to calculate the relationship -aggregation (see -[below](#server-side-aggregation-of-mannotation-relationships)). - When performing this count: - * Servers must count each event `type` and annotation `key` - separately. Clients will normally choose to do so to though this is an - implementation decision. + * Each event `type` and annotation `key` should normally be counted separately, + though whether to actually do so is an implementation decision. * Annotation events sent by [ignored users](https://spec.matrix.org/v1.6/client-server-api/#ignoring-users) should be excluded from the count. @@ -187,67 +180,31 @@ annotations when [counting annotations](#counting-annotations). #### Server-side aggregation of `m.annotation` relationships -Homeservers should -[aggregate](https://spec.matrix.org/v1.6/client-server-api/#aggregations) -events with an `m.annotation` relationship to a given event. +`m.annotation` relationships are *not* [aggregated](https://spec.matrix.org/v1.6/client-server-api/#aggregations) +by the server. In other words, `m.annotation` is not included in the `m.relations` property. + +## Alternatives + +### Encrypted reactions -When aggregating `m.annotation` events, homeservers should group events -together based on their event `type` and `key`, and count the number of each -distinct `type`/`key`. An example aggregation is as follows: +[matrix-spec#660](https://github.com/matrix-org/matrix-spec/issues/660) +discusses the possibility of encrypting message relationships in general. + +Given that reactions do not rely on server-side aggregation support, an easier +solution to encrypting reactions might be not to use the relationships +framework at all and instead just use a keys within `m.reaction` events, which +could then be encrypted. For example, a reaction could instead be formatted as: ```json5 { - "event_id": "$original_event_id", - // irrelevant fields not shown - "unsigned": { - "m.relations": { - "m.annotation": { - "chunk": [ - { - "type": "m.reaction", - "key": "👍", - "count": 3 - }, - { - "type": "example.com.test", - "key": "👍", - "count": 1 - }, - { - "type": "m.reaction", - "key": "👎", - "count": 2 - } - ] - } - } + "type": "m.reaction", + "content": { + "event_id": "$some_event_id", + "key": "👍" } } ``` -This event has received three thumbsup reactions, two thumbsdown reactions, and -a thumbsup annotation with an event type of `example.com.test` (which will be -ignored by clients which don't understand the `example.com.test` event type). - -As the example shows, the aggregation format has a `chunk` property at the top -level. (This is indended to allow pagination of reactions in a future -extension, though that is not currently specified.) Each entry in the `chunk` is -an object with properties: - - * `type`: the event `type` of the aggregated events. - * `key`: the `key` from the `m.relates_to` properties of the aggregated events. - * `count`: the number of unredacted events with this event `type` and annotation `key`. - -When evaluating `count`, servers should respect the guidelines above about -[counting annotations](#counting-annotations). - -## Alternatives - -### Encrypted reactions - -[matrix-spec#660](https://github.com/matrix-org/matrix-spec/issues/660) -discusses the possibility of encrypting message relationships. - ### Extended annotation use case In future it might be useful to be able to annotate events with more