Files
LEDMatrix/test
ChuckandClaude Opus 5.5 11a7ca9671 feat(common): sports_plugin_host, sports_live_scroll, sports_display_rules and sports_font_path, promoted from the scoreboards (sports consolidation stage 4)
The identical sweep: method families every scoreboard carrying them has as
an identical copy (executable AST, docstrings stripped, decorators compared),
re-measured at ledmatrix-plugins 56c4f15. Four new hardware-free modules;
the bodies are the plugins', with type annotations and type comments for
the mypy ratchet.

- src/common/sports_plugin_host.py: SportsPluginHostMixin, ten helpers of
  the scoreboard plugin class (manager.py) identical in all nine:
  _dispatch_switch_refresh (with _SWITCH_REFRESH_MIN_GAP_SECONDS),
  get_vegas_priority_weight, _favorite_team_is_live, _favorite_scan_targets,
  _favorite_scan_games, _game_involves, get_vegas_content_type,
  _dynamic_feature_enabled, _get_total_games_for_manager,
  _build_manager_key. Listed before BasePlugin, whose defaults two of them
  override.
- src/common/sports_live_scroll.py: SportsLiveScrollMixin, the eight
  manager.py methods that rebuild a live scroll strip mid-cycle (all eight
  scoreboards with a strip; ufc has none), with the two rebuild-rate
  constants. LIVE_VOLATILE_FIELDS differs (afl/nrl/soccer add period_text)
  and stays in each plugin as host contract.
- src/common/sports_display_rules.py: SportsCardOptionsMixin (_card_option,
  _recent_date_text; the eight team scoreboards; must precede
  SportsCoreSharedMixin, whose _card_option it wraps) and
  SportsGameRulesMixin (_filtered_or_all, all but football;
  _effective_live_duration, all but ufc). Split by carrier so ufc does not
  gain a _card_option override it never had.
- src/common/sports_font_path.py: resolve_font_path, what the 17
  _resolve_font_path copies (nine sports.py, eight game_renderer.py) return
  on a core that ships it: the cwd first, then resolve_asset_path. Not
  resolve_asset_path alone, which skips the cwd.

Left in the plugins: _get_timezone, _extract_game_details and _fetch_data
(per-plugin import, abstract contract), _schema_font_size and
_resolve_font_size (each plugin's _SCHEMA_PATH), and the families carried by
seven plugins or fewer.

Tests: behaviour ported from the plugins' own tests against stub hosts with
exactly the documented contract, a host-contract test per mixin, and
test_sports_stage4_parity.py, which with LEDMATRIX_PLUGINS set compares
every promoted method and constant with every plugin copy using
scripts/sports_drift_report.py's normalisation plus decorators and values
(27 pass against 56c4f15; mutation-checked: a changed body, a swapped
decorator, a changed constant, a dropped @contextmanager and an unlisted
new method each fail it). test_sports_font_path.py runs both on the same
paths from a temporary cwd. All four modules are on the mypy ratchet, in
src/common/README.md, the CHANGELOG's Unreleased section (module entries
for the sunset floor; the version is not bumped) and SPORTS_UNIFICATION.
Nothing in core uses them yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 20:56:51 -04:00
..