Skip to content

world_cup: FIFA soccer betting scenario boilerplate#242

Open
cyruszhang wants to merge 2 commits into
mainfrom
cyrusz/world-cup
Open

world_cup: FIFA soccer betting scenario boilerplate#242
cyruszhang wants to merge 2 commits into
mainfrom
cyrusz/world-cup

Conversation

@cyruszhang
Copy link
Copy Markdown
Collaborator

Summary

Adds a new world_cup scenario that mirrors NBA's wiring, parameterised by FIFA league code so a single module serves the men's WC, women's WC, club WC, and all six qualifying confederations.

  • data/world_cup/ — ESPN soccer API wrapper (WorldCupExternalAPI(league=…)), state tracker with soccer status names (STATUS_FIRST_HALF/STATUS_HALFTIME/STATUS_FULL_TIME/STATUS_FINAL_PEN/…) and halves/ET/shootout period semantics, store that polls summary + plays and emits curated Pydantic stat models (SoccerTeamMatchStats, SoccerPlayerMatchStats: possession, shots, passes, tackles, fouls, cards). End-of-match detected via ESPN type.type slugs (end-regular-time, end-extra-time, end-shootout, …) so locale changes can't break it.
  • world_cup/ — Trial builder (register_trial_builder("world_cup", …)) with league param validated against 9 known FIFA codes; thin agent + datastream subclass; formatters with soccer period labels (1H/2H/ET1/ET2/PEN).
  • Cross-cuttingAnyDataEvent union members, DEFAULT_IMPORTS, sport_type: Literal[..., "world_cup"], world_cup_league metadata field.
  • trial_params/world-cup-moneyline.yaml — Defaults league: fifa.world. Polymarket stream commented out with a note: the 2026 WC tournament-winner market is event-level only (no game-level markets up yet); the factory remains registered so it can be flipped on later.
  • Tests — 59 new tests against real ESPN fixtures captured via proxy for CONMEBOL qualifier event 684665 (Ecuador 1-0 Argentina, 165 plays, completed). Tests verify API wrapper, factory registration, event roundtrip, stat models, summary parsing, plays parsing (dedup + lifecycle ordering + scorer attribution: Enner Valencia penalty), state tracker, formatters, and trial-builder validation.

Workspace fix bundled

packages/dojozero-agent-runner/ has source files but no pyproject.toml on this branch (belongs to a parallel agent-refactor workstream). The packages/* glob caused every uv invocation — including pre-commit hooks — to fail. Listed members explicitly to unblock builds without touching the other workstream. One-line revert when that branch re-lands its pyproject.toml.

Out of scope (flagged with TODO comments)

  • Polymarket integration: factory wired, store_types does not yet include polymarket. Switch on when game-level WC markets go live.
  • LLM persona prompts tuned for soccer (deferred per discussion).
  • Extra-time / penalty-shootout state handling beyond emitting events.

Test plan

  • uv run pytest packages/dojozero/tests/test_data_world_cup.py packages/dojozero/tests/test_world_cup_formatters.py packages/dojozero/tests/test_world_cup_trial.py — 59/59 pass
  • uv run pytest packages/dojozero/tests/ (no integration) — 1034 pass, no regressions
  • uv run pyright on all touched files — 0 errors
  • uv run ruff check + ruff-format — clean (pre-commit hooks pass)
  • End-to-end CLI smoke: uv run dojo0 run --params trial_params/world-cup-moneyline.yaml with a real espn_game_id (deferred — needs a scheduled WC match or a CONMEBOL qualifier in season)

🤖 Generated with Claude Code

cyruszhang and others added 2 commits May 12, 2026 13:17
New `world_cup` scenario mirrors NBA's wiring for FIFA competitions
(men's WC, women's WC, club WC, qualifiers). A single trial builder
takes a `league` param so one module serves all FIFA codes.

- data/world_cup/: ESPN soccer API wrapper, state tracker w/ soccer
  status names + halves/ET/shootout periods, store that polls summary
  + plays and emits curated Pydantic stat models
  (SoccerTeamMatchStats / SoccerPlayerMatchStats covering possession,
  shots, passes, tackles, fouls, cards)
- world_cup/: trial builder (`register_trial_builder("world_cup")`),
  agent, formatters (1H/2H/ET1/ET2/PEN labels), datastream subclass
- cross-cutting: AnyDataEvent union, DEFAULT_IMPORTS, sport_type Literal
- trial_params/world-cup-moneyline.yaml: default league fifa.world,
  polymarket stream stubbed out pending game-level WC markets
- tests: 59 new tests against real ESPN fixtures captured via proxy
  for CONMEBOL qualifier event 684665 (Ecuador 1-0 Argentina)

Workspace fix: drop the orphaned `packages/dojozero-agent-runner`
(no pyproject.toml on this branch) from `[tool.uv.workspace] members`
so uv and pre-commit hooks work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wires the world_cup scenario into the dashboard scheduler so trials are
discovered, launched, and monitored automatically off ESPN's soccer
scoreboard. Daily tier targets 2025 Club WC fixtures for backtest
validation; prod tier targets the 2026 men's WC w/ the full NBA-style
persona × LLM matrix.

- WorldCupGameFetcher: per-league fetcher (sport=soccer, league=fifa.*)
  with a soccer-specific scoreboard parser that maps ESPN status.type.name
  (id 28 / 45 / etc.) onto the canonical 1=scheduled / 2=in_progress /
  3=finished scheme used elsewhere in the scheduler.
- Hardens _parse_odds_data against None entries (ESPN's soccer scoreboard
  emits null providers).
- _scheduler.py: register_source validation accepts "world_cup";
  _sync_source and fetch_games_for_batch dispatch on sport_type and
  instantiate WorldCupGameFetcher with the per-source FIFA league;
  _get_game_status_info reads `world_cup_league` from scheduled metadata.
- _expand_compact_trial_source: tier YAML may set `league:` which gets
  injected into the expanded scenario_config so daily can target
  fifa.cwc while prod uses fifa.world.
- _SOCCER_STATUS_NAME_MAP: replace fictional STATUS_AFTER_EXTRA_TIME with
  the real ESPN name STATUS_FINAL_AET (verified live: CWC 2025 QF Al Hilal
  4-3 Man City, event 735949).
- trial_sources/{base,daily,prod}/world_cup.yaml: base ships data_streams
  + agent_template + schedule defaults (pre_start_hours 2.0, sync 1h);
  daily runs 1 game/day with pundit on fifa.cwc; prod runs unlimited
  games on fifa.world w/ all six personas.
- Backtest replays: end-to-end fixtures + tests for Chelsea 3-0 PSG final
  (event 735958, 191 plays, FT) and Al Hilal 4-3 Man City QF (event 735949,
  264 plays, AET — exercises STATUS_FINAL_AET).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant