fix(correctness): call-join reset on embed swap + per-path notify dedupe
COR-2 (useCallEmbed): useCallJoined only reset `joined` when the embed became
undefined. Answering a 2nd call swaps the embed A->B directly (embed stays
truthy), so `joined` stayed true and call B rendered as already-joined,
skipping the loading/watchdog UI. Re-seed from `embed?.joined ?? false` on
every embed identity change.
COR-4 (ClientNonUIFeatures): the notify-dedupe used one Map<roomId,eventId>
slot shared by the main-timeline and per-thread paths, so a thread reply
overwrote the room's slot and a re-fired main message (decrypt/edit re-emit,
common in E2EE) then mismatched and double-notified. Key the slot by
`${roomId}|${threadId ?? 'main'}` so each path dedupes independently.
Both verified correct by two review passes (no missed-notification or
missed-join regressions).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -149,9 +149,11 @@ export const useCallJoined = (embed?: CallEmbed): boolean => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!embed) {
|
||||
setJoined(false);
|
||||
}
|
||||
// Re-seed from the (new) embed whenever it changes identity, not only when
|
||||
// it becomes undefined. Answering a 2nd call swaps embed A→B directly (embed
|
||||
// stays truthy), so a plain `if (!embed)` reset left `joined` stuck true and
|
||||
// B rendered as already-joined, skipping the loading/watchdog UI.
|
||||
setJoined(embed?.joined ?? false);
|
||||
}, [embed]);
|
||||
|
||||
return joined;
|
||||
|
||||
Reference in New Issue
Block a user