feat(call-to-play)!: coordinate game sessions across peers

Implement the launcher design as a production peer-to-peer feature. Call to
Play actions are immutable, validated events broadcast over the existing QUIC
control channel, deduplicated in a bounded in-memory history, and exchanged in
Hello/HelloAck so late joiners reconstruct current calls.

Add the Tauri bridge and modular launcher surfaces for play-now and scheduled
calls, check-in, readiness buffers, role-aware controls, chat, tickers, and
actual caller launch. A deterministic frontend reducer derives presentation
state from replicated history. Extend the JSONL peer harness with publish/list
commands and a three-peer live-delivery and late-join scenario.

This intentionally raises the only supported wire protocol from version 5 to
version 6; older builds are not supported. Document the transport architecture
and exclude generated peer-test state from Docker build contexts.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed
- `just frontend-test` -- passed, 20 tests
- `just build` -- passed
- `just peer-cli-tests S2 S48` -- passed
- `git diff --cached --check` -- passed
This commit is contained in:
2026-07-21 22:30:11 +02:00
parent 8f151e38b4
commit 0f53bc4b78
31 changed files with 3032 additions and 21 deletions
+10 -10
View File
@@ -548,7 +548,7 @@ The `useNominations({ username, seed })` hook owns the list and exposes
`createNomination`, `respond`, `rsvp`, `sendMessage`, `leave`, `cancel`,
`startNow`, `addTime`.
### Mock vs production
### Design reference vs production
The mock **simulates other people** with a 1-second `setInterval`
(`tickNomination`): bots RSVP to scheduled calls, ready-up during check-in, walk
@@ -558,14 +558,14 @@ The mock also seeds a few representative calls on mount (a live call with chat,
a fresh call you started, a scheduled call whose check-in window just opened,
and one scheduled for later collecting RSVPs).
**In production, replace the simulation with a real-time LAN transport:** the
launcher instances broadcast nominations, responses, RSVPs, and chat messages to
each other (whatever the app uses — a small pub/sub over the LAN, a lightweight
signaling server, or Tauri-side networking). Swap the guts of `useNominations`
(the `setInterval` + local `setNoms`) for your networking layer that pushes the
same state shape; the rendering components need nothing else. The `username` that
identifies "you" comes from `settings.username` (the Profile setting), not a
prop default.
The production launcher uses the peer's existing QUIC control channel. Each
create, response, RSVP, chat, leave, cancel, start, or deadline-extension action
is an immutable, uniquely identified event. Connected peers receive new events
immediately, while `Hello` / `HelloAck` exchange the bounded, deduplicated event
history so a late joiner reconstructs the same calls. The frontend reducer turns
that event history into the `Nomination` state above and derives time-based phase
changes locally. The `username` that identifies "you" comes from
`settings.username` (the Profile setting), not a prop default.
---
@@ -773,5 +773,5 @@ To preview the design in a browser:
- **Progress state** — designed. See "Download progress" section above. The action-button slot is swapped for a live `DownloadProgress` component (card + modal variants with container-query fallback for narrow tiles). Wire it to your real progress events; the rendering layer is dev-ready.
- **Keyboard arrow nav** — arrow keys should move focus between cards in the grid; not implemented in the mock but mentioned as a goal.
- **"Server running" state** — once Start Server actually spawns a process, the button should switch to a *running* state (live indicator dot + "Server running" label + click-to-stop). Not designed this round — flag for follow-up alongside whatever server-status panel the app grows.
- **Call to Play real-time transport** — the feature is fully designed and interactive, but the mock fakes other players with a local `setInterval` simulation. Production needs a real LAN transport that broadcasts nominations / responses / RSVPs / chat between launcher instances and pushes the same state shape into `useNominations`. Notifications when a call you're in enters its check-in window (OS notification / tray) are also a follow-up.
- **Call to Play notifications** — real-time LAN transport is implemented. OS / tray notifications when a call you're in enters its check-in window remain a follow-up.
- **German translations** — the language toggle is wired in Settings, but the catalog of translated UI strings hasn't been compiled. Stand up `react-i18next` (or equivalent) and seed `en.json` from the existing copy; `de.json` is a translation task for whoever owns localization.