fix(server): scope accept-rollback terminal to the acceptor only

Code-review catch: the Path-2 accept-rollback previously emitted
dm_call_undeliverable { terminal: true } via sendToFederatedCallUsers,
which broadcasts to every ringedUserIds entry. In a group DM this
would prematurely tear down non-accepting ringees whose own accept /
reject / timeout paths should govern their state. Switch to
sendToUser(acceptorId) so only the acting user gets the terminal
signal. Reorder the clearFederatedCall to happen before the emit so a
concurrent end-handler sees a cleared entry (clearFederatedCall is
idempotent). Spec updated, test extended to assert the scoping with a
two-ringee group-DM fixture.
This commit is contained in:
Jannis Braun
2026-04-23 23:38:31 +02:00
parent 1719e6d580
commit 1e59e7012c
2 changed files with 29 additions and 10 deletions
+6 -2
View File
@@ -1563,7 +1563,12 @@ async function handleDmCallAccept(event: Record<string, unknown>, userId: string
if (!result.ok) {
console.error(`[federation] dm_call_accept relay to ${fedCall.federatedCallHost} failed (${result.reason}): ${result.error}`);
const failure = buildFailureFromResult(result, fedCall.federatedCallHost, db);
connectionManager.sendToFederatedCallUsers(fedCall.federatedId, {
// Clear first so a concurrent end-handler sees a cleared entry (idempotent).
connectionManager.clearFederatedCall(fedCall.federatedId);
// Terminal targets ONLY the acceptor — other ringed users (group DM) didn't
// accept and should stay in their ring state; their own dm_call_end / timeout
// paths govern their teardown.
connectionManager.sendToUser(userId, {
type: 'dm_call_undeliverable',
dmChannelId: fedCall.dmChannelId,
federatedCallId: fedCall.federatedId,
@@ -1571,7 +1576,6 @@ async function handleDmCallAccept(event: Record<string, unknown>, userId: string
phase: 'accept',
failures: [failure],
});
connectionManager.clearFederatedCall(fedCall.federatedId);
}
return;
}