Commit graph

1 commit

Author SHA1 Message Date
Chris Parsons
e62e9554c9
Add golf qualifying points simulator (Plackett-Luce Monte Carlo) (#223)
* Add golf QP simulator with Plackett-Luce model, fixes #120

- New `participant_golf_skills` table (migration 0061) for SG: Total and
  per-major American odds per player/season
- New `app/models/golf-skills.ts` with getGolfSkillsMap, getGolfSkillsForSeason,
  batchUpsertGolfSkills
- Full `GolfSimulator` implementation replacing the TODO stub: Plackett-Luce
  ranking model (PL_BETA=1.5, FIELD_SIZE=156), 10k Monte Carlo iterations,
  awards QP by finishing position, ranks by total QP across all 4 majors
- New admin route `sports-seasons/:id/golf-skills` with bulk CSV import,
  fuzzy name matching, per-player SG + per-major odds inputs; saves skills
  and auto-runs simulation on submit
- Simulator dropdown on sport admin sorted alphabetically; renamed to
  "Golf Qualifying Points Monte Carlo"
- Golf Skills button shown on sports season admin when simulator type is
  golf_qualifying_points
- Extract normalizeName/diceCoefficient to shared `app/lib/fuzzy-match.ts`,
  removing duplication from surface-elo and golf-skills routes
- Parallelize 4 DB queries in GolfSimulator.simulate() with Promise.all
- O(1) field array removal via swap-to-end + pop (was O(N) splice)
- Fix source tag: performance_model (not elo_simulation) for SG-based model
- 23 unit tests covering americanToImplied, getMajorOddsKey, resolveSkill,
  simulateMajor, and Monte Carlo calibration properties

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Fix oxlint errors: no-non-null-assertion and eqeqeq

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 21:46:02 -07:00