In my implementation for the Conduit Matrix server, the /sync order is used for everything. The timeline is just one list that grows on one end for incoming events and on the other end for backfilled events.
I think it's important that the message order does not change, because that's very difficult to communicate to the user.
Well.
Not only does it feel like the most correct (I don’t think there is a perfect) behaviour for the user but also makes implementation much simpler. Synapse has a LOT of ordering foo and magic in the code I still don’t fully understand and I’ve gone fairly deep into synapse at times for work.
1. All up-to-date clients should be displaying the same message order. 2. A single client should not send messages in the wrong order.
Yes a client may be out of date and therefore show something different, but once it becomes up to date it should be showing the same state even if that means amending history. Why? Because the humans reading it will be confused otherwise! An app getting more data is something we intuitively understand, but if my client shows something and yours shows something else, we will conclude different meanings from it.
Additionally there are some clients that treat each message input by the user as a retriable thing in isolation, which is also clearly incorrect. If I send two messages and the first fails to go through, I almost certainly don't want to retry the second until the first has gone through, otherwise my client has literally sent out of order messages! I use Beeper for chat and this is one of the most frustrating things it does.
It's not debatable! There is, actually, in reality, one true message ordering (at this time I think we can safely ignore relativistic effects), and that message ordering should be the one that is always displayed. Our technology and the nature of distributed systems may make it impossible to always faithfully determine what the true message ordering is, but at the very least, the implementation should decide on a single message ordering, and always present that same message ordering. (This does mean that clients connected to different homeservers might see different orderings; this is unfortunate but probably unavoidable. But clients connected to the same homeserver should all see the same ordering.)
Anything else is just terrible, awful, horrible UX, that will ultimately confuse users. And it will also reduce user faith in the system as a whole: if they notice the inconsistent ordering, they will assume the system is buggy and unreliable.
At the risk of sounding way too absolutist: this is not debatable, and anyone who thinks it is, is wrong.
I don't think it's unavoidable at all, this is exactly the kind of problems CRDTs solve beautifully. If you model your chatting as a CRDT (basically, each message has a Lamport timestamp on it, and you have some sensible way to resolve ties deterministically), then assuming all peers have gotten all messages, the ordering should be perfectly consistent. What may happen is that you type a message, press "enter", and then some message might pop up before that when everyone finally sync, but I think that is acceptible UX, I see version of this in things like Slack and Discord frequently.
All peers having the same message order assuming they all have received the same messages is absolutely required for a chat application in 2024, distributed or not.
Ideally, yes. In the real world you get to deal with such inconveniences as unreliable transport, slow networks, server-to-server communications, eventual consistency, routing glitches, reconnections, clock skew, queues, concurrency, retries, and always, ALWAYS the infuriatingly slow speed of light. Oh yes, also multiple client implementations. For the record, many years ago I was involved in writing both a chat server and a client. (Albeit those were two different projects.)
From pure UX standpoint, you want the client to always show any messages it has sent but has not received back. Even for a single server and two clients, all synchronised to the same clock, you can get ordering conflicts. Let's say that you are sending a message at fixed two-second interval, and the other client is sending messages at non-fixed, power law distribution intervals. That's your happy path.
Now consider the same with dozens, or hundreds of clients across hundreds of different networks, each with their own debatable quality.
You want to see the messages you've sent, so they need to be visible on your screen. Having your own messages disappear into the void and only appear once they have been sent back is terrible UX. So you keep a local order and interleave received messages as they come in. But once you receive the message back from the server, you obviously want to reorder the known quantities. With two clients you will the occasional "jump" where one of your messages is moved to its canonical position. With hundreds of clients each user will see those jumps constantly - and with sufficient volume a decent fraction of their own sent messages can "disappear" at any time from their screen as they are reordered and don't fit on the screen.
Now add lots of bad networks and latency floor in hundreds of milliseconds. Network connections/route fluctuate constantly, so even messages sent by the same client less than two seconds apart can arrive in different order at the server. (The client reconnected between the two, and the message sent over the first connection arrives several seconds later than the other one.) The user is confused, because the server is very clearly showing them their own messages in the wrong order.
For one inconvenienced user the server being wrong occasionally is mildly annoying. But when that can happen to any number of users, concurrently, at any time, the overall effect is outright infuriating.
> this is not debatable, and anyone who thinks it is, is wrong
Your server has a known order it sent the messages out. Any disagreement means the client must be wrong.
Each of the clients connected to your server has a known order in which they sent their messages out. Any disagreement means the server must be wrong.
That's interesting because I have the complete opposite take and would hard disagree with this. I intuitively understand that if we both write messages at the same time, we will see them in different order. Snail mail has worked this way for centuries, and I very much prefer this to an app silently altering the content as time goes. It is confusing when it happens under my eyes (something moved at the top of the screen while I was reading the bottom, what was it?) and easily leads to missed messages especially in group conversations (my buddy sent a message with a poor connection at 11am, it is retried and sent at 2pm and appears before the lengthy discussion others had at noon).
Messenger apps claim that such a history exists by showing you, well, that history. In the same way, messengers claim that a message order exists, by showing you the messages in that order. If something exists, then it is independent of the viewer. So the assumption that the message order is the same for all viewers is founded in how two people look at physical objects.
I think you are thinking like a distributed systems designer. I would assume that if you asked 10 "random Americans" 9 of them would assume that someone managed to send their message first and would be surprised if their phone and their friends phone showed them messages in different orders.
The ordering the server decides may not be "correct" (for whatever definition of correct matters to you), but what is most important in this situation is consistency.
If I see that another message has arrived and my message could be misunderstood, I can correct that by sending another message. But if I don't know what ordering the other side is seeing then I don't know if my message is ambiguous or not.
The only way achieve that is to show a consistent ordering to both participants (or to force every message to be in reply to another message but that's too nerdy)
Especially if there were simple controls to flip into a mode that minimizes the ones already seen (collapsed and grey for example) while highlighting all of the ones inserted in the past.
Or, if there are many messages already seen and few inserted into hist, show the inserted ones with a small sampling of the already seen (so the user can anchor to already familiar data in the timeline) along with "72 messages hidden that were previously seen" type of thing in between the inserteds to condense the view.
I don't think that's clearly incorrect. If you sent two messages you presumably want them to be two messages and they should be retried as such. If what you wanted to send was a single, multi-line message, surely you would have just done that?
[12:00 / sent] Sell the house.
[12:05 / failed] Please feed the baby.
[12:06 / sent] Oh and the cat too.
Now the receiver's going to sell my cat [example inspired by The Art of Multiprocessor Programming].
And even in the case where people do tend to send one complete thought per message, it still matters: like maybe I send a message, and then have an extra thought, and send a follow-up message that clarifies my first message. If they are displayed out of order, that will be confusing.
Even if two messages are completely unrelated and completely separate thoughts (honestly this feels like a much less common case than the alternative), messages just should be displayed in the order they were sent, because that's what reflects reality best.
No. danpalmer is correct; the break between messages is an integral part of the communication.
I believe that's impossible? At least if you design it correctly.
For ordering/interleaving purposes, what matters isn't the time you claim to send the message, it's the time the message is received by the server. If you want, you can display the claimed send timestamp beside the message (and prominently highlight it if it is e.g. out of order, or with a long delay, etc.), but that is irrelevant to the ordering.
The point here is that there should be a single consistent order on the server, and that's what all clients ought be displaying. Any messages not yet acknowledged by the server should be displayed differently so that users are aware they haven't been seen yet, and any messages that arrive before those are sent would obviously get inserted above those.
If user U1 sends a message M1 at time T1, then U1 must be able to modify/delete that message M1, in some reasonable sense, at any conceivable time from T1 forwards.
Any protocol that doesn't support some reasonable form of message modification/deletion in this sense, is a toy protocol, and will never be widely adopted.
This could indeed be a potential problem for a decentralized system, or one where the server for some reason cannot (or cannot be trusted to) timestamp messages. In that case, I think the best behavior for a client would be to always display messages in the order they've arrived, regardless of any timestamp provided by the sender.
But this problem shouldn't exist for a system like Matrix. Matrix is (somewhat) decentralized, but each homeserver can still decide on the message ordering it will present to its own clients.
Not really getting this point though:
The /sync API returns events in an order "according to the arrival time of the event on the homeserver".
The spec for /messages says it returns events "in chronological order. (The exact definition of chronological is dependent on the server implementation.)".
Why would those two return different results? When does the chronological order of two messages differ from the arrival time of the event on the homeserver?If that understanding is correct, then IMO the answer is simply that the canonical timeline is what that server says it is. Poorly connected users or those on other servers experiencing issues or delays with federation may temporarily see a different sequence of events but once everyone's had a chance to sync back up the state should generally be what the primary server for the room saw it as.
Perhaps there should be some sort of flag for "this message has been reordered during a resync" that clients which initially had a different state due to whatever reason could store to make it clear what happened, and likewise if the central homeserver receives messages with a timestamp significantly off real time it could flag those messages as possibly having been received out of order while still displaying them in the order they were received.
But at least for messages sent within the same homeserver, I would think that those two apis should return the same data
If a Matrix server allows to delete messages (by the poster or by a moderator), then increasing IDs with no gaps become impossible. If the server allows editing of existing messages, then a sequence with no gaps is not sufficient to reflect all changes. Ideally a server does not do either, but uses more messages to augment existing messages, or mark some as deleted; with that, a sequence with no gaps would suffice.
And if, as in the example at the end, clients on different homeservers will inevitably see different views, then I don't think always showing the same history to the same client, or clients on the same server, solves the "gaslighting" problem - if anything it could make it worse. Maybe clients should make it obvious when messages have been "retconned" into the scrollback, and maybe servers should have certain features to support that. But the idea of having a consistent linear timeline is one of those answers that's clear, simple, and wrong.
Surely that's a presentation issue - you should display messages chronologically, regardless of what order you got them from the server? The author does touch on this a little bit, I don't see how that isn't the "obviously" correct approach?:
> An alternative is to continue providing events in any order, but add some kind of order number that allows clients to sort events into /sync order. MSC4033 proposes this.
Granted, tacking them all at the end isn't necessarily good, but at least the user will see them, and timestamp indicators can help make sense of it.
And I don't even see how placing them chronologically would be particularly useful - given a netsplit there's not gonna be any relation between the previously-present and delayed-received messages at that time interval anyway, you're just interleaving two entirely different discussions for no reason. (ok maybe there can be some unidirectional delay where it could maybe be useful, idk)
Like this[1]. It's how Element does it, and it's perfectly fine. Show the unread messages with a different background color until the user dismisses them if you must distinguish them from previously read messages. Alternatively, add a "jump to last unread message" button (and change the "jump to first" icon into a double up-arrow) that marks said message as read after jumping to it so you can just keep clicking it to hop to each one. If there's anything I'd change about this UI element, it's to display the number of unread messages in the green dot.
- People think that messages are a timeline and are in chronological order. For non distributed messages (Teams, WhatsApp) that's the reality, and people don't read message timestamps. Old messages being put at the bottom is confusing.
- Matrix is distributed so message can arrive out of order (sometimes with quite a delay)
Those two things together means that the client HAS to solve this display problem.
I know it's a much harder problem without a central server managing things. But consistency is very important for messages, out of order they could have a very different meaning and be very confusing.
In got example it is easy if the structures relating to the video and text contain some what to identify the source node, or just that they belong to the same lineage (you could have a per-thread-per-source-node value, produced from a salted hash of the real information, if source host Id is considered sensitive) and a timestamp taken at that node.
(Caveat: I know little of the specific protocols that are relevant here, so don't know if they do contain any such datum)
Where message ordering gets difficult to the point of impracticality (if not impossibility) is where you are ordering messages from many different sources that may not have fully synchronised clocks. You can make it easier with "in reply to" and "sent after" priorities (in each case, the value being a message identifier) so any given message can be sorted by its context, but the order of sibling messages may still not have a single possible ordering. And you have to decide, if using a "sent after" value, if you have the last message received at the time of sending, the last message received before this message was stated, the latest opened messages, etc, all of which could give different results.
To a certain extent you have to get to a point where ordering is good enough and you give up on it being exact & unambiguously consistent, or you'll spend so much time working out the ordering and have no time to send you own messages :)
i think the mental model should be what is most useful in court. if a netsplit occurs the state of the room doesn't exist anymore, conversation can continue but it should be a different room populated with working available clients. The main room can be restored and the missed convo can be a 3rd room
I think I have this right anyways. (CAP theorem for anyone curious.)
[1] https://uhoreg.gitlab.io/matrix-tutorial/sync.html#:~:text=w...