Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Clarify which tokens can be used in `from` or `to` in `GET /rooms/{roomId}/relations/{eventId}`.
54 changes: 31 additions & 23 deletions data/api/client-server/relations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ paths:
description: |-
Retrieve all of the child events for a given parent event.

Note that when paginating the `from` token should be "after" the `to` token in
terms of topological ordering, because it is only possible to paginate "backwards"
through events, starting at `from`.
Note that, in terms of topological ordering, the `from` token should be "after"
the `to` token when `dir=b`, and should be "before" the `to` token when `dir=f`.

For example, passing a `from` token from page 2 of the results, and a `to` token
from page 1, would return the empty set. The caller can use a `from` token from
page 1 and a `to` token from page 2 to paginate over the same range, however.
For example, with `dir=b`, passing a `from` token from page 2 of the results, and
a `to` token from page 1, would return the empty set. The caller can use a `from`
token from page 1 and a `to` token from page 2 to paginate over the same range,
however.
operationId: getRelatingEvents
security:
- accessTokenQuery: []
Expand Down Expand Up @@ -80,13 +80,13 @@ paths:
Retrieve all of the child events for a given parent event which relate to the parent
using the given `relType`.

Note that when paginating the `from` token should be "after" the `to` token in
terms of topological ordering, because it is only possible to paginate "backwards"
through events, starting at `from`.
Note that, in terms of topological ordering, the `from` token should be "after"
the `to` token when `dir=b`, and should be "before" the `to` token when `dir=f`.

For example, passing a `from` token from page 2 of the results, and a `to` token
from page 1, would return the empty set. The caller can use a `from` token from
page 1 and a `to` token from page 2 to paginate over the same range, however.
For example, with `dir=b`, passing a `from` token from page 2 of the results, and
a `to` token from page 1, would return the empty set. The caller can use a `from`
token from page 1 and a `to` token from page 2 to paginate over the same range,
however.
operationId: getRelatingEventsWithRelType
security:
- accessTokenQuery: []
Expand Down Expand Up @@ -142,13 +142,13 @@ paths:
Retrieve all of the child events for a given parent event which relate to the parent
using the given `relType` and have the given `eventType`.

Note that when paginating the `from` token should be "after" the `to` token in
terms of topological ordering, because it is only possible to paginate "backwards"
through events, starting at `from`.
Note that, in terms of topological ordering, the `from` token should be "after"
the `to` token when `dir=b`, and should be "before" the `to` token when `dir=f`.

For example, passing a `from` token from page 2 of the results, and a `to` token
from page 1, would return the empty set. The caller can use a `from` token from
page 1 and a `to` token from page 2 to paginate over the same range, however.
For example, with `dir=b`, passing a `from` token from page 2 of the results, and
a `to` token from page 1, would return the empty set. The caller can use a `from`
token from page 1 and a `to` token from page 2 to paginate over the same range,
however.
operationId: getRelatingEventsWithRelTypeAndEventType
security:
- accessTokenQuery: []
Expand Down Expand Up @@ -252,9 +252,14 @@ components:
The pagination token to start returning results from. If not supplied, results
start at the most recent topological event known to the server.

Can be a `next_batch` or `prev_batch` token from a previous call, or a returned
`start` token from [`/messages`](/client-server-api/#get_matrixclientv3roomsroomidmessages),
or a `next_batch` token from [`/sync`](/client-server-api/#get_matrixclientv3sync).
If `dir=b`, then `from` can be `next_batch` from a previous call, or a
`prev_batch` token from a [`/sync`] or a `start` token from a [`/messages`].
Comment on lines +255 to +256

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Starting a proper thread for this discussion.

Pagination tokens are positions between events. You should be able to further paginate from any position.

While this information is coming from my Synapse knowledge, I don't think that idea is Synapse specific.

You can see the sort of Complement tests I added around this kind of thing for /timestamp_to_event where you can paginate backwards from the start or end tokens,

@Hywan Hywan May 22, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any suggestion of how it should be phrased then?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would you want to paginate backwards from an end token?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It boils down to "because you can" and client flexibility. They may not want to process the event from /context and instead are only using it to get a pagination token to use as part of their normal pagination flows (uniform handling).

A more technical reason is perhaps you're using the filter query parameter: with /context, "It is not applied to the event itself" but it will apply consistently with /messages.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly "because Synapse lets me get away with it" doesn't hold much water for me here. We need to be mindful of meeting the requirements of a client without unduly constraining server implementations. Further, since we are talking about changing the definition of an existing, specified endpoint, there is a fine line between "correcting an obvious error" and "changing the way the endpoint works". It is not fair to other server implementations to suddenly add requirements without following the MSC process.

Nevertheless, an analogy with /messages is somewhat compelling. The spec for that has no restriction against paginating backwards from a next_batch in /sync, so we should probably replicate that. (Though it does appear to preclude paginating in either direction from the results of /context or /search, which I don't think is deliberate.)

(Also, why would we only permit paginating backwards from the start of a /messages rather than an end?)

So I guess we should loosen these constraints.

Suggested change
If `dir=b`, then `from` can be `next_batch` from a previous call, or a
`prev_batch` token from a [`/sync`] or a `start` token from a [`/messages`].
This token can be any of:
* `next_batch` from the response to a previous call.
* a `prev_batch` or `next_batch` token from a [`/sync`] response.
* a `start` or `end` token from a [`/messages`], [`/context`] or [`/search`] response

(And remove the separate description for dir=f)

I'm hoping for insight from the rest of the SCT on this, because frankly I'm struggling to decide.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed this among the SCT, and ended up concluding that the whole pagination thing needed simplifying and making more consistent, but that would require an MSC since it will mean changing behaviour for some implementations... which @clokep has offered to write! 🎉

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have written one, waiting for a bit of feedback on the draft from @richvdh and then will publish. Hopefully this week.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See MSC4492.


If `dir=f`, then `from` can be `prev_batch` from a previous call, or a
`next_batch` token from a [`/sync`] or an `end` token from a [`/messages`].

[`/messages`]: /client-server-api/#get_matrixclientv3roomsroomidmessages
[`/sync`]: /client-server-api/#get_matrixclientv3sync
required: false
example: page2_token
schema:
Expand All @@ -266,8 +271,11 @@ components:
The pagination token to stop returning results at. If not supplied, results
continue up to `limit` or until there are no more events.

Like `from`, this can be a previous token from a prior call to this endpoint
or from `/messages` or `/sync`.
Like `from`, this can be a previous token from a prior call to this endpoint,
or from [`/sync`] or [`/messages`].

[`/messages`]: /client-server-api/#get_matrixclientv3roomsroomidmessages
[`/sync`]: /client-server-api/#get_matrixclientv3sync
required: false
example: page3_token
schema:
Expand Down
Loading