Conversation
β¦mplete() on GameState (closes #452) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request refactors the GameState class by introducing a public current_time method and encapsulating the early reveal logic into trigger_early_reveal_if_complete. The websocket handlers were updated to utilize these new methods. Review feedback suggests that the refactoring resulted in a loss of observability; it is recommended to move the debug logging into the encapsulated method to ensure consistent tracking of the game state across all guess types and to remove the now-redundant logging in the websocket handlers.
| async def trigger_early_reveal_if_complete(self) -> None: | ||
| """Trigger early reveal if the round is playing and all guesses are in.""" | ||
| if self.phase == GamePhase.PLAYING and self.check_all_guesses_complete(): | ||
| await self._trigger_early_reveal() |
There was a problem hiding this comment.
The refactored trigger_early_reveal_if_complete method loses the observability previously present in websocket.py. Specifically, the all_complete status is no longer logged, making it harder to debug why an early reveal might not have triggered. Moving the debug logging into this method ensures all call sites (submit, artist guess, movie guess) benefit from consistent observability without duplicating logic.
| async def trigger_early_reveal_if_complete(self) -> None: | |
| """Trigger early reveal if the round is playing and all guesses are in.""" | |
| if self.phase == GamePhase.PLAYING and self.check_all_guesses_complete(): | |
| await self._trigger_early_reveal() | |
| async def trigger_early_reveal_if_complete(self) -> None: | |
| """Trigger early reveal if the round is playing and all guesses are in.""" | |
| if self.phase != GamePhase.PLAYING: | |
| return | |
| all_complete = self.check_all_guesses_complete() | |
| _LOGGER.debug( | |
| "Early reveal check: phase=%s, all_complete=%s", | |
| self.phase.value, | |
| all_complete, | |
| ) | |
| if all_complete: | |
| await self._trigger_early_reveal() |
| _LOGGER.debug( | ||
| "Early reveal check: phase=%s, all_complete=%s, artist_challenge=%s", | ||
| "Early reveal check: phase=%s, artist_challenge=%s", | ||
| game_state.phase.value, | ||
| all_complete, | ||
| game_state.artist_challenge_enabled, | ||
| ) | ||
| if game_state.phase == GamePhase.PLAYING and all_complete: | ||
| await game_state._trigger_early_reveal() | ||
| await game_state.trigger_early_reveal_if_complete() |
There was a problem hiding this comment.
This debug log is now redundant and incomplete compared to the original implementation, as it no longer includes the all_complete status. Since the logic has been encapsulated into GameState.trigger_early_reveal_if_complete(), the logging should also be moved there to provide consistent observability across all guess types while keeping the websocket handler clean.
await game_state.trigger_early_reveal_if_complete()
mholzi
left a comment
There was a problem hiding this comment.
Review: LGTM β
Clean refactor that eliminates all private-member access from websocket.py.
Checklist
| # | Check | Result |
|---|---|---|
| 1 | All 6 call sites updated β 3Γ _now() β current_time(), 3Γ _trigger_early_reveal() β trigger_early_reveal_if_complete() |
β
Confirmed, zero game_state._now( / game_state._trigger_early_reveal( remain in websocket.py |
| 2 | Phase check encapsulated correctly β trigger_early_reveal_if_complete() checks phase == PLAYING and check_all_guesses_complete() before delegating to _trigger_early_reveal() |
β Matches the exact guard that was previously duplicated at each call site |
| 3 | No logic moved incorrectly β the inner _trigger_early_reveal() still re-checks phase under _score_lock (line 987), so the outer check in the new method is a correct fast-path / short-circuit, not the sole race-condition guard |
β |
| 4 | API surface clean β current_time() is a simple delegate to the injected clock; trigger_early_reveal_if_complete() is a well-named, self-documenting intent method. Both placed logically in the class |
β |
Net result: +9 / β0 in state.py, +13 / β24 in websocket.py β less code, better encapsulation, no behavioral change. Good to merge.
Fixes #452 β adds public wrappers on GameState to stop websocket.py accessing private
_now()and_trigger_early_reveal()directly.