The sync token advances even when no messages are extracted from allowed rooms. This causes messages to be missed when:
- Sync returns events only for non-allowed rooms
- Sync returns non-message events (typing, read receipts) for allowed rooms
- Messages arrive during concurrent processing
// Currently: Always save token after sync, even if no messages extracted
self.save_sync_token(&next_batch);This would cause infinite re-processing of non-message events.
Store event IDs of processed messages, skip duplicates. Memory grows over time.
Matrix supports per-room prev_batch tokens. Track last seen event per room.
Only advance token if allowed rooms were present in sync response, regardless of whether they had messages.
// Track whether any allowed rooms appeared in this sync
let mut allowed_rooms_in_sync = false;
if let Some(rooms) = sync_response.rooms {
if let Some(joined_rooms) = rooms.join {
for (room_id, room_data) in joined_rooms {
let in_allowed = self.allowed_chats.contains(&room_id) || dm_rooms.contains(&room_id);
if in_allowed {
allowed_rooms_in_sync = true;
// ... process messages as before
}
}
}
}
// Only advance token if:
// 1. We extracted messages, OR
// 2. Allowed rooms were in sync (even with no messages = they're caught up)
// 3. No allowed rooms configured (process everything)
if !messages.is_empty() || allowed_rooms_in_sync || (self.allowed_chats.is_empty() && dm_rooms.is_empty()) {
self.save_sync_token(&next_batch);
}- If allowed rooms appear in sync with no messages → token advances (caught up)
- If sync only has events for non-allowed rooms → token does NOT advance
- Next sync will include the same batch + any new events
- Eventually the allowed room will appear and token advances
If we never get events for allowed rooms, token never advances. This is fine — we'll get them eventually when someone sends a message.
File: crates/rustyclaw-core/src/messengers/matrix_cli.rs
Lines: ~455-460 (save_sync_token section)