Skip to content

feat(scoreboards): inherit the shared sports.py logic from the core - #366

Merged
ChuckBuilds merged 3 commits into
mainfrom
feat/sports-shared-adoption
Sep 3, 2026
Merged

feat(scoreboards): inherit the shared sports.py logic from the core#366
ChuckBuilds merged 3 commits into
mainfrom
feat/sports-shared-adoption

Conversation

@ChuckBuilds

Copy link
Copy Markdown
Owner

Phase 3 adoption. Needs core ChuckBuilds/LEDMatrix#515. Independent of #359 (sports.py and game_renderer.py don't overlap), but versions are bumped above #359's since that lands first.

What changes

45 method bodies in each of these eight sports.py files were byte-identical to the same 45 in every other scoreboard — 1,007 lines per plugin, 8,056 duplicated. They now come from src.common.sports_shared and each class inherits the matching mixin.

8,321 lines removed.

Three identical bodies deliberately stayed behind

A byte-identical body is not automatically safe to move — it can bind a module-level name that differs per plugin.

  • _get_timezone binds resolve_timezone from a per-plugin module (hockey_timezone, soccer_timezone, …). All eight of those files differ — each carries its own _WRITEBACK_FIXED_IN — so hoisting the caller would have silently bound every scoreboard to one plugin's copy.
  • _extract_game_details / _fetch_data are @abstractmethod stubs — the sport contract.

Class constants are left in place, so each plugin's own values still shadow the mixin's defaults. That matters for afl and basketball, which set _SCORE_PROBE_TEXT to "000-000".

Test changes — all making tests exercise the real module, not a stub

Nineteen tests stubbed src/src.common as plain ModuleTypes, so the new import failed with 'src.common' is not a package. They now give those stubs a __path__ into the core, letting genuine submodules resolve while the stubbed ones stay stubbed.

Stubbing the mixins instead would have made all nineteen pass against dummies — which is exactly how B5 shipped four of eight scoreboards broken with every gate green.

soccer/test_schedule_horizon.py AST-parses sports.py for _get_weeks_data, which now lives in the core; it looks in both places, and its assertions are about the body, which moved verbatim.

Verification

safety-harness renders vs pristine main 176/176 byte-identical
plugin tests 245 passed
repo gates 5/5 pass

The one remaining fleet failure is 7-segment-clock/test_render_polarity.py, which fails identically on main and is fixed separately in #364.

One thing worth knowing

_schema_font_size located the plugin's config_schema.json via __file__, which breaks once the method lives in the core — measured at 81% anti-aliased edges instead of pixel-crisp. The 176 renders did not catch it; test_fonts_are_crisp.py did. Renders alone were not a sufficient gate for this change.

Forty-five method bodies in each of these eight sports.py files were
byte-identical to the same forty-five in every other scoreboard: 1,007 lines
per plugin, 8,056 duplicated in total. They now come from
src.common.sports_shared (ChuckBuilds/LEDMatrix#515) and each class inherits
the matching mixin. 8,321 lines removed.

Three of the forty-eight identical bodies stayed behind on purpose, because a
byte-identical body is not automatically safe to move:

- _get_timezone binds resolve_timezone from a per-plugin module
  (hockey_timezone, soccer_timezone, ...). All eight of those files differ --
  each carries its own _WRITEBACK_FIXED_IN -- so hoisting the caller would have
  silently bound every scoreboard to one plugin's copy.
- _extract_game_details and _fetch_data are @AbstractMethod stubs. They are the
  sport contract; satisfying them from a mixin would let a plugin instantiate
  without implementing its own sport.

Class constants are left in place rather than removed, so each plugin's own
values still shadow the mixin's defaults. That matters for afl and basketball,
which set _SCORE_PROBE_TEXT to "000-000"; the mixin's "00-00" is a default for
future plugins, not a change to these.

Test changes, all of them making tests exercise the real module rather than a
stub:

- Nineteen tests stubbed "src"/"src.common" as plain ModuleTypes, so the new
  import failed with "'src.common' is not a package". They now give those stubs
  a __path__ into the core, which lets genuine submodules resolve while the
  stubbed ones stay stubbed. Stubbing the mixins instead would have made every
  one of those tests pass against dummies -- which is how B5 shipped four of
  eight broken with every gate green.
- soccer/test_schedule_horizon.py AST-parses sports.py looking for
  _get_weeks_data, which now lives in the core. It looks in both places; its
  assertions are about the body, which moved verbatim.

Verification: all 176 safety-harness renders byte-identical to pristine main,
245 plugin tests pass, five repo gates pass. The one remaining fleet failure is
7-segment-clock/test_render_polarity.py, which fails identically on main and is
fixed separately in #364.

Versions are bumped above the sports_card/geometry branch rather than above
main, since that branch lands first and already claims the next minor.
@coderabbitai

coderabbitai Bot commented Sep 2, 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: Team

Run ID: be6fd703-8faf-42ca-88ff-5255f9db86ea


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

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 135 complexity

Metric Results
Complexity 135

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.

main gained the odds_text setting (#402) and the card-helper delegation (#359),
which together bumped every scoreboard past the numbers this branch claimed.
All eight manifests conflicted for that reason alone; no code conflicted.

Versions recomputed above main's: afl 1.22.0, baseball 1.40.0, basketball
1.29.0, football 3.4.0, hockey 1.25.0, lacrosse 1.24.0, nrl 1.21.0, soccer
2.24.0. plugins.json regenerated.

Checked that the three layers compose rather than assuming it. #402 added an
odds font slot and _odds_color() to the same game_renderer.py files #359
delegates twenty methods from, and this branch removes forty-five more methods
from sports.py next to them. All three are present together in every plugin:
the sports_shared mixin, the sports_card delegations, and the odds wiring.

Re-verified against main at the #359 merge: all 176 safety-harness renders
byte-identical.

The previous CI failure on this branch was stale, not a defect. It ran on
2026-09-02 20:17, and #515 -- which puts src/common/sports_shared.py on core
main -- merged 2026-09-03 17:29, twenty-one hours later. The workflow checks
the core out at CORE_REF: main, so the module simply did not exist yet when
that run imported it.
main gained #403, which adds odds_text to x-propertyOrder in all eight
scoreboards and bumps each a patch level. That is the only reason the manifests
conflicted again; no code conflicted.

Versions recomputed above main's: afl 1.22.0, baseball 1.40.0, basketball
1.29.0, football 3.4.0, hockey 1.25.0, lacrosse 1.24.0, nrl 1.21.0, soccer
2.24.0.

Verified all four layers coexist rather than assuming it -- the sports_shared
mixin, #359's sports_card delegations, #402's odds wiring, and #403's
x-propertyOrder entry are present together in every plugin. Four changes have
now landed on the same files this branch edits, so composition is the thing
most likely to break silently.

test_property_order_coverage.py, the guard that was failing this branch, now
passes: it was #402's omission, fixed by #403, not a defect here.
@ChuckBuilds
ChuckBuilds merged commit 73486b0 into main Sep 3, 2026
4 checks passed
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.

2 participants