Files
esc/docs/superpowers/specs/2026-03-12-prediction-scoring-design.md
2026-03-12 21:40:25 +01:00

3.1 KiB

Prediction Scoring — Design Spec

Date: 2026-03-12 Status: Approved


Goal

Allow the host to enter actual ESC results, calculate prediction scores for all players, and display them on the leaderboard.

What Exists

  • Players submit predictions (1st, 2nd, 3rd, last place) during lobby/pre-show via PredictionsForm
  • Predictions lock when host advances to live-event act
  • GameManager stores predictions in a Map<string, Prediction>
  • Leaderboard already shows jury (J:) and bingo (B:) points
  • DB schema has actual_winner, actual_second, actual_third, actual_last columns on rooms table (nullable, set when host enters results)

New Functionality

1. Host Enters Actual Results

  • New component: ActualResultsForm — shown in the Host tab during scoring and ended acts
  • Same country-picker UX as the predictions form (select from lineup, all 4 must be different)
  • New WS message: submit_actual_results (client → server) with { winner, second, third, last }
  • Server stores on the GameManager (in-memory) and broadcasts updated game state
  • Host can re-submit to correct mistakes (overwrites previous entry)

2. Server Scores Predictions

  • GameManager.setActualResults(winner, second, third, last) — stores the actual results
  • GameManager.getPredictionScore(playerId) — compares player's prediction to actuals:
    • first matches winner: 25 pts (scoring.prediction_winner)
    • second matches second: 10 pts (scoring.prediction_top3)
    • third matches third: 10 pts (scoring.prediction_top3)
    • last matches last: 15 pts (scoring.prediction_nul_points)
    • Total possible: 60 pts
  • Prediction scores feed into buildLeaderboard as a new predictionPoints field

3. Leaderboard Update

  • LeaderboardEntry gains predictionPoints: number
  • Before results are entered: shows P:? on the leaderboard
  • After results are entered: shows P:<score> with actual points
  • totalPoints includes prediction points (0 if no results entered yet)

4. Player View — Results Reveal

  • After actual results are entered, each player's gameState includes actualResults: { winner, second, third, last } | null
  • PredictionsForm (locked state) gains visual indicators: green checkmark for correct predictions, red X for incorrect
  • Players who didn't submit predictions get 0 prediction points

5. Display View

  • Shows actual results summary when entered
  • Shows leaderboard with prediction scores revealed

WS Messages

Client → Server:

Type Payload Guard
submit_actual_results winner, second, third, last (country codes) Host only, scoring or ended act

No new server → client messages — the existing game_state broadcast carries all the data.

GameState Changes

// Added to GameState
actualResults: { winner: string; second: string; third: string; last: string } | null

// LeaderboardEntry gains
predictionPoints: number

Scoring Config Values (existing)

{
  "prediction_winner": 25,
  "prediction_top3": 10,
  "prediction_nul_points": 15
}