fix(homekit): only hang up when the last HomeKit session ends - #89
Open
atdr wants to merge 1 commit into
Open
Conversation
The stop handler ended the Twilio call whenever any streaming session stopped. HomeKit runs up to cameraStreamCount sessions at once and starts a second one when you move between the room view's camera tile and the full camera view, so a STOP routinely arrives while another session is still streaming. Observed on the production Pi: session ac5c8c21 stopping ended the call under session d332e46a, three seconds into a live stream. The call now ends only once activeSessions is empty. This predates the grace window, which merely delayed the same hangup by three seconds and made it legible in the journal. Before that it fired instantly and looked like the stream simply dying. tests/homekit-hangup-grace.test.cjs gains four cases driving _stopSession rather than scheduleHangUp. The existing cases could not have caught this: they cover when the timer fires, not whether it should have been set, and the fault was entirely in the latter. Reverting the session check fails the new multi-session case. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Rq7wnggNTrhwGMADfJ5yvf
atdr
added this pull request to stack #90
September 12, 2026 15:19
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
cameraStreamCountsessions at once and starts a second one when you move between the room view's camera tile and the full camera view, so this fires in ordinary use rather than in some corner case.activeSessionsis empty.Stacked on #88
This sits on top of
feat/hangup-grace-period. The bug predates that PR, but the grace window is what made it legible, so the two read best in order. Reviewing this diff alone shows the one-line condition plus its tests.What was actually happening
Caught on the production Pi running
2.2.0-beta.2:Session B stopping ended the call three seconds into session A's stream. From the phone it looked like the stream simply died shortly after opening.
This is not a regression from #88. Before the grace window the same STOP called
hangUpCallimmediately, so the call died the instant the second session ended, with nothing in the journal to say why. #88 delayed it by three seconds and gave it a name, which is how it was found at all. Thehangup-scheduledline naming asessionIdthat never bound a mulaw stream is what gave it away.Changes
homekit.js_stopSessiondeletes its own session from the map first, so an empty map means this was the last one and the user is genuinely finished. The comment records the observed session IDs so the next reader has the evidence rather than the assertion.tests/homekit-hangup-grace.test.cjsFour cases driving
_stopSessionrather thanscheduleHangUp:endHapSession(the caller-hung-up path) never hangs up, whatever is streaming_stopSessionandactiveSessionsare exported to make this reachable. Standing up two real SRTP sessions would test the HAP stack rather than this condition.Why the existing tests missed it
Worth stating, because it is the reusable lesson. #88's cases all drove
scheduleHangUpdirectly. That covers when the timer fires, and the fault was entirely in whether it should have been set at all. A test that starts one layer above the bug cannot see it, however thorough it is about everything below.The new cases enter through
_stopSession, which is where the decision lives. Reverting the condition toif (hangUp && activeCall)fails the multi-session case and passes the other eleven.Test Plan
typecheck,lint,format:check,check,test— 146 tests).npm run coveragepasses;homekit.jsrises to 42.26% lines and the project to 69.09%.2.2.0-beta.3published from this commit and deployed to the Pi:pairedClients4 before and after, probes green,activeSessions.size === 0confirmed present in the installed code.hangup-scheduledat that point, and exactly one when the last session goes.🤖 Generated with Claude Code
https://claude.ai/code/session_01Rq7wnggNTrhwGMADfJ5yvf