The IndyCar simulator gave a near-clinched championship leader ~60% to win the title. It was reporting the futures odds and nothing else. `event_type` has no race value, so a season_standings calendar (F1, IndyCar) is stored as `schedule_event` rows — the admin default for that scoring pattern. The simulator skipped exactly those rows when counting races, so it saw zero remaining races, took the branch labelled "pre-season", and never looked at `participant_season_results`. Since `sourceOdds` is an admin input that is never auto-refreshed, the output was whatever the market said months ago. With a realistic late-season field (leader on 601 pts vs 480, 2 races left, stale futures at -300) the old path returns ~55%; counting the races returns 100.0%. - Add `countSeasonRaces` in a new leaf model. A race is every event except `final_standings`, and completion is inferred from the event date, since nobody marks rows labelled "Non-Scoring" complete. Its own module because `scoring-event.ts` reaches back into `simulator.ts` through `scoring-calculator`. - Split "season over" from "pre-season". Both had `remainingRaces === 0`, so a finished season reverted to an odds draw instead of reporting the final standings. - Warn when a season has championship points but no calendar, in the simulator and as a non-blocking readiness warning on the setup page. - Replace proportional vig removal with a power devig. Dividing every runner by the same book sum guts the favourite in a 27-driver market: a 75% implied favourite came out at 55%, a -20000 near-lock at 95%. Power devig gives 69.5% and 99.3%. Unpriced drivers now floor at the bottom of the market instead of being handed 1/N. - Move the race points tables to their own module so tests can read them without tripping the manifest/registry import cycle. The existing tests missed all of this because their event fixtures used `eventType: "race"`, which is not a value the enum has. Rebuilt on real enum values, plus a regression test for the reported case. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TUcV7KenckF893zQ46EDXt
23 lines
1,009 B
TypeScript
23 lines
1,009 B
TypeScript
/**
|
||
* Championship points tables for auto racing series.
|
||
*
|
||
* Stable series rules, not refreshable season data, so they live in code (see
|
||
* the hardcoding rules in docs/agents/simulators.md). Kept out of `registry.ts`
|
||
* so tests and callers can read a table without pulling in every simulator —
|
||
* importing the registry first also trips the manifest/registry import cycle.
|
||
*
|
||
* Each table must be contiguous from P1 and monotonically decreasing: the
|
||
* simulator's award loop stops at the first unscored position.
|
||
*/
|
||
|
||
/** F1 points: positions 1–10. */
|
||
export const F1_RACE_POINTS: Record<number, number> = {
|
||
1: 25, 2: 18, 3: 15, 4: 12, 5: 10, 6: 8, 7: 6, 8: 4, 9: 2, 10: 1,
|
||
};
|
||
|
||
/** IndyCar standard race points: positions 1–26. */
|
||
export const INDYCAR_RACE_POINTS: Record<number, number> = {
|
||
1: 50, 2: 40, 3: 35, 4: 32, 5: 30, 6: 28, 7: 26, 8: 24, 9: 22, 10: 20,
|
||
11: 19, 12: 18, 13: 17, 14: 16, 15: 15, 16: 14, 17: 13, 18: 12, 19: 11, 20: 10,
|
||
21: 9, 22: 8, 23: 7, 24: 6, 25: 5, 26: 5,
|
||
};
|