Skip to content

Commit d1d3dd9

Browse files
jb55claude
andcommitted
nostrverse: reject out-of-order presence events
Track event_created_at on RoomUser and skip presence updates whose created_at is older, preventing stale replaceable events from overwriting newer positions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 364b84d commit d1d3dd9

File tree

2 files changed

+11
-0
lines changed

2 files changed

+11
-0
lines changed

crates/notedeck_nostrverse/src/presence.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,20 +189,27 @@ pub fn poll_presence(
189189
}
190190

191191
let velocity = nostr_events::parse_presence_velocity(note);
192+
let created_at = note.created_at();
192193

193194
// Update or insert user
194195
if let Some(user) = users.iter_mut().find(|u| u.pubkey == pubkey) {
196+
// Skip stale events — replaceable events can arrive out of order
197+
if created_at <= user.event_created_at {
198+
continue;
199+
}
195200
// Update authoritative state; preserve display_position for smooth lerp
196201
user.position = position;
197202
user.velocity = velocity;
198203
user.update_time = now;
199204
user.last_seen = now;
205+
user.event_created_at = created_at;
200206
} else {
201207
let mut user = RoomUser::new(pubkey, "anon".to_string(), position);
202208
user.velocity = velocity;
203209
user.display_position = position; // snap on first appearance
204210
user.update_time = now;
205211
user.last_seen = now;
212+
user.event_created_at = created_at;
206213
users.push(user);
207214
}
208215
changed = true;

crates/notedeck_nostrverse/src/room_state.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,9 @@ pub struct RoomUser {
231231
pub is_self: bool,
232232
/// Monotonic timestamp (seconds) of last presence update
233233
pub last_seen: f64,
234+
/// Nostr event created_at of the latest accepted presence event.
235+
/// Used to ignore out-of-order replaceable events.
236+
pub event_created_at: u64,
234237
/// Runtime: renderbud scene object handle for avatar
235238
pub scene_object_id: Option<ObjectId>,
236239
/// Runtime: loaded model handle for avatar
@@ -248,6 +251,7 @@ impl RoomUser {
248251
update_time: 0.0,
249252
is_self: false,
250253
last_seen: 0.0,
254+
event_created_at: 0,
251255
scene_object_id: None,
252256
model_handle: None,
253257
}

0 commit comments

Comments
 (0)