feat: use sessionKey for cross-device dedup in detectBellTransitions (task-18)

Replace s.name with s.sessionKey || s.name as the map key in
detectBellTransitions so two sessions with the same name on
different devices are tracked independently.

- prevMap construction uses s.sessionKey || s.name as key
- next filter lookup uses the same s.sessionKey || s.name key
- Falls back to s.name when no sessionKey is present (backward compatible)

Co-authored-by: Amplifier <amplifier@example.com>
This commit is contained in:
Brian Krabach
2026-03-31 01:37:49 -07:00
parent 2b5b6e3003
commit c7c92ee0da
2 changed files with 30 additions and 6 deletions
+9 -6
View File
@@ -66,17 +66,20 @@ function filterByQuery(sessions, query) {
* @returns {string[]} names of sessions that newly have or increased bell count * @returns {string[]} names of sessions that newly have or increased bell count
*/ */
function detectBellTransitions(prev, next) { function detectBellTransitions(prev, next) {
const prevMap = new Map( var prevMap = new Map(
(prev || []).map((s) => [s.name, (s.bell && s.bell.unseen_count) || 0]), (prev || []).map(function(s) {
return [s.sessionKey || s.name, (s.bell && s.bell.unseen_count) || 0];
}),
); );
return (next || []) return (next || [])
.filter((s) => { .filter(function(s) {
const unseen = s.bell && s.bell.unseen_count; var unseen = s.bell && s.bell.unseen_count;
if (!unseen || unseen <= 0) return false; if (!unseen || unseen <= 0) return false;
const prevCount = prevMap.has(s.name) ? prevMap.get(s.name) : 0; var key = s.sessionKey || s.name;
var prevCount = prevMap.has(key) ? prevMap.get(key) : 0;
return unseen > prevCount; return unseen > prevCount;
}) })
.map((s) => s.name); .map(function(s) { return s.name; });
} }
/** /**
+21
View File
@@ -189,6 +189,27 @@ test('detectBellTransitions does not fire when unseen_count decreases', () => {
assert.deepStrictEqual(app.detectBellTransitions(prev, next), []); assert.deepStrictEqual(app.detectBellTransitions(prev, next), []);
}); });
test('detectBellTransitions uses sessionKey to distinguish same-name sessions across devices', () => {
// Two sessions both named 'main' but from different devices, identified by sessionKey
const prev = [
{ name: 'main', sessionKey: 'device-A::main', bell: { unseen_count: 3 } },
{ name: 'main', sessionKey: 'device-B::main', bell: { unseen_count: 0 } },
];
const next = [
{ name: 'main', sessionKey: 'device-A::main', bell: { unseen_count: 3 } }, // no change
{ name: 'main', sessionKey: 'device-B::main', bell: { unseen_count: 2 } }, // increased
];
// Only the device-B 'main' session should trigger (its count increased from 0 to 2)
assert.deepStrictEqual(app.detectBellTransitions(prev, next), ['main']);
});
test('detectBellTransitions falls back to s.name when no sessionKey present', () => {
// Sessions without sessionKey should still work using name as fallback
const prev = [{ name: 'work', bell: { unseen_count: 0 } }];
const next = [{ name: 'work', bell: { unseen_count: 1 } }];
assert.deepStrictEqual(app.detectBellTransitions(prev, next), ['work']);
});
// --- generateDeviceId --- // --- generateDeviceId ---
test('generateDeviceId returns a string matching /^d-[a-z0-9]+$/', () => { test('generateDeviceId returns a string matching /^d-[a-z0-9]+$/', () => {