镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

scoreboards: use core 3.8.0's stage 4 mixins; drop the copies (stage 4) - #594

Merged
ChuckBuilds merged 5 commits into
mainfrom
claude/sports-stage4-adoption
Oct 1, 2026
Merged

ChuckBuilds merged 5 commits into
mainfrom
claude/sports-stage4-adoption

Conversation

@ChuckBuilds

@ChuckBuilds ChuckBuilds commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

Sports consolidation stage 4, adoption: the nine scoreboards inherit the four modules core 3.8.0 ships (core #705, the "identical sweep" of the #680 roadmap) and delete their copies. No behaviour change.

What is removed

Module (core 3.8.0) What each plugin now inherits instead of carrying Plugins
src.common.sports_plugin_host SportsPluginHostMixin on the plugin class (before BasePlugin): _dispatch_switch_refresh + _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 all nine
src.common.sports_live_scroll SportsLiveScrollMixin: the live strip's mid-cycle rebuild (_live_scroll_*, _fingerprint_games, _preserving_scroll_position, the two LIVE_SCROLL_REBUILD_* constants). LIVE_VOLATILE_FIELDS stays (afl, nrl, soccer differ) eight (not ufc)
src.common.sports_display_rules SportsCardOptionsMixin (_card_option, _recent_date_text; ahead of SportsCoreSharedMixin) and SportsGameRulesMixin (_filtered_or_all, _effective_live_duration) on SportsCore eight / nine
src.common.sports_font_path resolve_font_path, imported as _resolve_font_path in every sports.py and game_renderer.py, and ufc's fight_renderer.py and headshot_downloader.py all nine

Lines in the scoreboards' tracked files, this PR's code commit:

Plugin Removed Added
afl 541 9
baseball 556 9
basketball 547 9
football 528 9
hockey 565 9
lacrosse 565 9
nrl 541 9
soccer 547 9
ufc 335 9
total 4,725 81

Imports only the deleted code used go too (contextlib.contextmanager; threading in football, hockey, lacrosse and ufc; os in ufc's two files). Baseball keeps threading: #582's get_vegas_elements uses threading.Event. pyflakes reports nothing new.

Also: scripts/test_stage4_mixin_copies.py, a sunset guard in the shape of stage 3's (no runtime file may define a moved name again, except the listed keeps: baseball renderer's own _recent_date_text, Baseball._recent_date_text in baseball.py (#588's override: blanks the date row when a series line is drawn, otherwise super(), i.e. core's), ufc's hand-run generate_placeholder_icon.py; plain imports; base membership and order; compared with core's modules both ways when LEDMATRIX_CORE is set). Docs: 08-shared-sports-code.md gains "Converged at 3.8.0", and CLAUDE.md's non-negotiable #7 names the four modules.

Floor and versions

Every scoreboard already floors on core 3.8.0 (#582's live Vegas cards), and 3.8.0 is tagged with #705 in it, so the floor does not rise and the bumps are patches, each with a new versions[0] (ledmatrix_min_version 3.8.0) and a CHANGELOG entry:

afl 1.35.1, baseball 1.54.3, basketball 1.41.1, football 3.18.1, hockey 1.40.1, lacrosse 1.36.1, nrl 1.34.1, soccer 2.39.1, ufc 1.19.1. plugins.json regenerated with update_registry.py; --check passes.

Rebuilt on current main

The branch was rebuilt on 2d97e56 rather than rebased: its first commit ("core's stage 4 modules are on main, in no release yet") had already landed via #589/#591 and is dropped. Every scoreboard manager.py conflicted, all adjacency with the live Vegas cards (#582), so the code commit was regenerated by the same AST script that produced the original, which reproduces the original commit exactly on its old base (bb1db84). On the new base it changes the same lines (the sorted +/- line set is identical, 4,317 lines) except one: baseball keeps import threading (above).

Main's scoreboard changes since the old base (#581 ufc, #582 live Vegas cards, #588/#593 baseball) touch none of the promoted families: an AST comparison of every promoted name in every file, old base vs main, finds no change. Nothing a plugin would lose.

Parity: every deleted copy matches core 3.8.0

  • Core's test/test_sports_stage4_parity.py + test_sports_font_path.py, run from a core checkout at the v3.8.0 tag (and again at core main), with LEDMATRIX_PLUGINS at plugins main (every copy still present): 47 passed. Against this branch (copies gone, counted as adopted): 31 passed.
  • scripts/sports_drift_report.py (core 3.8.0) on plugins main: every promoted family is 1 variant per class across its carriers (_effective_live_duration is one in SportsCore for afl/nrl/soccer and one in SportsLive for the other five, both core's). On this branch none remain, apart from baseball renderer's own _recent_date_text, which was never promoted.
  • No family drifted, so every family is adopted.

Pixels: no rendering change

Core harness (core main, 16b566e1, i.e. 3.8.0 + #710), plugins main (2d97e56) vs this branch, alternating before/after/before as a control, compared pixel by pixel (ImageChops.difference), Pillow 12.3.0 at start and end:

Set Frames Differ
Harness screens (9 plugins x sizes) 192 0
Scroll / Vegas cards 72 0
Celebration frames 135 0
Total 399 0

Control (before vs before): 399 frames, 0 differ. The branch also passes its committed card and celebration goldens. In a fresh process each plugin's adopted names resolve to the core modules (ufc's _card_option still to sports_shared, as before).

Monorepo checks

With LEDMATRIX_CORE at a fresh core main checkout:

  • run_plugin_tests.py on the nine, plugins main vs this branch: 333 passed, 2 failed on both sides, the same two pre-existing failures (baseball test_odds_placement.py; football's interactive test_football_plugin.py, which prompts for input).
  • Every scripts/test_*.py: all 45 pass on main, and all 46 on this branch (the new test_stage4_mixin_copies.py included).
  • check_version_bump.py --base origin/main with the nine ids, check_manifest_version_fields, check_min_core_version, check_manifests_ascii, check_module_collisions, check_scroll_adoption, check_sports_display_contract, check_core_api_signatures, check_sports_drift, check_sports_helpers_parity, update_registry.py --check: all pass.

🤖 Generated with Claude Code

ChuckBuilds and others added 4 commits October 1, 2026 14:41
… mixins; drop the copies (stage 4)

Core 3.8.0 (core #705) ships four modules holding the method
families every scoreboard carrying them had as an identical copy (the
"identical sweep"). Each plugin now inherits the mixins and deletes its
copies; imports are plain (the next commit floors every plugin on 3.8.0).

- manager.py, all nine: the plugin class inherits SportsPluginHostMixin
  (src.common.sports_plugin_host), listed before BasePlugin, and loses
  _dispatch_switch_refresh, _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 and
  _build_manager_key, with the "Vegas ticker weighting" comment header that
  introduced them.
- manager.py, the eight with a live strip (not ufc): it also inherits
  SportsLiveScrollMixin (src.common.sports_live_scroll) and loses
  _live_scroll_managers, _refresh_live_scroll_managers, _live_scroll_fields,
  _fingerprint_games, _live_scroll_fingerprint, _live_scroll_needs_rebuild,
  _note_live_scroll_built, _preserving_scroll_position and the two
  LIVE_SCROLL_REBUILD_* constants. LIVE_VOLATILE_FIELDS stays: afl, nrl and
  soccer also ignore period_text.
- sports.py: SportsCore inherits SportsCardOptionsMixin (the eight team
  scoreboards; first, ahead of SportsCoreSharedMixin, whose _card_option it
  wraps) and SportsGameRulesMixin (all nine), from
  src.common.sports_display_rules, and loses _card_option,
  _recent_date_text, _filtered_or_all and _effective_live_duration
  (SportsLive's copy in baseball, basketball, football, hockey and lacrosse).
- _resolve_font_path in every sports.py and game_renderer.py, and in ufc's
  fight_renderer.py and headshot_downloader.py, is imported from
  src.common.sports_font_path (resolve_font_path) under the same name, so
  callers and baseball.py's import are unchanged. ufc's
  generate_placeholder_icon.py, a hand-run tool, keeps its copy.

Imports only the deleted code used are dropped (contextlib.contextmanager;
threading in football, hockey, lacrosse and ufc --
baseball keeps it, since #582's get_vegas_elements uses threading.Event; os in ufc's two
files). pyflakes reports nothing new.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
afl 1.35.1, baseball 1.54.3, basketball 1.41.1, football 3.18.1,
hockey 1.40.1, lacrosse 1.36.1, nrl 1.34.1, soccer 2.39.1, ufc 1.19.1.

Every plugin already floors on core 3.8.0 (#582's live Vegas cards), the
release that ships src.common.sports_plugin_host, sports_live_scroll,
sports_display_rules and sports_font_path, which the previous commit imports
plainly. The floor does not rise, so these are patch bumps; each has a new
versions[0] entry (ledmatrix_min_version 3.8.0) and a CHANGELOG entry naming
what the plugin dropped. plugins.json regenerated with update_registry.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scripts/test_stage4_mixin_copies.py, in the shape of the stage 3 guard: for
every plugin adopting src.common.sports_plugin_host (all nine),
src.common.sports_live_scroll (all but ufc) or src.common.sports_display_rules
(SportsCardOptionsMixin: all but ufc; SportsGameRulesMixin: all nine), no
runtime file may define a moved name again -- a method or class constant on
any class, or a module-level _resolve_font_path -- except what KEEP lists
with its reason (baseball's renderer has its own, different
_recent_date_text; ufc's hand-run generate_placeholder_icon.py keeps its font
resolver). The mixin must be imported plainly and be a base of the plugin
class / SportsCore, SportsCardOptionsMixin ahead of SportsCoreSharedMixin;
every file that resolves fonts must import resolve_font_path from core under
its old name. With a core checkout the lists are compared with what core's
modules define, both ways. A self-check plants a copy, a guarded import, a
missing base, the wrong base order and an unaliased font import.

Mutation-checked: a method restored on soccer's plugin class, a constant on
nrl's, a font resolver in hockey's renderer, afl's import wrapped in try,
ufc's base dropped, football's mixins reordered, baseball's font import
unaliased and a name dropped from the list each fail it.

check_sports_drift.py passes unchanged; its baseline needs no edit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… code from core 3.8.0

docs 08: the sports.py and game_renderer.py rows say what else is core's,
manager.py gets a row, and the convergence list gains "Converged at 3.8.0"
naming the four modules, what each plugin inherits, the base-order rule,
ufc's kept placeholder-icon copy, the guard script and the identical
families deliberately left in the plugins. CLAUDE.md non-negotiable #7:
floor 3.8.0 and the four modules.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 437d4c71-d9b6-44df-9df1-474196629471

  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codacy-production

codacy-production Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 296 complexity

Metric Results
Complexity 296

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

Baseball._recent_date_text (#588) is not a copy of the promoted method: with
a series line the full-screen Recent card draws its own bottom row, so it
blanks the date there and otherwise defers to core's via super(). KEEP it
with that reason. Found by CI: the local guard loop recorded the exit code
of a command substitution rather than of the guard.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ChuckBuilds
ChuckBuilds merged commit 56e3f7a into main Oct 1, 2026
5 checks passed
@ChuckBuilds
ChuckBuilds deleted the claude/sports-stage4-adoption branch October 1, 2026 19:14
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