With one account on two devices, both ring. Answer on one and the other keeps ringing, because nothing tells it. When its ring guard fired it sent the caller an end with reason timeout, and the caller hung up the call in progress. This got much more likely with the iPad build, where one account on a phone and a tablet is the normal case.
Ring guard: releases the ring locally and sends nothing. The caller gives up on its own dial timer long before this fires, so the message was redundant, and on a shared account it was destructive.
End handler: it did not check the call id at all, so any end for any call hung up whatever was current. It now requires the call id to match, and once a call has connected it ignores an end whose reason means the ring was never picked up (declined, busy, timeout). Those can only have come from another device that was ringing: someone silencing it, or a build already in people's hands that still announces its timeout. A plain hang-up carries no such reason and still ends the call.
SecondDeviceCallTest guards both halves where Android CI actually runs it. The iPhone test reads this file too, but only when the checkouts sit side by side under the names it expects, which no CI build directory has. Proven able to fail: both checks fail against the code before the fix.
Not observed on two real devices yet; found by reading the signalling path end to end. JVM suites: 1294 tests, 0 failures.
With one account on two devices, both ring. Answer on one and the other keeps ringing, because nothing tells it. When its ring guard fired it sent the caller an end with reason `timeout`, and the caller **hung up the call in progress**. This got much more likely with the iPad build, where one account on a phone and a tablet is the normal case.
**Ring guard:** releases the ring locally and sends nothing. The caller gives up on its own dial timer long before this fires, so the message was redundant, and on a shared account it was destructive.
**End handler:** it did not check the call id at all, so any end for any call hung up whatever was current. It now requires the call id to match, and once a call has connected it ignores an end whose reason means the ring was never picked up (`declined`, `busy`, `timeout`). Those can only have come from another device that was ringing: someone silencing it, or a build already in people's hands that still announces its timeout. A plain hang-up carries no such reason and still ends the call.
`SecondDeviceCallTest` guards both halves where Android CI actually runs it. The iPhone test reads this file too, but only when the checkouts sit side by side under the names it expects, which no CI build directory has. Proven able to fail: both checks fail against the code before the fix.
Not observed on two real devices yet; found by reading the signalling path end to end. JVM suites: **1294 tests, 0 failures**.
The iPhone half is the same fix in its own MR.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
With one account on two devices, both ring. Answer on one and the other keeps ringing, because nothing tells it. When its ring guard fired it sent the caller an end with reason
timeout, and the caller hung up the call in progress. This got much more likely with the iPad build, where one account on a phone and a tablet is the normal case.Ring guard: releases the ring locally and sends nothing. The caller gives up on its own dial timer long before this fires, so the message was redundant, and on a shared account it was destructive.
End handler: it did not check the call id at all, so any end for any call hung up whatever was current. It now requires the call id to match, and once a call has connected it ignores an end whose reason means the ring was never picked up (
declined,busy,timeout). Those can only have come from another device that was ringing: someone silencing it, or a build already in people's hands that still announces its timeout. A plain hang-up carries no such reason and still ends the call.SecondDeviceCallTestguards both halves where Android CI actually runs it. The iPhone test reads this file too, but only when the checkouts sit side by side under the names it expects, which no CI build directory has. Proven able to fail: both checks fail against the code before the fix.Not observed on two real devices yet; found by reading the signalling path end to end. JVM suites: 1294 tests, 0 failures.
The iPhone half is the same fix in its own MR.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
🤖 Generated with Claude Code
mentioned in commit
9e8c1005fe