diff --git a/dashboard/index.html b/dashboard/index.html index 97c153c..7f705ac 100644 --- a/dashboard/index.html +++ b/dashboard/index.html @@ -242,7 +242,7 @@ // ----------------------------------------------------------------------- // State // ----------------------------------------------------------------------- - /** @type {Map} eventId -> parsed lock */ + /** @type {Map} dTag -> latest parsed lock */ const lockStore = new Map(); /** @type {WebSocket[]} */ const sockets = []; @@ -352,6 +352,16 @@ return lock.expiresAt != null && lock.expiresAt <= nowUnix(); } + function shouldReplaceLock(existingLock, incomingLock) { + if (!existingLock) return true; + if (incomingLock.createdAt !== existingLock.createdAt) { + return incomingLock.createdAt > existingLock.createdAt; + } + + // Deterministic tie-break: prefer lexicographically higher event id. + return (incomingLock.eventId || '') > (existingLock.eventId || ''); + } + // ----------------------------------------------------------------------- // Platform styling // ----------------------------------------------------------------------- @@ -592,9 +602,10 @@ const event = data[2]; const lock = parseLockEvent(event); - // De-duplicate: keep the event with earliest created_at per d-tag + // De-duplicate by dTag: keep one lock per d-tag, preferring the + // most recent created_at; if equal, replace deterministically by event id. const existing = lockStore.get(lock.dTag); - if (!existing || existing.createdAt > lock.createdAt) { + if (shouldReplaceLock(existing, lock)) { lockStore.set(lock.dTag, lock); }