add prediction scoring design spec

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-12 21:40:25 +01:00
parent 4e06930796
commit f0dc35610e

View File

@@ -0,0 +1,87 @@
# 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
```ts
// Added to GameState
actualResults: { winner: string; second: string; third: string; last: string } | null
// LeaderboardEntry gains
predictionPoints: number
```
## Scoring Config Values (existing)
```json
{
"prediction_winner": 25,
"prediction_top3": 10,
"prediction_nul_points": 15
}
```