Skip to content

fix(scoreboards): recent games return when favourites are set; make nrl/afl fixtures render - #341

Merged
ChuckBuilds merged 1 commit into
mainfrom
fix/nrl-afl-harness-fixtures
Aug 30, 2026
Merged

fix(scoreboards): recent games return when favourites are set; make nrl/afl fixtures render#341
ChuckBuilds merged 1 commit into
mainfrom
fix/nrl-afl-harness-fixtures

Conversation

@ChuckBuilds

Copy link
Copy Markdown
Owner

Summary

SportsRecent.update() calls self._favorites_first(...). In every lineage except football that helper — and _other_games_window and _is_favorite_game with it — is defined on SportsUpcoming, a sibling of SportsRecent rather than an ancestor, so the call raises AttributeError. update() catches it, logs Error updating recent games, and carries on with an empty list — so the recent screen shows nothing at all.

It only bites when favourite teams are configured without show_favorite_teams_only (the elif self.favorite_teams: branch), which is the ordinary way to use the setting. Reproduced directly:

hockey     SportsRecent inherits _favorites_first: False
football   SportsRecent inherits _favorites_first: True
nrl        SportsRecent inherits _favorites_first: False

football already had all three on SportsCore; this moves them there in the other eight. The class attributes they read (other_recent_games_to_show, _other_window_start, …) are already assigned in SportsCore.__init__ everywhere, so nothing else had to move.

Why no test caught it

The two fixtures that would have are blank, and the safety harness cannot fail a blank card — it only fails on a crash or an overflow.

nrl — 30 of 30 renders blank. Its mock seeded the raw ESPN payload at the top level (leagues/season/events) instead of under the cache key the manager reads, so every lookup missed. Its favourite teams were numeric ids, which the resolver rejects outright ('18' is not a NRL team code). Now keyed nrl_schedule_20260626-20260717 — what NrlBaseManager builds from the frozen clock and the 14/7 window — with nrl_scoreboard_current seeded for the live view, and favourites PEN/SYD, which play in the fixture's games. That last part is the point: it makes the harness exercise the favourites-first path that was broken instead of skipping it.

afl — 20 of 30 blank, and the 10 that rendered were worse than blank. Its key was afl_schedule_20260626-20260724, written when the lookahead default was 14; it is 7 now, so the plugin asked for ...-20260717, missed, and fell through to a live ESPN fetch. The recent screen looked healthy because it was drawing real 2026 AFL results off the network — St Kilda 75-102 Geelong, a match not in the fixture at all. Key corrected, afl_scoreboard_current seeded, and the fixture's in-progress game moved from 26 hours before its own frozen clock to 30 minutes before it, so it is live in the sense the fixture's own comment already claimed.

test_nrl_plugin asserted the broken shape (mock["events"] at the top level), so it now asserts the cache keys as well as the contents — the key is the invariant that was wrong.

Type of change

  • Bug fix in an existing plugin

Plugin(s) affected

afl · baseball · basketball · hockey · lacrosse · nrl · soccer · ufc — patch bumps. football-scoreboard is untouched; it already had the helpers in the right place.

Test plan

  • Rendered every affected plugin through the core safety harness

216 harness renders, all PASS, no overflow or fill warnings, across 64x32, 128x32, 96x48, 192x48, 128x64, 256x64, 256x128, 384x96.

before after
nrl blank renders 24/24 0/24
afl blank renders 8/24 0/24
  • Byte-identical with the network blackholed (HTTP(S)_PROXY pointed at a dead port) — the check that proves afl is no longer reading from ESPN.
  • The other seven plugins are byte-identical to origin/main: their fixtures set no favourites, so the broken path was never reached there and moving the helpers changes nothing.
  • Plugin self-test failures identical to origin/main (11 pre-existing on this machine).
  • check_module_collisions.py clean across 43 plugins; plugins.json regenerated by update_registry.py.

Notes for reviewer

  • The helper move is mechanical and behaviour-preserving — the byte-identical renders on the seven plugins that don't hit the path are the evidence. nrl's new fixture is what actually exercises it.
  • Known and not addressed here: nrl's MEL/SYD/PAR logo assets resolve to the wrong images — an Italy crest, a Rugby Romania wordmark, and a palm tree. Those files are downloaded at runtime rather than committed, so this is a logo-downloader mapping bug for rugby league, not a fixture one. Worth its own issue; it is visible in the nrl recent/upcoming renders now that they render at all.
  • Worth considering separately: the harness reaching the network at all is what let afl's fixture rot unnoticed for however long. A no-network mode would turn that class of failure into a hard error instead of a silent fallback.

🤖 Generated with Claude Code

…rl/afl fixtures render

SportsRecent.update() calls self._favorites_first(...). In every lineage except
football that helper -- and _other_games_window and _is_favorite_game with it --
is defined on SportsUpcoming, a SIBLING of SportsRecent rather than an ancestor,
so the call raises AttributeError. update() catches it, logs "Error updating
recent games", and carries on with an empty list, so the recent screen shows
nothing at all.

It only bites when favourite teams are configured WITHOUT
show_favorite_teams_only -- the `elif self.favorite_teams:` branch -- which is
the ordinary way to use the setting. Reproduced directly:

    hockey     SportsRecent inherits _favorites_first: False
    football   SportsRecent inherits _favorites_first: True
    nrl        SportsRecent inherits _favorites_first: False

football already had all three on SportsCore. This moves them there in the other
eight. The class attributes they read (other_recent_games_to_show,
_other_window_start, ...) are already assigned in SportsCore.__init__ everywhere,
so nothing else had to move.

Why no test caught it: the two fixtures that would have are blank.

nrl -- 30 of 30 harness renders were blank. Its mock seeded the raw ESPN payload
at the top level (leagues/season/events) rather than under the cache key the
manager reads, so every lookup missed; and its favourite teams were numeric ids,
which the resolver rejects with "not a NRL team code". Now keyed
nrl_schedule_20260626-20260717 -- what NrlBaseManager builds from the frozen
clock and the 14/7 window -- with nrl_scoreboard_current seeded for the live
view, and favourites PEN and SYD, which play in the fixture's games. That last
part matters: it is what makes the harness exercise the favourites-first path
that was broken, rather than skip it.

afl -- 20 of 30 blank, and the 10 that rendered were worse than blank. Its key
was afl_schedule_20260626-20260724, written when the lookahead default was 14;
it is 7 now, so the plugin asked for ...-20260717, missed, and fell through to a
LIVE ESPN FETCH. The recent screen looked healthy because it was drawing real
2026 AFL results off the network -- St Kilda 75-102 Geelong, a match not in the
fixture at all. Key corrected, afl_scoreboard_current seeded, and the fixture's
in-progress game moved from 26 hours before its own frozen clock to 30 minutes
before it, so it is live in the sense the fixture's comment already claimed.

test_nrl_plugin asserted the broken shape (mock["events"] at the top level), so
it is updated to assert the cache KEYS as well as the contents -- the key is the
invariant that was wrong, and a fixture that renders blank is invisible to the
safety harness, which only fails on a crash or an overflow.

Verified against origin/main across eight sizes:

  * 216 harness renders, all PASS, no overflow or fill warnings.
  * nrl and afl: 0 of 24 renders blank each, down from 24 and 8.
  * Byte-identical with the network blackholed (HTTP(S)_PROXY to a dead port),
    which is the check that proves afl is no longer reading from ESPN.
  * The other seven plugins are byte-identical to origin/main -- their fixtures
    set no favourites, so the broken path was never reached there and moving the
    helpers changes nothing.
  * Plugin self-test failures identical to origin/main (11 pre-existing here).
  * check_module_collisions clean across 43 plugins; plugins.json regenerated.

Known and NOT addressed here: nrl's MEL/SYD/PAR logo assets resolve to the wrong
images (an Italy crest, a Rugby Romania wordmark, a palm tree). Those files are
downloaded at runtime, not committed, so this is a logo-downloader mapping bug
for rugby league rather than a fixture one -- worth its own issue.

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

coderabbitai Bot commented Aug 30, 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: Pro Plus

Run ID: 747587a2-08d0-45ac-aea4-18dcc5a48c31


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

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
ChuckBuilds merged commit 4deee1e into main Aug 30, 2026
4 checks passed
@ChuckBuilds
ChuckBuilds deleted the fix/nrl-afl-harness-fixtures branch August 30, 2026 22:24
ChuckBuilds pushed a commit that referenced this pull request Aug 31, 2026
… this

Main moved a long way under this branch. Resolving hunk by hunk showed the
work splits cleanly in two, and the halves want opposite resolutions.

**football-scoreboard is fully superseded.** What this branch does for football
shipped as #335 and was then improved by #341, #343 and #344. Main is strictly
ahead everywhere they overlap: it season-corrects the division roster lookup,
str()-guards ESPN's broadcast field, catches OverflowError on a bare Infinity,
routes the no-favourites branch through _favorites_first so it builds selection
pools, and adds _attach_odds_to_rotated_games, which this branch does not have
at all. Several of main's comments describe this branch's own approach as the
old way. Every football hunk therefore takes main, and football's sports.py,
manager.py, data_sources.py, tests and README now match origin/main byte for
byte -- this branch no longer changes football in any way.

**The other eight lineages still need all of it.** They have _favorites_first
and nothing else: no _compose_selection, no rotation, no _passes_other_filters.
Their settings were in the schema with nothing reading them. Those hunks take
this branch.

Three resolutions worth naming:

- baseball, basketball, hockey and lacrosse: main re-adds _is_favorite_game
  beside the rotation methods this branch adds. Taking both would have defined
  it twice in one class, and Python takes the last -- main's copy would have
  silently shadowed this branch's. Kept one, plus main's _DRAWS_SCORE ClassVar.
- nrl: main defines _is_favorite_game TWICE in SportsCore, at 320 and 2177, and
  they do not agree -- the first matches on ESPN team id, the second on
  abbreviation. #189 moved nrl to ids deliberately; #332 added the abbr copy,
  which shadowed and silently reverted that fix. This branch removes the
  duplicate, so the fix is restored. That is a live bug on main today.
- Manifests and plugins.json take main, then the eight changed plugins are
  re-bumped on top of the versions main has since published. Football is not
  bumped, because nothing about it changed.

READMEs: football takes main; afl, baseball and basketball keep both sections,
since this branch documents selection and main documents the matchup separator.

Verified: run_plugin_tests.py --all gives 222 passed, 2 skipped, 1 failed, and
that one failure -- football's test_favorite_live_boost.py, "excluded team
hidden from recent/final scores in default (no-favorites) path" -- reproduces
identically on a clean origin/main worktree. It is main's, not this merge's:
_favorites_first(games, 0, N) does not apply the exclude filter the old
filter/sort/truncate path did. The eight apply excludes elsewhere and pass.
check_selection_settings, check_manifest_version_fields, check_scroll_adoption
and check_module_collisions all pass.

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