summaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/adr/0001-gui-frontend-architecture.md89
-rw-r--r--docs/adr/0002-version-lockstep.md55
2 files changed, 144 insertions, 0 deletions
diff --git a/docs/adr/0001-gui-frontend-architecture.md b/docs/adr/0001-gui-frontend-architecture.md
new file mode 100644
index 0000000..44dca32
--- /dev/null
+++ b/docs/adr/0001-gui-frontend-architecture.md
@@ -0,0 +1,89 @@
1# 0001 — GUI is a second frontend over a shared core
2
3Status: accepted, 2026-11-01
4
5## Context
6
7The client is a terminal UI built around `ClientCore`, which is already
8headless and tested without a terminal (`tests/client_core.rs` drives it with a
9fake screen). The GUI must add a second presentation of the same product with
10these constraints:
11
12- Installed desktop application. No browser, no webview, no macOS.
13- Linux x86_64 and Windows x86_64, cross-compiled where possible; i686 stays
14 TUI-only. Windows 10 is the floor.
15- "Lightweight": ~40 MB binary, ~150 MB idle memory, ~1 s cold start.
16- Effects are tweened 2D animation: reels, wheel, cards, chips, particles, a
17 live crash curve. No 3D, no audio for now.
18- egui is chosen for rendering; the repository is GPL-3.0-or-later.
19
20The existing boundary is terminal-shaped: `Effect` carries lines of text,
21`handle_key` carries arrow keys, and `Game::render` returns a formatted board.
22None of it can be reused by a GUI as-is.
23
24## Decision
25
261. **One brain, two frontends.** `ClientCore` owns state, navigation, and
27 flows. Frontends send `Command` and render `View`. The TUI is the first
28 adapter and stays green throughout the refactor; roulette is ported first
29 because it has the largest UI surface.
302. **The boundary is semantic, not textual.** `Command` covers app flows
31 (connect, trust, login, play, leave) and game actions (`PlaceBet(BetTarget)`,
32 `Spin`, `Hit`, `CashOut`). `View` covers app screens
33 (`Connect`, `Trust`, `TrustMismatch`, `Login`, `Lobby`, `History`,
34 `Game(GameView)`) and per-game state (reels, felt with chips and cursor,
35 hand with legal actions, crash phase and multiplier).
363. **The core owns navigation.** Which screen is showing and which game is open
37 is state, not presentation; both frontends must behave identically.
384. **egui (eframe).** Immediate mode suits per-frame custom drawing; forms,
39 text input, and scrolling come free; MIT/Apache; ~10–20 MB. Slint was
40 rejected for its retained/declarative model, which fights per-frame drawing
41 of the crash curve and particles. Macroquad was rejected because every input
42 field and list would be hand-built. Webviews were rejected on memory and
43 system dependencies.
445. **A `gui/` workspace member.** The existing package keeps the core, TUI, and
45 server bins and all current test paths. egui's ~150 transitive crates must
46 never enter the TUI or server build graph — the same mistake as the
47 package-wide `native-tls` dependency.
486. **A blocking network thread with channels.** The core is I/O-free; the
49 adapter owns the TLS stream. One thread reads/writes, forwards every line,
50 and wakes the UI via `egui::Context::request_repaint`. No async runtime:
51 the protocol has one request in flight plus pushes. Request deadlines live
52 in the shared adapter so both frontends time out identically.
537. **First contact is explicit.** The handshake completes with a record-only
54 decision, then the adapter asks before sending anything. New key: modal with
55 the fingerprint. Changed key: hard stop with an explicit "forget and
56 reconnect". The TUI keeps its print-and-accept prompt via the same state
57 machine.
588. **Single-file binaries with embedded assets**, named
59 `zagan-bet-gui-<version>-<platform>-<arch>[.exe]`, plus bash/PowerShell
60 installers. The site lists both. No auto-update; the lobby points at the
61 download page when the server advertises a newer release.
62
63## Consequences
64
65- The client core is rewritten at its boundary before any GUI code exists:
66 `Effect`, the `Game` trait, and `handle_key` all change. This is the cost of
67 keeping one implementation of reserve/settle/forfeit and payout rules.
68- The TUI's terminal concerns (prompt editing, wheel animation, interactive
69 input) move into the TUI adapter, where they belong.
70- The GUI must be themed deliberately; egui's defaults look like a debug tool.
71 A style spike on one reference screen gates the game ports.
72- Windows binaries are unsigned; SmartScreen will warn until a certificate is
73 bought. No auto-update means players download again.
74- The refactor is testable headlessly: the TUI adapter and the core tests
75 remain the regression net, and `View` can be asserted without pixels.
76
77## Alternatives considered
78
79- **Separate GUI client** reusing only rules and protocol: faster to start,
80 duplicates connection/session/timeout flows and lets the two clients drift on
81 the invariants in `AGENTS.md`. Rejected.
82- **Hybrid: GUI reads `GameState` directly**: avoids the refactor but creates a
83 second parser of stringly-typed data, guaranteeing renderer drift. Rejected.
84- **Slint**: best declarative animation story and smallest runtime, but the
85 retained model is wrong for per-frame custom drawing. Rejected after the
86 license objection (GPL) was removed by open-sourcing.
87- **Tauri / webview**: easiest effects, but a system webview breaks the memory
88 budget and adds a distro-dependent dependency. Rejected.
89- **tokio**: no concurrency to exploit. Rejected.
diff --git a/docs/adr/0002-version-lockstep.md b/docs/adr/0002-version-lockstep.md
new file mode 100644
index 0000000..1e7f8ba
--- /dev/null
+++ b/docs/adr/0002-version-lockstep.md
@@ -0,0 +1,55 @@
1# 0002 — Client and server must share MAJOR.MINOR
2
3Status: accepted, 2026-11-01
4
5## Context
6
7`AGENTS.md` previously described MINOR as backwards compatible: an old client
8should work with a newer server and vice versa. In practice the wire format,
9game messages, and client flows have changed in every MINOR so far
10(`PLAY_START` payloads, `CRASH_*`, `HISTORY`, cursor and bet semantics). Silent
11half-compatibility produces confusing failures: a new client sends a command
12the old server echoes back as text, or an old client misparses a new field.
13
14The project now ships multiple frontends (TUI and GUI) and a server, all
15released together from one repository.
16
17## Decision
18
191. **Version compatibility is MAJOR.MINOR lockstep.** A client and server may
20 differ only in PATCH. Any difference in MAJOR or MINOR refuses the
21 connection.
222. **The first line after the TLS handshake is `HELLO <version>`.** The server
23 replies with its own version, the latest release version, and the download
24 URL. Any other message before `HELLO` is rejected. No credentials are sent
25 before the versions agree.
263. **The server is authoritative about the latest release.** It advertises
27 `latest` and the download URL in the handshake; the client compares its own
28 `CARGO_PKG_VERSION` and offers a link when it is behind. The download site
29 is not queried by clients: that would add a second TLS stack and a web PKI
30 trust domain for one string.
314. **A MAJOR bump covers a wire change; a MINOR bump covers a feature that
32 changes the protocol or the shared semantics.** Both require releasing
33 clients and server together.
34
35## Consequences
36
37- Every MINOR release must update the server and all clients simultaneously;
38 a stale server is a hard failure, not a degraded experience. Deployment order
39 matters.
40- `AGENTS.md`'s MINOR rule is rewritten; the old "old clients work with new
41 servers" promise is withdrawn.
42- The handshake is itself a breaking wire change: this lands as v4.0.0.
43- The update check needs no extra dependency and works for both frontends, at
44 the cost of only being as fresh as the server you connect to.
45
46## Alternatives considered
47
48- **Keep MINOR backwards compatible** and negotiate per-feature: more work,
49 and every feature so far would have needed a capability flag. Rejected.
50- **Fetch `version.json` from the download site**: site-authoritative updates,
51 but adds an HTTP client and a CA trust store with different rules from the
52 pinned game server. Rejected.
53- **Semver-range matching**: allows broader compatibility but makes the
54 failure modes depend on which optional features each side implemented.
55 Rejected for a small, tightly released product.