* fix(common): favourite check no longer calls a started postseason a finished season
The day after a regular season ends, ESPN's default scoreboard still
returns that last regular-season day, while leagues[0].season has moved
to Postseason. All events were in the past, so the check logged "the
season has finished" for MLB on 2026-09-29 while the upcoming manager in
the same process was showing TB's wild-card games.
When every event is past and the league is in a later in-season phase
(regular season or postseason) than all of the returned events, draw no
conclusion. The offseason is excluded, so a genuinely finished season is
still reported as finished.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(common): favourite check reports the next matchday between soccer rounds
Between matchdays ESPN's soccer scoreboard keeps showing the last one, so
every event is in the past and in the league's current phase, which the
postseason rule does not cover; the check said the Premier League season
had finished on 2026-09-29 (last games 20 September, next 10 October).
When the league calendar is a "day" whitelist, its entries are days with
games, so a future one is used as the next fixture. MLB's day calendar is
a blacklist and is not read that way; PLL's whitelist has no future days
and is still reported as finished.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(common): favorite_team_check and sports_timezone, promoted from the scoreboards (sports consolidation stage 2)
Two new hardware-free modules, taken from files the scoreboard plugins carry
as copies:
- src/common/favorite_team_check.py: FavoriteTeamCheck(logger, leagues), the
seven byte-identical <sport>_favorite_check.py copies. Same code; the only
additions are two type annotations (for the mypy ratchet).
- src/common/sports_timezone.py: resolve_timezone_name(), resolve_timezone(),
system_timezone_name(), from the ten <sport>_timezone.py copies. They
differed only in the plugin label named in the nothing-resolved warning and
the write-back-bug values, which become keyword-only arguments
(plugin_label, writeback_fixed_in). Same resolution order and log text.
Tests are ported from the plugins' own (test_favorite_check.py,
test_schedule_note_uses_game_dates.py, test_timezone_resolution.py; the
timezone ones run once per plugin's values and pin the exact warning text).
Both modules are on the mypy ratchet, in src/common/README.md, the CHANGELOG's
Unreleased section and SPORTS_UNIFICATION's module table. Nothing in core uses
them yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(common): bdf_font and json_body shipped in 3.5.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* chore(common): annotate the favourite check's deliberate except/pass for Bandit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>