matrix-doc/proposals/3306-counting-unread-messag...

98 lines
4.6 KiB
Markdown

# MSC3306: How to count unread messages
## Preface
It all started when the author of this MSC tried to count unread messages on
the client side so that the result matches the `notification_count` number
returned by `/sync`. After a couple of unsuccessful attempts to match it
it occured to me that, aside from the generic guidance in The Spec that
the unread notifications are counted from the read receipt and only include,
well, messages(?) there's some extensive sacred knowledge regarding which
messages should be counted. I went asking around and looking into the Synapse
code, finding a particular function, the contents of which I suggest enshrining
in a canonical text for reasons described in the normative part of this MSC,
as follows.
## Introduction
The Client-Server API (CS API) and the Push Gateway API (PG API) employ
a certain counter called "the number of unread notifications". In CS API it
comes in the `/sync` response, placed under
`rooms.*.unread_notifications.notification_count`; PG API places a similar
counter but spanning all rooms in the `/notify` request body under
`notification.counts.unread`. The way this number is calculated is obscure:
you have to look at the homeserver's source code to figure out how it is
produced, bearing in mind that, despite the `notification_count` name in
CS API, it is different from the number of messages for which there's
a [Push Rule](https://spec.matrix.org/unstable/client-server-api/#push-rules)
with `action` set to `notify`. There's merit therefore providing a common
"notable events" criterion, both for homeservers to calculate the unread count
uniformly but also for clients so that they could provide more accurate numbers
when it's possible and/or even customise the calculation algorithm to
users' liking.
## Proposal
It is proposed to use the following algorithm (slightly extending
[the _should_count_as_unread function in Synapse](https://github.com/matrix-org/synapse/blob/bdfde6dca11a9468372b3c9b327ad3327cbdbe4a/synapse/push/bulk_push_rule_evaluator.py#L65)
that provides a reasonable baseline) to determine whether a given event should
be included in an unread counter:
1. return false if the event is never going to come to clients, i.e., it is
rejected or soft-failed
2. return false if the event is a room message event with
`msgtype == "m.notice"`
3. return false if the event is redacted (only for clients)
4. return false if the event is an edit, as per the algorithm proposed by
[MSC1849](https://github.com/matrix-org/matrix-doc/pull/1849), i.e. with
`rel_type == "m.replace"` in its content (see below)
5. return true if the event content has a non-empty `body` value (see below)
6. return true if the event is a state event with one of the following types:
`m.room.topic`, `m.room.name`, `m.room.avatar`, `m.room.tombstone`
7. return true if the event is encrypted and is not a state event (see below)
8. otherwise, return false
Homeservers can only check criteria 4 and 5 in unencrypted rooms while clients
and bridges supporting E2B can apply them in any room; rule 7 is only
applicable to cases when decryption is impossible or impractical.
Homeservers SHOULD implement the above algorithm; clients MAY implement it, in
order to report more accurate figures to the users, but are not required to,
given that the numbers produced by homeservers are in many cases good enough.
## Potential issues
In some cases counting messages on the server side may yield different results
for encrypted and non-encrypted rooms, as homeservers cannot inspect
the content to determine whether a given event should be counted. This proposal
does not try to align unread counting on client side and server side, deeming
the divergence acceptable. Shifting calculation entirely to the client side is
not friendly to mobile clients that rely heavily on push notifications; on
the other hand, mandating calculation to occur on the server side means that
clients (and bridges) won't be able to take advantage from looking into
messages.
## Alternatives
The obvious alternative is to do nothing and stay with the current unspecified
way to count unread messages. The obvious drawback of this alternative is that,
as the number of homeserver codebases grows, counting events will be done in
increasingly diverse ways, confusing users who happen to deal with several
homeservers.
## Security considerations
None that I know of.
## Unstable prefix
Since impact on the network operation from a possible change in calculation logic
in non-Synapse homeservers is negligible, no unstable prefix is suggested for
counters calculated in a new way. Just start using a common algorithm.