fix(platform): category-scoped unread pick and channel unread counts

Filter message rows by channelId in _unreadForChannel after HyperDB find.
When every unread channel shares one category parentId, limit
_selectGuildChannelWithUnread to that category before position tie-break.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Raven Scott
2026-05-22 18:32:14 -04:00
co-authored by Cursor
parent 19188c725c
commit f7c795259f
2 changed files with 23 additions and 3 deletions
+2
View File
@@ -135,6 +135,8 @@ Primary consumer: `apps/pearcord/index.js` sidecar reading pear-pipe JSON.
**v0.8.115:** `loadGuild` / `_openGuild` clears stale `activeChannelId`, then `_selectGuildChannelWithUnread` picks mention-weighted unread channels before falling back to the first text channel. `setSearch` records `searchRecentByGuild` in user prefs. View: `searchRecentQueries`.
**v0.8.124:** `_unreadForChannel` filters rows by `channelId` after HyperDB find. When all unread are in one category, `_selectGuildChannelWithUnread` picks only within that `parentId`. Smoke: `test:guild-category-unread-pick`.
**v0.8.123:** Equal unread/mention scores tie-break to lower `channel.position`. Smoke: `test:guild-unread-position-tie`.
**v0.8.120:** `_selectGuildChannelWithUnread` scores `mentions × 1000 + unread`; mention channel beats higher plain unread. Smoke: `test:guild-mention-channel-pick`.
+21 -3
View File
@@ -5059,12 +5059,25 @@ class PearcordPlatform extends EventEmitter {
})
}
const mentionByCh = new Map(alertRows.map((a) => [a.channelId, a.count || 0]))
let best = null
let bestScore = -1
const scored = []
for (const ch of candidates) {
const unread = await this._unreadForChannel(ch.id, ch.guildId)
const mentions = mentionByCh.get(ch.id) || 0
const score = mentions * 1000 + unread
if (score > 0) scored.push({ ch, score })
}
let pool = scored
const categoryParents = new Set(
scored.map((r) => r.ch.parentId).filter((id) => id != null && id !== '')
)
const hasUncategorizedUnread = scored.some((r) => !r.ch.parentId)
if (categoryParents.size === 1 && !hasUncategorizedUnread) {
const parentId = [...categoryParents][0]
pool = scored.filter((r) => r.ch.parentId === parentId)
}
let best = null
let bestScore = -1
for (const { ch, score } of pool) {
if (
score > bestScore ||
(score === bestScore && best && (ch.position || 0) < (best.position || 0))
@@ -5911,7 +5924,12 @@ class PearcordPlatform extends EventEmitter {
})
const since = state?.lastReadAt || 0
const msgs = await this.db.find(COLLECTIONS.MESSAGES, { channelId })
return msgs.filter((m) => m.createdAt > since && m.authorId !== user.id).length
return msgs.filter(
(m) =>
m.channelId === channelId &&
m.createdAt > since &&
m.authorId !== user.id
).length
}
async _unreadMap () {