fix(nests): don't teardown on wrapper Closed — let orchestrator reconnect
The cliff-detector recycle path emits Closed → Reconnecting → Connecting → Connected from the wrapper. The Closed branch was calling teardown(), which cancels cliffDetectorJob, announcesJob, and the wrapper itself, preventing the orchestrator from ever reopening the inner listener. Result pre-fix (visible in receiver log): cliff-detector fires after 4s of silence, teardown runs ~500ms later, wrapper never reopens, room permanently dead. User-initiated close goes through disconnect() / onCleared() which call teardown directly; the wrapper's subsequent Closed emission is redundant for those paths, so no-op'ing it is safe. UI still reflects Closed via state.toUiState(ui.connection). https://claude.ai/code/session_01UHN3fnXzWdj8UbSXnxSwwv
This commit is contained in:
+27
-4
@@ -883,11 +883,34 @@ class NestViewModel(
|
||||
// wait for a manual reconnect tap.
|
||||
}
|
||||
|
||||
// Server-initiated Closed: tear down stale
|
||||
// local state so any later user-driven reconnect
|
||||
// starts fresh.
|
||||
NestsListenerState.Closed -> {
|
||||
teardown(targetState = ConnectionUiState.Closed)
|
||||
// Closed from the wrapper is *almost always*
|
||||
// transient — the orchestrator emits Closed
|
||||
// → Reconnecting → Connecting → Connected
|
||||
// around every cliff-detector recycle and
|
||||
// every JWT refresh. We must NOT teardown
|
||||
// here: teardown cancels `cliffDetectorJob`,
|
||||
// `announcesJob`, etc., AND calls
|
||||
// `wrapper.close()`, which cancels the
|
||||
// wrapper's orchestrator before it can
|
||||
// reopen the inner listener. End result
|
||||
// pre-fix: the very first cliff-detector
|
||||
// recycle permanently kills the room
|
||||
// instead of recovering it (visible in the
|
||||
// 15:56:25 receiver log: cliff fires →
|
||||
// teardown fires 521 ms later → wrapper
|
||||
// never reopens → `cliff-detector EXITED
|
||||
// closed=false`).
|
||||
//
|
||||
// User-initiated close goes through
|
||||
// `disconnect()` / `onCleared()` which call
|
||||
// `teardown` directly; the wrapper's
|
||||
// subsequent Closed emission here is a
|
||||
// redundant signal — no-op'ing it doesn't
|
||||
// change anything for those paths. The UI
|
||||
// still picks up the Closed via
|
||||
// `state.toUiState(ui.connection)` above
|
||||
// for visual feedback.
|
||||
}
|
||||
|
||||
else -> { /* no extra side effect */ }
|
||||
|
||||
Reference in New Issue
Block a user