mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-13 18:46:37 +00:00
feat(common): sports_live_fetch -- the reconciled live fetch and odds (sports family 9) (#793)
New hardware-free module src/common/sports_live_fetch.py, copied from
ledmatrix-plugins claude/family9-reconcile once the nine scoreboards made
_fetch_todays_games (seven bodies when measured) and _fetch_odds (three) one
body each. Both live on the plugins' SportsCore, so one mixin,
SportsLiveFetchMixin, carries exactly those two plus the odds worker
_drain_odds_queue; no manager gains a method it lacks today.
Owner decisions (2026-10-12):
- Live scores are always fresh: every poll asks ESPN through
get_espn_scoreboard and leaves the answer under the shared
espn_scoreboard_cache_key for its dates (max_age=1: only a copy another
reader fetched within the last second is reused). The plugins' 30 s
<sport_key>_scoreboard_current cache is gone.
- College basketball is asked by date like every other league (ESPN
answered single dates for both college leagues on 2026-10-12).
- Odds never block update(): one daemon worker per manager answers a queue
and attaches each line in place under _games_lock; one batch in flight per
manager, games queued meanwhile join it, every dict queued for an id gets
the one answer. show_odds, the two odds intervals and a missing odds
manager (debug, not ERROR) are respected.
- An answer whose events is not a list is no games.
Fix: get_espn_scoreboard() no longer caches an answer whose events is not a
list ("events": null), which every reader of the shared key inherited; it is
still returned to the caller.
- test/test_sports_live_fetch.py: the plugins' pinned cases (requests,
dates and keys at 10:00 and 02:00 Eastern, freshness, malformed and failed
answers, odds that never block and land later, the intervals, one batch per
manager, a worker that cannot start, update and display on two threads),
plus the host contract. Mutation-checked (11 mutants, all caught).
- test/test_sports_live_fetch_parity.py: with LEDMATRIX_PLUGINS, compares
each body with every plugin copy. Passes against claude/family9-reconcile;
fails against the pre-reconcile tree.
- test/test_espn_scoreboard_cache.py: the null-events regression.
- mypy ratchet, src/common/README.md, CHANGELOG (Unreleased: New modules,
Fixes), docs/SPORTS_UNIFICATION.md family 9 status and decisions.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -51,6 +51,7 @@ Rules for the package:
|
||||
| [`sports_game_over`](#sports_game_over) | Whether a game ESPN still lists as live has ended | Yes (scoreboards) | 3.8.1 |
|
||||
| [`sports_game_renderer`](#sports_game_renderer) | Scoreboard scroll/Vegas card geometry | Yes (scoreboards) | 3.3.0 |
|
||||
| [`sports_helpers`](#sports_helpers) | Small helpers every scoreboard `sports.py` copies | Yes (scoreboards) | 3.5.0 |
|
||||
| [`sports_live_fetch`](#sports_live_fetch) | The live poll's scoreboard request, and odds off the update path | Yes (scoreboards) | next release |
|
||||
| [`sports_live_scroll`](#sports_live_scroll) | Rebuild a live scroll strip mid-cycle without moving it | Yes (scoreboards) | 3.8.0 |
|
||||
| [`sports_plugin_host`](#sports_plugin_host) | Helpers of a scoreboard's plugin class (`manager.py`) | Yes (scoreboards) | 3.8.0 |
|
||||
| [`sports_rankings`](#sports_rankings) | Which teams are ranked, in which poll, and the "ranked" filter | Yes (scoreboards) | 3.8.5 |
|
||||
@@ -370,6 +371,19 @@ shape), `_dispatch_switch_refresh()` (a manager refresh on a daemon thread, so
|
||||
`display()` never waits on the network), `get_vegas_content_type()` and small
|
||||
dynamic-duration helpers. List it before `BasePlugin`.
|
||||
|
||||
### sports_live_fetch
|
||||
|
||||
[`sports_live_fetch.py`](sports_live_fetch.py). Sports family 9:
|
||||
`SportsLiveFetchMixin` (`SportsCore`). `_fetch_todays_games` asks ESPN for
|
||||
today's scoreboard (and yesterday's while `_needs_previous_day()` says it can
|
||||
still hold a live game) on every live poll through `get_espn_scoreboard`, and
|
||||
leaves it under the shared `espn_scoreboard_cache_key` for odds-ticker and the
|
||||
other scoreboards; an answer without an `events` list is no games.
|
||||
`_fetch_odds` queues a game and returns at once; one daemon worker per manager
|
||||
(`_drain_odds_queue`) asks the odds manager for each queued game and attaches
|
||||
the line in place under `_games_lock`, so a card can draw once without odds and
|
||||
gain them. Games queued while the worker is busy join its batch.
|
||||
|
||||
### sports_rankings
|
||||
|
||||
[`sports_rankings.py`](sports_rankings.py). Sports family 8:
|
||||
|
||||
Reference in New Issue
Block a user