# chanora_state Authoritative client-side mirror of server state: channel tree, client list, and connection lifecycle. Owns the reducers that fold protocol events into state and produce deltas for the bridge (per SAD §7.2 and SDD §5). ## Architecture ### Core reducer pattern The crate exposes a single `reduce(state: &mut Option, event: StateEvent) -> Reduction` function. Callers own state storage and pass it by `&mut`. The reducer returns a `Reduction` containing only the emitted `Delta` values. This satisfies: - **SRS-056** — deterministic deltas: the same `(state, event)` always produces the same `Reduction` - **SRS-057** — per-connection ordering - **SRS-058** — reducer functions are pure ### Module: `channel_join` A more specialized reducer for voice-channel join/leave state tracking with: - Optimistic `UserJoinRequested` events - `AuthoritativeSelfMove` confirmation from live deltas - `SnapshotReady` reconciliation after connects/reconnects - `ChannelJoinProjection` for UI rendering (in_channel, can_join, can_leave, sync_state) - `ConnectionEpoch` tracking to disambiguate stale events across reconnects ### State model - `ServerState` — owned `HashMap` and `HashMap` with stable ordering vectors. Built from `ServerSnapshot`, updated incrementally via `StateEvent`s. - `ConnectionState` — enum: Idle / Connecting / Ready / Reconnecting / Lost ## Public API Summary ### Types | Type | Role | |---|---| | `ServerState` | Authoritative mirror of connected server state | | `ConnectionState` | Lifecycle enum (Idle, Connecting, Ready, Reconnecting, Lost) | | `StateEvent` | Protocol-layer input events (Snapshot, ChannelChanged, ClientChanged, etc.) | | `Delta` | Bridge output events (SnapshotApplied, ChannelUpserted, ClientRemoved, etc.) | | `Reduction` | Result of `reduce()`: a `Vec` | | `StateError` | Reducer errors (Unknown entity, invariant violation) | ### Key functions - `reduce(state, event)` → `Reduction` — apply a protocol event, return deltas - `reduce_reconnect_snapshot(state, snap)` → `Reduction` — replace all state on reconnect (SRS-059) ### `ServerState` methods - `channel(id)` / `client(id)` — lookup by id - `channels()` / `clients()` — ordered iterators - `own_channel()` — the channel our client is in - `clients_in_channel(channel_id)` — filtered iterator ### `channel_join` module - `reduce(state, event)` → `JoinReduction` — channel-join state machine - `project(state)` → `ChannelJoinProjection` — UI-ready snapshot - `ChannelJoinEvent`, `ChannelJoinState`, `ChannelJoinProjection` — state machine types ## Design notes - Events are ignored when state is `None` (disconnected), except `Snapshot` (creates state) and `ConnectionChanged`. - Deleting a channel also removes all clients in that channel. - Duplicate IDs in snapshots are deduplicated deterministically.