# 0001: Testable client and server cores Status: Accepted (2026-10-28) ## Context The client and server started as binaries with their game logic and I/O mixed together. That made the TUI hard to reason about: a spin appended results below the board, a later bet change redrew at the wrong line, and none of it could be tested without a terminal. The server handler had the same problem: it owned static database and session state, so its security-sensitive paths could not be exercised from `tests/`. ## Decision - The library (`src/lib.rs`) owns shared logic. `src/bin/client` and `src/bin/server` are thin adapters for crossterm, TLS, environment variables, and interactive prompts. - `client::core::ClientCore` owns commands, game state, the current screen, and pending replies. It returns `Effect`s (`Print`, `Render(View)`, `ClearRegion`, `SendLine`, `Disconnect`, `Quit`). The binary applies them; the tests apply them to a headless screen. The prompt buffer, history and key mapping live in `client::input`, and `client::shell` parses a finished line, so the core never sees a `Key` or a raw command line. - `server::core::ServerCore` owns message handling and receives an injected `Connection`, `GameRegistry`, and bcrypt cost. The binary only owns the TLS listener and per-connection thread. - Tests live in `tests/` and exercise the library. Pure UI math is tested directly; terminal ANSI output is checked manually with `docs/TESTING.md`. There are no PTY tests because they cannot cover Windows and `RULES.md` requires identical behaviour on all platforms. - The client keeps sending its SHA-256 credential. The server stores `bcrypt(credential)` and upgrades legacy SHA-256 rows on the first successful login. This protects a stolen server database without changing the wire protocol, but the client-side credential remains replayable if `client.db` leaks. - Each settled spin writes a durable `plays` row in the same transaction as the balance updates. The in-memory session is a transient guard and is removed as soon as the spin settles or fails. ## Consequences - Client flows and server security rules are testable without a terminal or a network. A visual bug becomes an assertion about the headless screen. - The binaries have an extra translation layer (`Effect` application), and the server opens a SQLite connection per client. - Terminal rendering still needs a manual Linux/Windows pass; the checklist is in `docs/TESTING.md`. - Password storage is stronger, but not a full PAKE. A future MAJOR protocol change can replace the replayable credential.