* feat(common): sports_favorites -- the reconciled favourite matching (sports family 6)
New hardware-free module src/common/sports_favorites.py, copied from
ledmatrix-plugins claude/family6-reconcile once the nine scoreboards made
_is_favorite_game (seven bodies), _select_games_for_display (two) and
_select_recent_games_for_display (three) one body each. One mixin per class
that carries the methods, so adopting one gives no manager a method it did
not have:
- SportsFavoritesMixin (SportsCore): _is_favorite_game and _favorite_code.
- SportsUpcomingFavoritesMixin: _select_games_for_display.
- SportsRecentFavoritesMixin: _select_recent_games_for_display.
Each side of a game is named by the 3.5.0 _favorite_key seam
(SportsHelpersMixin; the abbreviation by default, nrl overrides it with the
ESPN team id and None for a missing id) and compared with favorite_teams
stripped and upper-cased. The selection methods give each favourite up to the
per-team limit, count a game between two favourites for both, treat only
games with an id as possible duplicates and log their summary at INFO.
- test/test_sports_favorites.py: the plugins' pinned cases for an abbreviation
host and an id-keyed (nrl-style) host -- case, spaces, ids, the NEW
collision, the "None" favourite, missing keys; selection order, limits,
duplicates and the id-less fix, the INFO summary; host contract, one carrier
per method, and SportsGameRulesMixin reaching the shared body.
- test/test_sports_favorites_parity.py: with LEDMATRIX_PLUGINS, compares each
body with every plugin copy (drift-report normalisation plus decorators),
checks no other plugin class carries a copy, and that only nrl overrides
_favorite_key.
- mypy ratchet, src/common/README.md, CHANGELOG (Unreleased, New modules).
- sports_helpers docstrings: _favorite_key now has a caller and an override.
- docs/SPORTS_UNIFICATION.md: family 6 status and decisions, and the seam
table. SportsCoreSharedMixin._round_robin_favorites still groups by raw
abbreviation or _team_in: it is not one of the plugin bodies, so it waits
for a later family.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(sports): family 6 also routes the Upcoming favourites-only filter and three live boosts
ledmatrix-plugins claude/family6-reconcile now sends the Upcoming update()'s
favourites-only pre-filter and the basketball, hockey and lacrosse live
favourite boost through _is_favorite_game, so a lower-case favourite works on
a favourites-only Upcoming board. The module is unchanged (update() is not
promoted); the parity test still passes against the branch. Updates the
pinned row and cell counts and what is left for later families.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs: cite ledmatrix-plugins #635 for the family 6 reconcile
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>