Skip to content

Add live telemetry dashboard and batch-simulation automation - #16

Open
DanielFourman wants to merge 8 commits into
RedHat-Israel:mainfrom
DanielFourman:hackathon
Open

Add live telemetry dashboard and batch-simulation automation#16
DanielFourman wants to merge 8 commits into
RedHat-Israel:mainfrom
DanielFourman:hackathon

Conversation

@DanielFourman

@DanielFourman DanielFourman commented Jul 16, 2026

Copy link
Copy Markdown

Summary

  • Per-obstacle outcome tracking on Player: wall_hits, water_hits, crack_hits added alongside the existing success counters, and misses is now actually incremented on a missed penguin (previously declared but dead) — this is what lets the telemetry UI show true success/total ratios instead of always 100%.
  • Removed the coin/jackpot obstacle mechanic entirely (COIN, coins_for_jackpot, score_jackpot, and its scoring branch).
  • LiveSink (telemetry): finished-round results now include full per-player state and duration_seconds; a round-numbering fix lets "Clear history" reset the displayed round count without disturbing the internal counter batch-polling relies on.
  • New headless batch simulation: rose/engine/simulate.py (run_single_game/run_batch/_aggregate) plus a root-level simulate.py CLI (python simulate.py --drivers A B --games 50 --output stats.json), documented in the README.
  • New /simulate (POST) and /simulate/{job_id} (GET) endpoints: start a batch job and poll it. _run_live_batch() drives the games through the same shared game loop a human's Reset+Run would use, so a batch run plays out live on the main game screen.
  • New rose/telemetry/observer.py: the TelemetryObserver/NullObserver/CompositeObserver interface both the live dashboard and automation are built on.
  • Small unrelated fix: Dockerfile's CMD referenced rose/main.py, which hasn't existed for 2 years — corrected to main.py.

Test plan

  • pytest — 75/75 passing (fixed one pre-existing hang: test_simulate_job_runs_in_background_and_completes never started the background game loop the /simulate endpoint depends on, so it polled forever; now starts/cancels logic.game_loop() for the test's duration, matching what server.run() does in production)
  • flake8 / black --check — no new issues (pre-existing warnings confirmed present in the pre-change baseline too)
  • radon cc — no complexity regression
  • Live end-to-end smoke test against running containers: POSTed /simulate with two real driver processes, polled to completion, verified aggregated results; confirmed /telemetry and the dashboard both serve real per-obstacle ratios during live play

🤖 Generated with Claude Code

DanielFourman and others added 7 commits July 15, 2026 12:32
Adds a telemetry package (observer + sinks) wired into the live game
loop, new /telemetry, /simulate, /simulate/{job_id} server routes, and
a simulate.py CLI for running batch games between two drivers without
the websocket/UI rate throttle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Coins are worthless individually; collecting exactly
config.coins_for_jackpot (5) awards a one-time config.score_jackpot
(50) bonus. Coins collected beyond that grant no further bonus.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Splits the blended hits/pickups counters into per-obstacle success/fail/miss
data the redesigned telemetry dashboard needs: wall_hits, water_hits,
crack_hits, coin_misses, and a finally-wired-up misses (penguin miss was
tracked in the field but never incremented). Also exposes a `running` flag
and `total_finished` round count on GET/POST /telemetry(/clear), and attaches
each player's full end-of-game state to game results so "Recent games" can
show a real per-driver stat breakdown instead of just final score.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds duration_seconds to the game-end result (both the live loop and
the headless simulate.py path), timed from round start to round end.
Meaningful mainly for the headless/automation path, where rounds run
back-to-back as fast as the drivers respond rather than on a fixed
wall-clock cadence.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Coins are gone from the game, matching upstream RedHat-Israel/rose-game-engine:
no COIN obstacle, no coins_for_jackpot/score_jackpot config, no coin/coin_misses
player counters, no coin scoring branch. Kept everything else added since
(wall_hits/water_hits/crack_hits/misses fix, running flag, duration_seconds,
players-in-result) since none of that is coin-specific.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Clear history previously left the round count monotonically increasing
forever (by design, since result_count() backs the live-batch
"has another round finished" poll and must never go backwards or reset
mid-job). Split that: result_count() stays untouched across a clear,
but a new _round_offset captures total_finished at clear time so the
number shown to users (via snapshot()'s total_finished) restarts at 1
for the next game, without disturbing the internal counter.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
_run_live_batch() drives batch games through the shared game_loop (the
same reset/running state a human's Reset+Run would set), not through
simulate.py's headless runner. The test never started that loop, so
telemetry.result_count() never advanced and the job polled forever
until timing out. Start logic.game_loop() as a background task for the
duration of the test (mirroring what server.run() does in production)
and cancel it afterward, and give the poll loop enough budget to clear
the mandatory inter-round pause.
@yaacov

yaacov commented Jul 16, 2026

Copy link
Copy Markdown
Member

Thank you for the pull request 👍

Can you fix the tests ?
Does this pull request require a change in the UI ? can you link to the UI change ?

state is a dict that's mutated in place (state["key"] = ...), never
reassigned, so global was never required.
@DanielFourman

Copy link
Copy Markdown
Author

Thanks for the review!

Tests/lint: Fixed — flake8 was flagging global state in admin_handler and run() (F824: unused, since state is a dict mutated in place via state["key"] = ... and never reassigned, so global was never actually needed there). Removed both declarations in d13a0c3, pushed to this branch. make lint passes clean now.

UI change: Yes, this pairs with a UI change — the telemetry dashboard and automation pages are added in rose-game-web-ui#17: RedHat-Israel/rose-game-web-ui#17

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants