From 659419212050bab50f600493fbe48a28aed44ac5 Mon Sep 17 00:00:00 2001 From: Cameron Little Date: Tue, 20 Jan 2026 11:02:54 -0700 Subject: [PATCH] Fix `upToId` computation `queryChanges` (#2688) Currently, stalwart stops processing changes once the value of `upToId` is hit, which means it discards that change. In our UI, this means the last item disappears. This fixes that by moving the check to after the item has been processed. Also, from the spec (emphasis mine): > The last (highest-index) id the client currently has cached from the query results. When there are a large number of results, in a common case, the client may have only downloaded and cached a small subset from the beginning of the results. If the sort and filter are both only on immutable properties, this allows the server to omit changes after this point in the results, which can significantly increase efficiency. **If they are not immutable, this argument is ignored.** I've removed `upToId` from the `mutable` branch. --- crates/jmap/src/changes/query.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/jmap/src/changes/query.rs b/crates/jmap/src/changes/query.rs index eff4100c..edcbcbfa 100644 --- a/crates/jmap/src/changes/query.rs +++ b/crates/jmap/src/changes/query.rs @@ -266,9 +266,7 @@ impl QueryChanges for Server { if has_changes { if is_mutable { for (index, id) in results.ids.into_iter().enumerate() { - if matches!(up_to_id, Some(up_to_id) if up_to_id == id) { - break; - } else if changes.created.contains(&id) || changes.updated.contains(&id) { + if changes.created.contains(&id) || changes.updated.contains(&id) { response.added.push(AddedItem::new(id, index)); } } @@ -276,10 +274,11 @@ impl QueryChanges for Server { response.removed = changes.updated; } else { for (index, id) in results.ids.into_iter().enumerate() { + if changes.created.contains(&id) { + response.added.push(AddedItem::new(id, index)); + } if matches!(up_to_id, Some(up_to_id) if up_to_id == id) { break; - } else if changes.created.contains(&id) { - response.added.push(AddedItem::new(id, index)); } } }