fix(threads): review-wave fixes for per-thread notifications

- useRoomsListener now PREPENDS the emitting Room (was appended): the SDK emits
  RoomEvent.UnreadNotifications with VARIABLE arity (0/1/2 args), so a trailing
  extra arg landed in the wrong positional slot on the most common room-count
  sync path — room.isSpaceRoom() threw inside the SDK emit loop and the badge
  PUT never ran. Both consumers updated (CONFIRMED HIGH review finding).
- roomToUnread: SpaceChild RESET now passes the thread prefs so muted-thread
  subtraction survives space-child state changes.

Reviewer also verified: badge subtraction math exact (no double-subtraction),
encrypted thread replies caught by the timeline guard (m.relates_to is
cleartext), fresh prefs flow to handlers, single-owner wiring load-bearing.
Documented-acceptable: hasCurrentUserParticipated can lag until the server
bundle refreshes after your first reply; dedupe maps grow per-session only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-01 22:53:32 -04:00
parent 501d493ca4
commit 0adce52d37
3 changed files with 20 additions and 20 deletions
+6 -4
View File
@@ -6,6 +6,7 @@ import {
Room,
RoomEvent,
RoomEventHandlerMap,
Thread,
ThreadEvent,
} from 'matrix-js-sdk';
import { focusAssistActiveAtom } from '../../state/focusAssist';
@@ -446,8 +447,10 @@ function MessageNotifications() {
};
}, [mx, notificationSelected, selectedRoomId, deliverNotification]);
const handleNewReply = useCallback<RoomEventHandlerMap[ThreadEvent.NewReply]>(
(thread, mEvent) => {
const handleNewReply = useCallback(
// useRoomsListener prepends the emitting Room; the thread's own room lookup
// below is kept as the authority (identical object in practice).
(_room: Room, thread: Thread, mEvent: MatrixEvent) => {
if (mx.getSyncState() !== 'SYNCING') return;
const room = mx.getRoom(thread.roomId);
if (!room || room.isSpaceRoom()) return;
@@ -457,8 +460,7 @@ function MessageNotifications() {
// Suppress when the user is actively looking at this thread (or the inbox).
if (
document.hasFocus() &&
(notificationSelected ||
(selectedRoomId === thread.roomId && activeThreadId === thread.id))
(notificationSelected || (selectedRoomId === thread.roomId && activeThreadId === thread.id))
) {
return;
}