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.
|
// wait for a manual reconnect tap.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server-initiated Closed: tear down stale
|
|
||||||
// local state so any later user-driven reconnect
|
|
||||||
// starts fresh.
|
|
||||||
NestsListenerState.Closed -> {
|
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 */ }
|
else -> { /* no extra side effect */ }
|
||||||
|
|||||||
Reference in New Issue
Block a user