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);
}