Skip to content

feat(sports): share the card helpers the eight scoreboards each carried - #513

Merged
ChuckBuilds merged 1 commit into
mainfrom
feat/sports-card-helpers
Sep 2, 2026
Merged

feat(sports): share the card helpers the eight scoreboards each carried#513
ChuckBuilds merged 1 commit into
mainfrom
feat/sports-card-helpers

Conversation

@ChuckBuilds

Copy link
Copy Markdown
Owner

Twenty methods were byte-identical in all eight scoreboards' game_renderer.py: the colour pickers, the scroll_card settings lookup, the date and time formatting, the favourite-team rules and the font-size grid snapping. Every fix to any of it had to be made eight times, and a new scoreboard began by copying them a ninth.

src/common/sports_card.py holds them once. 245 lines leave each plugin (companion plugins PR).

Free functions, not a base class

Every helper takes config / logger / fonts as arguments rather than reading them off an instance, so a plugin keeps its method and delegates the body — call sites, signatures and override points all untouched. Adoption is per-function and reversible, which is what let all eight move with byte-identical renders.

The bodies are the plugins' code moved, not rewritten. Two deliberate differences, both verified:

  • crisp_size takes the seven-plugin guard (not desired) rather than football's. They agree on every real input; the extra guard only stops a None size raising TypeError — so it is a no-op for seven plugins and removes a crash path for the eighth.
  • schema_font_size caches per schema path. The plugins cached on their own class; the path is that same distinction without a class to hang it on, and two plugins never share an entry. It must be passed in because the plugins derived it from __file__, and __file__ here is the core's.

Verified before any plugin was touched

1,238 differential comparisons against the plugins' own originals — zero differences. 534 of the helpers against afl's, and 704 of the font-sizing chain against all eight plugins' (including football, whose _crisp_size variant this replaces).

That check earned its keep: writing the constant tables by hand introduced two silent errors it caught — the tie colour was (255,255,0) instead of the plugins' (255,200,0), and I had invented a five_by_seven alias that does not exist. Both now come from the plugins verbatim, and all six tables are asserted equal.

Tests

43 tests pin the contract, including the cases the plugins' own comments record as having bitten:

  • a three-character string must not iterate into a colour
  • a shared font face must give up rather than guess which element owns it
  • a font_size equal to the schema default carries no intent (the web UI writes the whole default block on every save)
  • a bad timezone falls back to UTC rather than blanking the card
  • two plugins with different schema defaults must not share a cached answer

Full suite: 3768 passed, 6 skipped.

Sequencing

This is a pure addition — nothing imports it yet, so it is safe to merge on its own. The companion plugins PR floors at 3.3.0 and must not merge until that release is cut.

🤖 Generated with Claude Code

https://claude.ai/code/session_014RRtqXDCnvnY6EQwhT5CV9

Twenty methods were byte-identical in all eight scoreboards' game_renderer.py:
the colour pickers, the scroll_card settings lookup, the date and time
formatting, the favourite-team rules and the font-size grid snapping. Every fix
to any of it had to be made eight times, and a new scoreboard began by copying
them a ninth.

src/common/sports_card.py holds them once. 245 lines leave each plugin.

**Free functions, not a base class.** Every helper takes config/logger/fonts as
arguments rather than reading them off an instance, so a plugin keeps its
method and delegates the body -- call sites, signatures and override points are
all untouched. Adoption is therefore per-function and reversible, which is what
let all eight move with byte-identical renders.

The bodies are the plugins' code moved, not rewritten. Two deliberate
differences, both verified:

- crisp_size takes the seven-plugin guard (`not desired`) rather than
  football's. They agree on every real input; the extra guard only stops a
  None size raising TypeError, so adopting it is a no-op for seven plugins and
  removes a crash path for the eighth.
- schema_font_size caches per schema PATH. The plugins cached on their own
  class, which is the same distinction expressed without a class to hang it
  on; two plugins never share an entry. The path has to be passed in because
  the plugins derived it from __file__, and __file__ here is the core's.

Verified before any plugin was touched: 534 differential comparisons of the
helpers against afl's originals and 704 more of the font-sizing chain against
all eight plugins' originals -- 1,238 comparisons, zero differences. Writing
the constant tables by hand introduced two errors that check caught: the tie
colour was (255,255,0) instead of the plugins' (255,200,0), and a
"five_by_seven" alias that does not exist. Both are now taken from the plugins
verbatim.

43 tests pin the contract, including the cases the plugins' own comments record
as having bitten: a three-character string must not iterate into a colour, a
shared font face must give up rather than guess an element, a font_size equal
to the schema default carries no intent, and a bad timezone falls back to UTC
rather than blanking the card.

Full suite 3768 passed, 6 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014RRtqXDCnvnY6EQwhT5CV9
@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 43 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 9d6ff025-690b-432b-a389-6ae092174152

📥 Commits

Reviewing files that changed from the base of the PR and between 92f9d06 and 110d7b7.

📒 Files selected for processing (2)
  • src/common/sports_card.py
  • test/test_sports_card.py

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 124 complexity · 0 duplication

Metric Results
Complexity 124
Duplication 0

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.

@ChuckBuilds

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@ChuckBuilds

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@ChuckBuilds
ChuckBuilds merged commit 10da2f9 into main Sep 2, 2026
9 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.

1 participant