Integration: Race Outlook prediction stack#270
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d8a7b05839
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| for (let r = 0; r < MAX_FUTURE_ROUNDS; r++) { | ||
| const outcomes = stats.map((s) => sampleRoundOutcome(s, rng)); |
There was a problem hiding this comment.
Require at least one blitz in simulated rounds
When the mechanics model is active, each player's blitzed flag is sampled independently and the simulation immediately scores that vector. For games where each player has a low or mid blitz rate, a large share of simulated rounds can have no blitzPileRemaining === 0, even though validateGameRules rejects such score sets and real rounds only end once someone blitzes. Those invalid rounds still advance scores and can skew win and next-round probabilities; resample or condition the outcomes so at least one player blitzes.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
This integration PR stacks the full “Race Outlook” prediction feature set: a richer Monte Carlo race forecast, optional permission-gated historical player profiles, a mechanics-aware sampling layer for Dutch Blitz, and the corresponding UI updates/tests to exercise the end-to-end experience.
Changes:
- Added a permission-gated server query to compute per-player historical prediction profiles from prior finished games in the same circle.
- Expanded the probability model into a coherent “race forecast” (win odds + next-round threats + finish ranges + unresolved outcomes), with optional history blending and mechanics-aware sampling.
- Updated scoring UI to pass history/mechanics inputs through and render the new Race Outlook card, plus added unit/component tests.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/server/queries/predictionProfiles.ts | New server-only query + profile builder for permission-gated historical samples. |
| src/server/queries/index.ts | Re-export prediction profile query/builder and types. |
| src/server/queries.ts | Re-export getPredictionProfilesForGame from the server query barrel. |
| src/server/tests/predictionProfiles.test.ts | Unit tests for gating, scoping, caps, and profile math. |
| src/lib/scoring/probability.ts | New Race Outlook forecast model: unresolved outcomes, history blending, mechanics sampling, and helpers. |
| src/lib/tests/probability.test.ts | Model tests for determinism, clamping, percent allocation, history/mechanics behavior. |
| src/components/scoring/ScoringShell.tsx | Thread predictionProfiles into the scoring shell and down to the between-rounds view. |
| src/components/scoring/graphs/WinProbabilityCard.tsx | Replace projected finish with Race Outlook UI backed by calcRaceForecast. |
| src/components/scoring/BetweenRoundsView.tsx | Derive per-round mechanics samples and pass them + profiles into the forecast card. |
| src/components/tests/scoring/WinProbabilityCard.test.tsx | Component test coverage for Race Outlook rendering and copy. |
| src/app/games/[id]/page.tsx | Fetch and pass prediction profiles for circle members only. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export function allocateOutcomePercents( | ||
| counts: [string, number][], | ||
| total: number | ||
| ): Record<string, number> { | ||
| const exact = counts.map(([id, count]) => ({ | ||
| id, | ||
| value: total === 0 ? 0 : (count / total) * 100, | ||
| })); |
| // If every player has non-positive mean, no one is progressing | ||
| if (stats.every((s) => s.mean <= 0)) { | ||
| return Object.fromEntries(players.map((p) => [p.id, 0])); | ||
| return { | ||
| players: Object.fromEntries( | ||
| players.map((p) => [ |
| const predictionProfiles = isCircleMember | ||
| ? await getPredictionProfilesForGame(params.id) | ||
| : {}; |
Summary
This integration PR contains the full Race Outlook prediction stack for end-to-end testing:
Use this branch/PR to test the full experience together. The smaller PRs remain useful as review slices.
Verification already run on the stacked tip
npm run lintnpm testRESEND_API_KEY=re_dummy npx next buildNote
I created this from the top of the stack (
mwickett/dutch-blitz-mechanics-forecast) so it contains every commit in the series.