Fixes#46. This is likely the "everyone dropped out of the call" part of the 2026-09-29 incident.
LocalMember sized maximumNetworkErrorRetryCount to min(sync_disconnect_grace_period_ms, delayed_leave_event_delay_ms), which is 10 s with the defaults. During a homeserver stall each delayed-leave restart times out locally after 2 s, so the retries ran out 20–35 s in, and the call showed "Connection lost", even though production's server keeps the membership for 60 s (delayed_leave_event_delay_ms: 60000).
Change: size it to max(grace, leaveDelay), i.e. the server's delayed-leave window. The embedded call has no /sync loop of its own for the grace period to describe, and the server's delayed leave is what actually ends the membership.
Verified in Lotus with production's call config routed in (delayed_leave_event_delay_ms: 60000, delayed_leave_event_restart_ms: 15000), in a call with Synapse frozen (SIGSTOP) for 40 s:
Before (pinned lotus.22): frame "Connection lost" at 40 s, and the call did not come back after resume.
After:no "Connection lost" during the stall, and the call is fine after resume.
Longer stalls (past the leave window) still end the call. With #50 and cinny #318's host half, the host then shows "Call disconnected" and reconnects once sync is back.
tsc and oxlint are clean. The localMember unit tests fail identically with and without this change: 18 failures from Promise.withResolvers is not a function on this machine's Node 20. CI's Node should run them.
Fixes #46. This is likely the "everyone dropped out of the call" part of the 2026-09-29 incident.
`LocalMember` sized `maximumNetworkErrorRetryCount` to `min(sync_disconnect_grace_period_ms, delayed_leave_event_delay_ms)`, which is **10 s** with the defaults. During a homeserver stall each delayed-leave restart times out locally after 2 s, so the retries ran out **20–35 s** in, and the call showed "Connection lost", even though production's server keeps the membership for **60 s** (`delayed_leave_event_delay_ms: 60000`).
**Change:** size it to `max(grace, leaveDelay)`, i.e. the server's delayed-leave window. The embedded call has no `/sync` loop of its own for the grace period to describe, and the server's delayed leave is what actually ends the membership.
**Verified** in Lotus with production's call config routed in (`delayed_leave_event_delay_ms: 60000`, `delayed_leave_event_restart_ms: 15000`), in a call with Synapse frozen (`SIGSTOP`) for 40 s:
- **Before** (pinned lotus.22): frame **"Connection lost" at 40 s**, and the call did not come back after resume.
- **After:** **no "Connection lost"** during the stall, and the call is fine after resume.
Longer stalls (past the leave window) still end the call. With #50 and cinny #318's host half, the host then shows "Call disconnected" and reconnects once sync is back.
`tsc` and oxlint are clean. The `localMember` unit tests fail identically with and without this change: 18 failures from `Promise.withResolvers is not a function` on this machine's Node 20. CI's Node should run them.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
maximumNetworkErrorRetryCount was sized to min(sync grace period,
leave delay), i.e. 10 s, so the membership manager gave up 20-35 s into
a homeserver stall and showed "Connection lost", even when the server
would keep the membership for 60 s (prod config). Size it to the leave
delay instead: the embedded call has no /sync loop for the grace period
to describe, and the server's delayed leave is what actually ends the
membership.
Fixes#46
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
jared
merged commit 4be3e92eb6 into lotus2026-10-18 04:52:15 -04:00
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.
Fixes #46. This is likely the "everyone dropped out of the call" part of the 2026-09-29 incident.
LocalMembersizedmaximumNetworkErrorRetryCounttomin(sync_disconnect_grace_period_ms, delayed_leave_event_delay_ms), which is 10 s with the defaults. During a homeserver stall each delayed-leave restart times out locally after 2 s, so the retries ran out 20–35 s in, and the call showed "Connection lost", even though production's server keeps the membership for 60 s (delayed_leave_event_delay_ms: 60000).Change: size it to
max(grace, leaveDelay), i.e. the server's delayed-leave window. The embedded call has no/syncloop of its own for the grace period to describe, and the server's delayed leave is what actually ends the membership.Verified in Lotus with production's call config routed in (
delayed_leave_event_delay_ms: 60000,delayed_leave_event_restart_ms: 15000), in a call with Synapse frozen (SIGSTOP) for 40 s:Longer stalls (past the leave window) still end the call. With #50 and cinny #318's host half, the host then shows "Call disconnected" and reconnects once sync is back.
tscand oxlint are clean. ThelocalMemberunit tests fail identically with and without this change: 18 failures fromPromise.withResolvers is not a functionon this machine's Node 20. CI's Node should run them.🤖 Generated with Claude Code
https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5