# Em que estado minha conexão está, e o que vem depois? [#em-que-estado-minha-conexão-está-e-o-que-vem-depois] > Pergunta: "em que estado minha conexão está, e o que vem depois?" ## Dois eixos, nunca achatados [#dois-eixos-nunca-achatados] **Guest (`RoomSessionStateMachine`, `guest.getStatus()`)** tem dois eixos independentes: * **`transport`**: `offline` → `connecting` → `online` (e `retrying` no meio de uma reconexão). Nada aqui é terminal — `offline` é descanso, não morte. * **`membership`**: `unassociated` → `associating` → (`awaiting_approval` só quando o accessMode exige) → `member` → **`ended`** (terminal, único, com `reason`). **Host (`HostTransportStateMachine`, `host.transport`)** só tem o eixo `transport` — não existe eixo `membership` no host, e portanto não existe `ended` nele por tipo, não só por recusa em runtime. O fim de vida do host é outra coisa: destruição do **objeto** via `host.close()` (ver [receita-microfone.md](/pt/docs/event-room/latest/markdown/receita-microfone)), não um valor neste eixo. ## Os 9 `reason` de `ended` (guest) [#os-9-reason-de-ended-guest] | `reason` | O que aconteceu | | --------------------------- | ---------------------------------------------------------------------------------- | | `left` | `guest.close()` — saída explícita | | `room_closed` | O host encerrou a sala (`room.close()`) | | `room_expired` | A sala expirou no servidor | | `creator_replaced` | (nunca alcançado pelo guest — ver assimetria abaixo) | | `rejected` | Segunda rejeição consecutiva de aprovação | | `idle_timeout` | Conexão ociosa sem associação, servidor fechou | | `control_lost` | (eixo do host — ver `HostConnection#resume`, não chega ao guest) | | `contract_mismatch` | Fingerprint do contrato divergiu do peer (mesmo nome, formas concretas diferentes) | | `protocol_version_mismatch` | `protocolVersion` do peer é diferente do seu | ## Assimetria: `contract_mismatch` e `protocol_version_mismatch` terminam o guest, não o host [#assimetria-contract_mismatch-e-protocol_version_mismatch-terminam-o-guest-não-o-host] Não existe verbo de servidor para expulsar um guest já admitido — por isso só o **guest** alcança esses dois `reason`. O **host sobrevive**, na mesma sala, com o mesmo QR: um guest com contrato ou versão divergente termina sozinho (`ended{reason}`), e o host segue aceitando outros guests normalmente. Ver [versionamento-e-deploy.md](/pt/docs/event-room/latest/markdown/versionamento-e-deploy) para a tabela de compatibilidade completa. ## Observações não-terminais (nunca silenciadas, nunca encerram nada) [#observações-não-terminais-nunca-silenciadas-nunca-encerram-nada] `invalid_join_code`, `payload_too_large`, `bad_message`, `service_unavailable`, `occupancy_limit_not_honored` e qualquer código desconhecido chegam como `{code, known}` pelo canal de observação (`room.onObservation`/equivalente do guest) — nunca terminam a sessão sozinhos, nunca são engolidos em silêncio. ## Quando reconectar faz sentido vs. quando é sempre adesão nova [#quando-reconectar-faz-sentido-vs-quando-é-sempre-adesão-nova] * **Host**: uma queda de transporte com sala ainda viva dispara reconexão automática e invisível (`resume_creator`, usando o `creatorToken` em memória) — o app não vê nada acontecer, a menos que a retomada falhe de verdade (`control_lost`, sem retry). Entre salas (host sem sala aberta), o transporte tem prazo de 30s ocioso antes de cair; `startRoom()` depois disso reconecta de forma transparente. * **Guest**: não existe retomada — uma queda de transporte no meio de uma sessão de guest é sempre uma nova chamada a `joinRoom`, sujeita a uma nova aprovação se o accessMode exigir. ## Exibição de um único indicador [#exibição-de-um-único-indicador] `deriveDisplayStatus(status)` reduz os dois eixos a um único valor para exibição (nunca fonte de verdade para lógica de controle — quem precisa dos dois eixos lê `getStatus()` direto).