Commit graph

3 commits

Author SHA1 Message Date
3e50619629 claude/probability-config-review-1tdolw (#119)
All checks were successful
🚀 Deploy / 🧪 Test (push) Successful in 3m1s
🚀 Deploy / ʦ🔍 Typecheck & Lint (push) Successful in 1m17s
🚀 Deploy / 🐳 Build (push) Successful in 1m9s
🚀 Deploy / 🚀 Deploy (push) Successful in 11s
Co-authored-by: Claude <noreply@anthropic.com>
Reviewed-on: #119
2026-06-30 23:24:48 +00:00
Chris Parsons
766ba948e1
Add MLS standings sync and fix simulator conference resolution (#423)
* Add MLS standings sync and fix simulator conference resolution

- New MlsStandingsAdapter using ESPN's free soccer API (no key required),
  returning Eastern/Western conference data, W/D/L/GF/GA/GD/PTS, conference
  rank, and home/away records; registered under mls_bracket
- Display route now shows soccer table columns and a 9-team playoff cutoff
  line for mls_bracket (top 9 per conference qualify for MLS Cup Playoffs)
- MLS simulator gains a third conference fallback: reads externalId="Eastern"
  or "Western" on the participant, mirroring the LLWS pool-assignment pattern
  so admins can bootstrap conference data before the first standings sync
- 9 unit tests covering stat mapping, conference normalization, rank ordering,
  and error paths

https://claude.ai/code/session_01WhzXHpv6taXdHzhgvnv83u

* Address code review feedback on MLS standings + simulator

1. Update mls-simulator.ts module comment to document the new step-3
   externalId fallback in the conference resolution order
2. Tighten normalizeConference to exact-match "Eastern"/"Western
   Conference" instead of broad substring, preventing false matches
   on names like "Northeast"
3. Pre-parse statsMap for each entry before the sort so it isn't
   rebuilt O(n log n) times during comparison
4. Document the externalId name-matching tradeoff on
   parseConferenceFromExternalId
5. Try ESPN's gamesPlayed stat before falling back to wins+losses+ties
   sum; export parseConferenceFromExternalId for direct testing
6. Add tests: normalizeConference passthrough, winPct=0 at preseason,
   and parseConferenceFromExternalId (case-insensitivity, null/undefined,
   numeric ESPN IDs, unrecognized strings)

https://claude.ai/code/session_01WhzXHpv6taXdHzhgvnv83u

* Fix lint: replace != null with !== null && !== undefined

oxlint enforces eqeqeq; the five != null checks in mls.ts were flagged.

https://claude.ai/code/session_01WhzXHpv6taXdHzhgvnv83u

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-14 15:39:40 -07:00
Chris Parsons
c097e4827c
Add MLS sport simulator (mls_bracket) (#422)
* Add MLS sport simulator (mls_bracket)

Adds Major League Soccer as a draftable sport with a full-season Monte Carlo
simulator. Models both preseason regular-season projection (34 games across
Eastern and Western conferences) and the MLS Cup Playoffs bracket, including
the Wild Card (single game + PKs), Round 1 best-of-3 series, Conference
Semis/Finals (single game), and MLS Cup.

P1–P8 mapping: MLS Cup winner, finalist, Conference Finals losers, Conference
Semifinals losers. Conference assignment reads from regularSeasonStandings.conference
or falls back to the region simulator input ("Eastern"/"Western").

Admin inputs: projectedTablePoints (primary, max 102 for 34×3), with derivation
chain to sourceElo via existing input-policy; sourceOdds as alternative.
No hardcoded team data — all inputs are admin-managed per season.

- database/schema.ts: add mls_bracket to simulatorTypeEnum
- drizzle/0104_chief_boom_boom.sql: migration for the new enum value
- mls-simulator.ts: MLSSimulator + exported pure helpers for testability
- registry.ts / manifest.ts / simulator-config.ts: register mls_bracket
- mls-simulator.test.ts: 38 unit tests covering all helpers and sync checks

https://claude.ai/code/session_015wkBJ3SYGcMGjsddKKGkwa

* Fix MLS simulator: config loading, sourceOdds fallback, normalization

Three issues found in code review comparing against EPL and NFL simulators:

1. Load simulator config from DB via getSportsSeasonSimulatorConfig so
   admins can override iterations, seasonGames, parityFactor, drawRates
   per season without code changes. Previously all constants were hardcoded.

2. Add sourceOdds → convertFuturesToElo fallback when no sourceElo is
   present. EPL and NFL both do this; MLS was throwing immediately instead
   of attempting the odds conversion that the manifest declares as optional.

3. Call normalizeSimulationResultColumns before returning results, matching
   EPL's local normalization pattern for consistency (runner also normalizes
   globally, but EPL calls it locally too).

https://claude.ai/code/session_015wkBJ3SYGcMGjsddKKGkwa

* Polish MLS simulator: configNumber zero, logger warning, Map lookup

Three small fixes from secondary code review:

1. configNumber: allow value >= 0 (not just > 0) so admins can
   legitimately set baseDrawRate or drawDecay to 0 without the value
   being silently discarded and replaced with the default.

2. Add logger.warn when a participant is excluded from simulation due
   to a missing Elo rating, matching the NLL bracket-aware pattern.
   Gives admins a visible signal instead of a silent exclusion.

3. getBySeeds: build a Map once instead of calling Array.find() per
   seed. Eliminates 4M linear scans across 50k iterations for a 9-
   element array — trivially fast either way, but Map is the right tool.

https://claude.ai/code/session_015wkBJ3SYGcMGjsddKKGkwa

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-14 12:45:53 -07:00