Skip to content

Game over is the game's: a seat knocked out no longer ends it for the casters, the viewer and the play page - #15

Merged
earakely-scale merged 1 commit into
mainfrom
fix/game-over-for-everyone
Oct 5, 2026
Merged

earakely-scale merged 1 commit into
mainfrom
fix/game-over-for-everyone

Conversation

@earakely-scale

Copy link
Copy Markdown
Owner

The bug

A seat's state has its own game_over, which the bridge sets once that seat is defeated (GameOver => human.defeated || turn >= turnLimit || victory != null, per seat). The env took any seat's game_over as the whole game's, in three places:

  • The live data (/live/data.json, live.game_over): the casters and the viewer's director read it.
  • The play page's status: /play/api/status and the play view.
  • The data/get summary's top-level game_over: it was the first seat's, and openciv3_await_game reads it.

What it did:

  • In the sol-vs-opus broadcast, Sol lost its last city, and the casters signed off at turn 155 calling it "a win on score". The conquest victory was only recorded at turn 156.
  • With three or more agents, the first elimination would bring the outro and the final-summary card mid-game while the match played on.
  • openciv3_await_game would stop waiting if the first seat fell.

The fix

One _game_over() serves all three places. The game is over:

  • at a victory;
  • at the turn limit, which any seat still in the game reports;
  • or once every seat is defeated.

A defeated seat's own defeated and its tool replies are unchanged: the game is still over for that agent.

docs/tools.md says data/get's game_over and victory are the game's, not the first seat's, and docs/viewer.md notes that live.game_over means over for every seat.

Tests

  • 512 pass; ruff is clean.
  • New, on the real bridge (tests/env/test_seats.py): with three seats, Egypt disbands its units and is defeated, while Rome and Greece play on. The live data, _game_over() and data/get say the game goes on, and Rome's brief moves to T1.
    • On main the live data says it is over (assert (True, None, 1) == (False, None, 1)).

🤖 Generated with Claude Code

… casters, the viewer and the play page

The bridge's per-seat game_over includes that seat's own defeat, and the env took any seat's as the game's: the live
data, the play page's status and data/get's summary said game over at the first elimination. In the sol-vs-opus
broadcast the casters signed off a turn before the conquest and called it a win on score; with three or more agents
the outro would come mid-game, and openciv3_await_game would stop waiting if the first seat fell. One _game_over now
serves all three: over at a victory or the turn limit (which a seat still in the game reports), or once every seat
is defeated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@earakely-scale
earakely-scale merged commit bdb6808 into main Oct 5, 2026
5 checks passed
@earakely-scale
earakely-scale deleted the fix/game-over-for-everyone branch October 5, 2026 18:47
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.

1 participant