# Issue #301 Artifact — Client action gating from canonical phase state Refs: #287, #301 ## What changed Frontend host/player shells now prefer the canonical phase exposed by `phase_view_model.current_phase` when deciding: - which gameplay actions are enabled - whether reveal data should still be shown - which SPA hash-route should represent the active game state This tightens the #301 slice so the client stays aligned with backend canonicalisation even when `session.status` lags during reveal/scoreboard promotion. ## Gated UI actions by phase ### Lobby - **Host:** `startRound` - **Player:** `join` ### Bluff / lie - **Host:** `showQuestion` - **Player:** `submitLie` - **Blocked:** guess submission, scoreboard load, next round, finish game ### Guess - **Host:** `mixAnswers`, `calculateScores` - **Player:** `submitGuess` - **Blocked:** lie submission, scoreboard load, next round, finish game ### Reveal - **Host:** `loadScoreboard` - **Player:** display-only reveal state - **Blocked:** start next round, finish game, guess/lie submission ### Scoreboard - **Host:** `startNextRound`, `finishGame` - **Player:** display-only reveal/scoreboard state - **Blocked:** scoreboard reload, guess/lie submission ## Test evidence Targeted tests added/updated for: - host shell canonical gating and route sync when `current_phase` differs from `session.status` - player shell canonical gating and route sync when `current_phase` differs from `session.status` - shared gameplay phase machine gating from canonical permissions - shared API mapper contract coverage, including reveal/scoreboard payload stability ## Contract note No backend protocol redesign was introduced. This follow-up only preserves and consumes the existing canonical phase/action contract more strictly on the client side.