app/broadcast_session.h

mirror a live tournament game on the board

                  (broadcast-docs/PLAN.md §3, B2).
The Lichess broadcast stream does not send moves. It sends the entire PGN of a game, again, every time that game changes (PLAN §1.3). So this class is not a move consumer; it is a diff engine. Each update is compared against what is already loaded, and the difference is driven onto the physical board.

That framing is what makes the hard case fall out for free. Broadcast relays are operated by humans typing moves at a venue, and they retroactively correct mistakes — a game that read 24. Nf3 a minute ago can read 24. Nd2 now. A delta protocol would need a retraction message. A whole-game feed just sends the corrected game, and a diff notices that it stopped agreeing at ply 47.

Which is why this composes ReviewSession rather than replaying forward: undoing a physical move — routing a captured piece back out of storage and onto its square — is the genuinely hard part, and review already does it correctly and under test. A correction is jumpToPly(k) + truncateTo(k) + appendMoves.

Catch-up is likewise inherited rather than invented: when moves land faster than the gantry can execute them, this never queues them one at a time — it re-targets the cursor at the tip and lets jumpToPly decide. Past kJumpStepThreshold that is one direct board setup instead of an unbounded backlog of individual moves, so falling behind degrades into a single catch-up operation. The same property makes a deep correction cheap.

Pure: no network. Whoever owns the socket parses PGN (pgn.h) and hands games in.

namespace kirin

Enums

enum class MirrorRefusal

Values:

enumerator None
enumerator NotStandardVariant
enumerator BoardPrepFailed
class BroadcastSession
#include <broadcast_session.h>

Public Functions

BroadcastSession(IEngine &engine, IBoardBackend &backend)
bool follow(const PgnGame &game, ResetMode resetMode = ResetMode::Hand)
BroadcastUpdate update(const PgnGame &game)
void stop()
inline bool following() const
inline MirrorRefusal refusal() const
inline const std::string &key() const
inline const std::string &white() const
inline const std::string &black() const
inline const std::string &whiteClock() const
inline const std::string &blackClock() const
inline const std::string &result() const
inline bool finished() const
inline const ReviewSession &review() const
inline ReviewSession &review()

Private Functions

std::vector<std::string> toUci(const std::vector<PgnMove> &moves) const
void adoptMetadata(const PgnGame &game)

Private Members

IEngine &engine_
ReviewSession review_
bool following_ = false
MirrorRefusal refusal_ = MirrorRefusal::None
std::string key_
std::string white_
std::string black_
std::string whiteClock_
std::string blackClock_
std::string result_
struct BroadcastUpdate
#include <broadcast_session.h>

Public Members

bool ok = true
bool ignored = false
int appended = 0
int rewoundTo = -1
int plyCount = 0