"""WebSocket server, connection registry, and frame routing. Runs on the gateway's asyncio loop (started in ``AndroidAdapter.connect()``). Uses the ``websockets`` core dep (v15): ``websockets.serve(handler, host, port, ssl=ctx)``. Per-connection handler: 1. Await first frame; must be ``hello {token, device_id, device_name, caps, fcm_token?}``. Verify token (constant-time) + allowlist. On failure: send ``error {code:"auth"}`` and close. 2. On success: register in the connection registry (``device_id -> {ws, caps, fcm_token}``), send ``hello.ack {server_caps, sync_cursor, channels[]}``. 3. Loop: decode frames, dispatch to adapter inbound handlers. 4. On close: deregister; if no devices remain, ensure pending outbox frames have push fired. Routing: ``emit(chat_id, frame)`` broadcasts to ALL connected devices (single-user model). Heartbeat via WS ping/pong + app-level ping/pong. Backpressure: bounded per-connection send queue; coalesce ``message.update`` under pressure, never drop ``message``/``tool.end``/``notification``. Milestone M1. """