Skip to content

feat(scoreboards): color a recent game's score by how the favorite team did - #259

Merged
ChuckBuilds merged 3 commits into
mainfrom
claude/sports-ticker-favorite-colors-s5hh0e
Aug 6, 2026
Merged

feat(scoreboards): color a recent game's score by how the favorite team did#259
ChuckBuilds merged 3 commits into
mainfrom
claude/sports-ticker-favorite-colors-s5hh0e

Conversation

@ChuckBuilds

@ChuckBuilds ChuckBuilds commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Pull Request

Summary

Adds an optional customization.favorite_result_colors setting to the eight team scoreboards: with it on, a finished game's score is drawn green when your favorite team won and red when it lost. The motivating case is scroll/Vegas mode, where a series against the same opponent goes past as several near-identical cards — same two logos, only the digits change — and there is no quick way to tell a win from a loss. Off by default, so nothing changes until a user opts in.

Type of change

  • Bug fix in an existing plugin
  • New plugin (also fill out the SUBMISSION.md checklist below)
  • New feature for an existing plugin
  • Documentation only
  • Repo-wide change (registry script, hook, top-level docs)

Also carries one incidental schema fix — see Notes for reviewer.

Plugin(s) affected

afl-scoreboard, baseball-scoreboard, basketball-scoreboard, football-scoreboard, hockey-scoreboard, lacrosse-scoreboard, nrl-scoreboard, soccer-scoreboard

Not touched: cricket-scoreboard (already greens the winner and uses a different renderer), ufc-scoreboard (fights have no numeric score), f1-scoreboard (no favorite-team win/loss).

Related issues

N/A

Test plan

  • Loaded the plugin in LEDMatrix on real hardware
  • Loaded the plugin in LEDMatrix emulator mode (EMULATOR=true python3 run.py)
  • Rendered the plugin in the dev preview server (scripts/dev_server.py)
  • Verified the web UI configuration form against the schema
  • Other — see below

What was run in this environment:

  • New unit tests: plugins/baseball-scoreboard/test_favorite_result_colors.py (8 groups, all passing) covers win/loss/tie/no-favorite/both-favorites, the feature being off by default, unusable scores, custom + clamped + malformed colors, all three sources of favorites, and the nested hockey/lacrosse payload shape.
  • End-to-end render check on all 8 plugins: rendered a real recent card through GameRenderer.render_game_card(game, "recent") and confirmed the score pixels come out green on a win and red on a loss, and that the card is pixel-identical to before with the feature off.
  • Full existing test sweep across the 8 plugins before and after: the set of failures is byte-identical to the baseline (all are environment skips — no core src on the path, no pytest, interactive prompts, missing fonts). nrl-scoreboard/test_nrl_plugin.py needed a one-line update because it asserted the old (broken) location of the customization block; it passes.
  • python scripts/check_module_collisions.py — OK, no new modules were added.

The core safety harness could not be run here (it lives in the LEDMatrix core repo). Worth an eyeball on hardware, though the golden fixtures all use favorite_teams: [], so the feature is inert for them.

Required for plugin changes

  • Bumped version in plugins/<id>/manifest.json — AFL 1.4.0, baseball 1.23.0, basketball 1.11.0, football 2.12.0, hockey 1.8.0, lacrosse 1.8.0, NRL 1.4.0, soccer 2.7.0, each with a versions changelog entry
  • class_name in manifest.json matches the actual class in manager.py exactly — unchanged
  • entry_point matches the real file — unchanged
  • Updated the plugin's README.md if config keys changed — new Favorite Team Result Colors section plus a feature bullet in all 8
  • config_schema.json is the source of truth for the web UI form — enabled (default: false) plus win_color / loss_color / tie_color colour-picker arrays marked x-advanced, all with defaults, descriptions and constraints
  • Pre-commit hook ran successfully (auto-syncs plugins.json)

Checklist

  • My commits follow the message convention in CONTRIBUTING.md
  • I read CONTRIBUTING.md and CODE_OF_CONDUCT.md
  • I've not committed any secrets

Notes for reviewer

Two render paths, deliberately. The switch view (sports.py) and the scroll/Vegas cards (game_renderer.py) are independent copies, so the colour is resolved in both. get_vegas_content() renders through game_renderer, so the ticker case is covered by that half. Only finished games are tinted — _score_color_for(game, game_type) returns the normal colour for live and upcoming cards.

Why "exactly one favorite team". If neither side is a favorite the score is left alone; if both are, it is also left alone, since a favorite-vs-favorite game has no losing side worth flagging in red. Non-numeric or missing scores (postponements) fall back to the normal colour too.

Where favorites come from in the scroll renderer. GameRenderer only ever sees the game dict and the raw config, so games now carry their league manager's resolved favorites ("favorite_teams" in _extract_game_details_common) — that is the only place dynamic groups such as AP_TOP_25 appear expanded. The raw config is read as well and the two are unioned, so a config edit applies before the next data refresh and hand-built game dicts still work. Matching accepts the ESPN id as well as the abbreviation, which is how NRL keys its favorites.

Incidental fix worth a look: NRL and Soccer declared their customization block at the schema root, a sibling of properties rather than one of them. The web UI renders properties, and the root sets additionalProperties: false, so that block was inert and a config setting customization would not validate. This PR moves it into properties (and adds it to the root x-propertyOrder), which is what makes the new setting reachable there — but it also means the existing font/layout customization UI appears for those two plugins for the first time. That is the desired behaviour as far as I can tell, since their sports.py already reads those keys, but it is the one change here that is not purely additive. It accounts for most of the line count in those two schema diffs (the block is re-indented one level). test_nrl_plugin.py asserted the old location and is updated accordingly.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RRLLpvsvXgy1pskvaNVJWx


Generated by Claude Code

Summary by CodeRabbit

  • New Features
    • Added optional favorite-team result colors across baseball, basketball, football, hockey, lacrosse, soccer, AFL, and NRL scoreboards.
    • Finished-game scores can display distinct colors for wins, losses, and ties.
    • Colors are customizable with RGB values and apply only when exactly one favorite team is identified; live and upcoming games retain existing colors.
  • Documentation
    • Added configuration guidance, defaults, eligibility rules, and supported display modes.
  • Chores
    • Updated plugin versions and release histories across all supported scoreboards.

…am did

In scroll and Vegas modes a series against the same opponent scrolls past as
several near-identical cards -- same two logos, only the digits change -- and
working out which of them your team won means reading the score and remembering
which side you are. That is the whole problem this fixes.

Adds customization.favorite_result_colors to the eight team scoreboards that
show a numeric final score (AFL, baseball, basketball, football, hockey,
lacrosse, NRL, soccer): with it enabled, a finished game's score is drawn green
when the favorite team won and red when it lost, with all three colors
configurable. Off by default, so nothing changes until a user opts in.

The colour is resolved in both render paths, which are independent copies:
SportsCore for the one-game-at-a-time switch view and GameRenderer for the
scroll/Vegas cards (which is also what get_vegas_content renders through). Only
finished games are tinted; live and upcoming cards are untouched. A game needs
exactly one favorite team -- neither side, or both, keeps the normal color,
since a favorite-vs-favorite game has no losing side worth flagging in red.

Games now carry their league manager's resolved favorites so the scroll
renderer, which otherwise only sees the game dict and the raw config, can match
dynamic groups such as AP_TOP_25; the raw config is read as well so an edit
applies before the next data refresh. Matching accepts the ESPN id as well as
the abbreviation, which is how NRL keys its favorites.

NRL and Soccer declared their customization block at the schema root rather
than inside properties, so the web UI never rendered it and setting it tripped
the root's additionalProperties. Moved it where it belongs, which is also what
makes the new setting reachable there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RRLLpvsvXgy1pskvaNVJWx
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@ChuckBuilds, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 46 minutes

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

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9a7341e8-0f26-473a-bf8a-4048c6b25278

📥 Commits

Reviewing files that changed from the base of the PR and between 43621ec and 4ad34ac.

📒 Files selected for processing (17)
  • plugins/afl-scoreboard/game_renderer.py
  • plugins/afl-scoreboard/sports.py
  • plugins/baseball-scoreboard/game_renderer.py
  • plugins/baseball-scoreboard/sports.py
  • plugins/baseball-scoreboard/test_favorite_result_colors.py
  • plugins/basketball-scoreboard/game_renderer.py
  • plugins/basketball-scoreboard/sports.py
  • plugins/football-scoreboard/game_renderer.py
  • plugins/football-scoreboard/sports.py
  • plugins/hockey-scoreboard/game_renderer.py
  • plugins/hockey-scoreboard/sports.py
  • plugins/lacrosse-scoreboard/game_renderer.py
  • plugins/lacrosse-scoreboard/sports.py
  • plugins/nrl-scoreboard/game_renderer.py
  • plugins/nrl-scoreboard/sports.py
  • plugins/soccer-scoreboard/game_renderer.py
  • plugins/soccer-scoreboard/sports.py
📝 Walkthrough

Walkthrough

Eight scoreboard plugins add optional favorite-team result colors for finished games. The change includes validated configuration, result classification, renderer integration, tests, documentation, release notes, and catalog version updates.

Changes

Favorite result colors

Layer / File(s) Summary
Configuration contracts and documentation
plugins/*-scoreboard/config_schema.json, plugins/*-scoreboard/README.md, plugins/nrl-scoreboard/test_nrl_plugin.py
Adds customization.favorite_result_colors with validated win, loss, and tie RGB values. Documents eligibility, defaults, display modes, and configuration behavior.
Favorite resolution and result classification
plugins/*-scoreboard/sports.py
Detects favorite teams by abbreviation or ID, classifies finished games, clamps RGB values, propagates favorite data, and preserves fallback colors for invalid or ambiguous cases.
Score rendering and validation
plugins/*-scoreboard/game_renderer.py, plugins/baseball-scoreboard/test_favorite_result_colors.py
Applies result colors to recent scores while preserving live and upcoming defaults. Tests cover favorite sources, outcomes, payload shapes, invalid data, and color fallback behavior.
Release catalog updates
plugins.json, plugins/*-scoreboard/manifest.json
Updates plugin versions and adds release-history entries for the feature.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SportsCore
  participant GameDetails
  participant GameRenderer
  SportsCore->>GameDetails: attach resolved favorite teams
  GameDetails->>GameRenderer: provide teams, scores, and game state
  GameRenderer->>GameRenderer: classify result and resolve RGB color
  GameRenderer->>GameRenderer: render recent score
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: coloring recent scoreboard scores based on favorite-team results.
Docstring Coverage ✅ Passed Docstring coverage is 83.45% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/sports-ticker-favorite-colors-s5hh0e

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 Aug 5, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 460 complexity

Metric Results
Complexity 460

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.

The scroll/Vegas recent card was the only place in any scoreboard that drew a
final score gold. This plugin's own switch-mode scorebug draws it white, and so
does every other sport, so the same game changed colour depending on which
display mode you were in.

Folded into the 1.23.0 entry rather than a separate bump: that version is not
released yet, and this ships with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RRLLpvsvXgy1pskvaNVJWx
@ChuckBuilds

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
plugins/afl-scoreboard/sports.py (1)

490-494: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Annotate FAVORITE_RESULT_COLOR_DEFAULTS with ClassVar in all four files. Each file declares the same mutable dict as a class attribute without a ClassVar annotation, and Ruff reports RUF012 at every site. The repository already follows this pattern with TOURNAMENT_ROUND_ORDER: ClassVar[Dict[str, int]] in plugins/basketball-scoreboard/sports.py.

  • plugins/afl-scoreboard/sports.py#L490-L494: add : ClassVar[Dict[str, tuple]] and import ClassVar from typing.
  • plugins/basketball-scoreboard/sports.py#L327-L331: add : ClassVar[Dict[str, tuple]]; ClassVar is already imported.
  • plugins/basketball-scoreboard/game_renderer.py#L294-L298: add : ClassVar[Dict[str, tuple]] and import ClassVar from typing.
  • plugins/soccer-scoreboard/game_renderer.py#L291-L295: add : ClassVar[Dict[str, tuple]] and import ClassVar from typing.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/afl-scoreboard/sports.py` around lines 490 - 494, Annotate
FAVORITE_RESULT_COLOR_DEFAULTS as ClassVar[Dict[str, tuple]] in all four sites:
plugins/afl-scoreboard/sports.py:490-494,
plugins/basketball-scoreboard/sports.py:327-331,
plugins/basketball-scoreboard/game_renderer.py:294-298, and
plugins/soccer-scoreboard/game_renderer.py:291-295. Add the ClassVar import from
typing in the AFL sports, basketball game_renderer, and soccer game_renderer
files; basketball sports already imports it.

Source: Linters/SAST tools

plugins/baseball-scoreboard/test_favorite_result_colors.py (1)

158-183: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add scroll/Vegas tie-color coverage.

GameRenderer._favorite_result() has a separate tie branch, but this path only tests wins and losses. Add assertions for the default tie color and a configured tie_color.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/baseball-scoreboard/test_favorite_result_colors.py` around lines 158
- 183, Extend test_scroll_card_colors around GameRenderer._recent_score_color
with finished-game tie assertions, covering the default tie color and a
separately configured tie_color. Use a tied game and verify the configured
renderer returns the expected custom color, while the default renderer preserves
the established default tie color.
plugins/football-scoreboard/sports.py (2)

446-450: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Score parsing is stricter here than in the renderer.

SportsCore._favorite_result uses int(str(...).strip()). The matching GameRenderer._side_score uses int(float(...)). A score value such as "5.0" resolves in scroll mode but falls back to the default color in switch mode. ESPN returns integer strings today, so this is a consistency concern rather than a current defect. Align both paths on one parse rule.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/football-scoreboard/sports.py` around lines 446 - 450, Align score
parsing in SportsCore._favorite_result with GameRenderer._side_score by applying
the same int(float(...)) conversion to both home_score and away_score, while
preserving the existing invalid-value fallback behavior.

400-404: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Mutable class attribute FAVORITE_RESULT_COLOR_DEFAULTS repeated across six modules. Ruff reports RUF012 at each site because the same dict literal is copied into every plugin as a class attribute. Annotate it as ClassVar (or wrap it in types.MappingProxyType) so the value cannot be mutated per instance. Apply the same pattern at every site.

  • plugins/football-scoreboard/sports.py#L400-L404: annotate the dict as ClassVar[Dict[str, Tuple[int, int, int]]] and add ClassVar/Tuple to the typing import.
  • plugins/hockey-scoreboard/sports.py#L351-L355: apply the same annotation and import update.
  • plugins/football-scoreboard/game_renderer.py#L385-L389: apply the same annotation and import update.
  • plugins/hockey-scoreboard/game_renderer.py#L329-L333: apply the same annotation and import update.
  • plugins/nrl-scoreboard/game_renderer.py#L291-L295: apply the same annotation and import update.
  • plugins/lacrosse-scoreboard/game_renderer.py#L338-L342: apply the same annotation and import update.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/football-scoreboard/sports.py` around lines 400 - 404, Make
FAVORITE_RESULT_COLOR_DEFAULTS a ClassVar[Dict[str, Tuple[int, int, int]]] and
add ClassVar and Tuple to the typing imports in
plugins/football-scoreboard/sports.py#L400-L404,
plugins/hockey-scoreboard/sports.py#L351-L355,
plugins/football-scoreboard/game_renderer.py#L385-L389,
plugins/hockey-scoreboard/game_renderer.py#L329-L333,
plugins/nrl-scoreboard/game_renderer.py#L291-L295, and
plugins/lacrosse-scoreboard/game_renderer.py#L338-L342.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/lacrosse-scoreboard/sports.py`:
- Around line 359-365: Update _coerce_rgb in
plugins/lacrosse-scoreboard/sports.py (lines 359-365) and
plugins/nrl-scoreboard/sports.py (lines 516-522) to first require value to be a
list or tuple containing exactly three items; otherwise return fallback.
Preserve the existing per-channel integer conversion and clamping for valid RGB
sequences.

---

Nitpick comments:
In `@plugins/afl-scoreboard/sports.py`:
- Around line 490-494: Annotate FAVORITE_RESULT_COLOR_DEFAULTS as
ClassVar[Dict[str, tuple]] in all four sites:
plugins/afl-scoreboard/sports.py:490-494,
plugins/basketball-scoreboard/sports.py:327-331,
plugins/basketball-scoreboard/game_renderer.py:294-298, and
plugins/soccer-scoreboard/game_renderer.py:291-295. Add the ClassVar import from
typing in the AFL sports, basketball game_renderer, and soccer game_renderer
files; basketball sports already imports it.

In `@plugins/baseball-scoreboard/test_favorite_result_colors.py`:
- Around line 158-183: Extend test_scroll_card_colors around
GameRenderer._recent_score_color with finished-game tie assertions, covering the
default tie color and a separately configured tie_color. Use a tied game and
verify the configured renderer returns the expected custom color, while the
default renderer preserves the established default tie color.

In `@plugins/football-scoreboard/sports.py`:
- Around line 446-450: Align score parsing in SportsCore._favorite_result with
GameRenderer._side_score by applying the same int(float(...)) conversion to both
home_score and away_score, while preserving the existing invalid-value fallback
behavior.
- Around line 400-404: Make FAVORITE_RESULT_COLOR_DEFAULTS a ClassVar[Dict[str,
Tuple[int, int, int]]] and add ClassVar and Tuple to the typing imports in
plugins/football-scoreboard/sports.py#L400-L404,
plugins/hockey-scoreboard/sports.py#L351-L355,
plugins/football-scoreboard/game_renderer.py#L385-L389,
plugins/hockey-scoreboard/game_renderer.py#L329-L333,
plugins/nrl-scoreboard/game_renderer.py#L291-L295, and
plugins/lacrosse-scoreboard/game_renderer.py#L338-L342.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 11f02605-ee6d-493f-8d86-ddbf0b6c9a5e

📥 Commits

Reviewing files that changed from the base of the PR and between 7369463 and 43621ec.

📒 Files selected for processing (43)
  • plugins.json
  • plugins/afl-scoreboard/README.md
  • plugins/afl-scoreboard/config_schema.json
  • plugins/afl-scoreboard/game_renderer.py
  • plugins/afl-scoreboard/manifest.json
  • plugins/afl-scoreboard/sports.py
  • plugins/baseball-scoreboard/README.md
  • plugins/baseball-scoreboard/config_schema.json
  • plugins/baseball-scoreboard/game_renderer.py
  • plugins/baseball-scoreboard/manifest.json
  • plugins/baseball-scoreboard/sports.py
  • plugins/baseball-scoreboard/test_favorite_result_colors.py
  • plugins/basketball-scoreboard/README.md
  • plugins/basketball-scoreboard/config_schema.json
  • plugins/basketball-scoreboard/game_renderer.py
  • plugins/basketball-scoreboard/manifest.json
  • plugins/basketball-scoreboard/sports.py
  • plugins/football-scoreboard/README.md
  • plugins/football-scoreboard/config_schema.json
  • plugins/football-scoreboard/game_renderer.py
  • plugins/football-scoreboard/manifest.json
  • plugins/football-scoreboard/sports.py
  • plugins/hockey-scoreboard/README.md
  • plugins/hockey-scoreboard/config_schema.json
  • plugins/hockey-scoreboard/game_renderer.py
  • plugins/hockey-scoreboard/manifest.json
  • plugins/hockey-scoreboard/sports.py
  • plugins/lacrosse-scoreboard/README.md
  • plugins/lacrosse-scoreboard/config_schema.json
  • plugins/lacrosse-scoreboard/game_renderer.py
  • plugins/lacrosse-scoreboard/manifest.json
  • plugins/lacrosse-scoreboard/sports.py
  • plugins/nrl-scoreboard/README.md
  • plugins/nrl-scoreboard/config_schema.json
  • plugins/nrl-scoreboard/game_renderer.py
  • plugins/nrl-scoreboard/manifest.json
  • plugins/nrl-scoreboard/sports.py
  • plugins/nrl-scoreboard/test_nrl_plugin.py
  • plugins/soccer-scoreboard/README.md
  • plugins/soccer-scoreboard/config_schema.json
  • plugins/soccer-scoreboard/game_renderer.py
  • plugins/soccer-scoreboard/manifest.json
  • plugins/soccer-scoreboard/sports.py

Comment thread plugins/lacrosse-scoreboard/sports.py
…th paths

Addresses the CodeRabbit review on #259. Each helper is duplicated per plugin,
so every one of the 16 copies is fixed, not just the sites the review named.

_coerce_rgb accepted any 3-element iterable, so a configured colour of "123"
unpacked into (1, 2, 3) -- a near-black -- instead of falling back. Only a
3-character string hit this (a short list or a longer one already failed the
unpack), but it silently produced a colour where the intent was a fallback.
Now requires a list or tuple of exactly three items.

SportsCore._favorite_result parsed scores with int(str(...)) while
GameRenderer._side_score used int(float(...)), so "5.0" coloured in scroll mode
but not in switch mode. ESPN returns integer strings today so nothing was
visibly broken, but the two paths must agree on what a usable score is; both
now use int(float(...)). A new test asserts they agree rather than checking
each in isolation.

FAVORITE_RESULT_COLOR_DEFAULTS is annotated ClassVar (RUF012), matching the
existing TOURNAMENT_ROUND_ORDER annotation in basketball's sports.py.

Tests: the malformed-colour case is now a table including "123", and the
scroll/Vegas path covers its own tie branch, default and configured.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RRLLpvsvXgy1pskvaNVJWx
@ChuckBuilds
ChuckBuilds merged commit 5fb40ad into main Aug 6, 2026
4 checks passed
@ChuckBuilds
ChuckBuilds deleted the claude/sports-ticker-favorite-colors-s5hh0e branch August 6, 2026 12:47
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