app/analysis_service.h

analyze a finished game and file the artifact (PLAN §5).

WHERE THIS RUNS IS THE WHOLE DESIGN. The Kirin engine keeps its state in GLOBALS — LinkedEngine wraps those globals, it does not own an instance of them (see linked_engine.h). So there is no such thing as a “private engine”, and analysis CANNOT be moved to a background thread: it would trample the search state of whatever game is being played. The review plan assumed otherwise; the code does not support it.

Instead this runs on the SESSION WORKER THREAD, from the recorder’s sink, at the one moment the engine is provably idle: the game just ended. GameSession serializes everything it does on that thread, so a new game requested mid-run simply queues behind the analysis rather than racing it — the safety comes from the threading model that already exists, not from a lock bolted onto it.

Analysis is still interruptible: cancel() (wired to “new game”) makes the analyzer give up between plies, so a player is never made to wait for a review they didn’t ask for.

namespace kirin
class AnalysisService
#include <analysis_service.h>

Public Functions

AnalysisService(GameStore &store, bool shareAnalyses = false, long nodesPerMove = GameAnalyzer::kDefaultNodes)
inline void setShareAnalyses(bool on)
bool analyzeAndStore(const GameRecord &rec)
inline void cancel()
inline void resetCancel()

Private Members

GameStore &store_
LinkedEngine engine_
GameAnalyzer analyzer_
std::atomic<bool> cancel_ = {false}
bool shareAnalyses_