Skip to content

fix(football): a favourites-only board wakes only for its own kickoffs (3.18.7) - #622

Merged
ChuckBuilds merged 2 commits into
mainfrom
perf/football-kickoff-clamp-shown-games
Oct 4, 2026
Merged

ChuckBuilds merged 2 commits into
mainfrom
perf/football-kickoff-clamp-shown-games

Conversation

@ChuckBuilds

@ChuckBuilds ChuckBuilds commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner

Summary

football-scoreboard 3.18.7. Only games the board would actually show now count as kickoffs that wake the live poll.

What was wrong. The live loop passed every game on the scoreboard to core's idle back-off (_note_scheduled_start_candidate) as a kickoff to wake for. After each kickoff, the poll stays at live_update_interval (30 s) for 15 minutes. A college Saturday has a kickoff about every half hour from late morning to midnight. So a favourites-only board (show_favorite_teams_only, the schema default) fetched the whole 54-game scoreboard (865 KB decoded, 63 KB gzipped) about every 30 s all day, for games it then filtered out.

It was also late for the favourite. A stored kickoff is kept for its 15-minute grace period, and a later kickoff can't replace it until that ends. In the replay below, the 12:30 games blocked UGA's 12:45 kickoff, so the game was first shown at 12:59.

Fix. A game is offered only if _classify_live_game would include it once live. That also honours exclude_teams. Boards that show every live game (show_all_live, or show_favorite_teams_only off) offer every game, exactly as before.

Where the 643 MB on ledpi came from

  • The counter is decoded size. fetch-stats bytes is len(response.content). ESPN sends the scoreboard gzipped: 865,068 bytes decoded, 63,275 on the wire (13.7x).
  • The cadence was what ledpi's config asks for. ledpi's ncaa_fb has show_favorite_teams_only: false, so every live FBS game is shown. Its journal for 2026-10-03 shows 107–121 polls an hour from 11:00 to 03:00 ET, with 1–18 games live the whole time. 120 polls × 865 KB ≈ 104 MB/h decoded, which matches 643 MB in 6 h. On the wire that is about 7.6 MB/h, or ~45 MB per 6 h.
  • ESPN can't send less. Checked live on 2026-10-04:
    • groups=80 returns the same 54 events.
    • status=in, state=in, live=1, enable=/disable= are ignored (same bytes).
    • limit above 500 truncates to 25 events.
    • The scoreboard/header endpoint lists only 16 events.
    • A per-game summary is much larger than the whole scoreboard.
  • What this PR changes. This change only helps favourites-only boards. ledpi's configuration is unchanged by it (proved below). Core feat(fetch): count bytes on the wire as well as decoded LEDMatrix#760 adds a wire_bytes counter so fetch-stats reports what actually crosses the network.

Test plan

  • Replay of the real 2026-10-03 Saturday, 09:00–03:00 ET (18 h). All 54 recorded ESPN events were rewound to scheduled / in progress (3.5 h) / final at each moment and served gzipped through a fake ESPN at the requests adapter layer. Plugin and core ran unmodified under frozen time, with update() every 5 s and ESPN's 400 for date ranges. Old = main, new = this branch.
config arm requests decoded on wire live games shown
favourites-only (UGA, AUB; TB) main 1,285 765.4 MB 52.49 MB UGA from 12:59
favourites-only (UGA, AUB; TB) this PR 995 558.2 MB 38.26 MB UGA from 12:45:25
ledpi's config (all live shown) main 2,532 1,471.3 MB 101.22 MB —
ledpi's config (all live shown) this PR 2,532 1,471.3 MB 101.22 MB identical every tick
  • Favourites-only polls per hour, ET:
    • main: 09–12h 9/10/37/62, 120 during the games, then 62/33/37/37/39.
    • This branch: 9/6/6/39, 120 during the games, then 9/6/6/5/4.
  • Displayed games, favourites-only: the same games are shown. Apart from the 14-minute late start that main had, the only differences are three 20 s phase offsets at kickoff/final between two 30 s pollers.
  • Live A/B against real ESPN, ledpi's config, alternated (main, branch, branch, main; 12 min each; 2026-10-04 17:25–18:15 ET, four NFL games live). Each arm made 44 requests and showed the same four live games. Steady-state scoreboard polling was 127 req/h in every arm, at 24.3–26.2 MB/h decoded and 2.35–2.46 MB/h on the wire. A Saturday window wasn't available (the next one is 2026-10-10), which is why the replay above uses recorded data.
  • test_kickoff_wakes_the_idle_poll.py has four new checks: favourites-only offers only favourites, show_all_live offers all, all-live boards offer all, excluded teams are never offered. Two of them fail against main's sports.py.
  • run_plugin_tests.py football-scoreboard: 65 pass. The one failure is test_football_plugin.py, an interactive prompt that also fails on main.
  • check_version_bump.py --base origin/main football-scoreboard, check_manifest_version_fields, check_sports_drift, check_sports_helpers_parity, check_module_collisions, check_min_core_version, test_check_min_core_version, test_espn_dates_copies, test_stage3_mixin_copies, update_registry.py --check: all pass, run against core main.

Notes for reviewer

  • Other scoreboards. The other eight scoreboards also offer every event. Their _classify_live_game signatures differ (bool vs tuple, ids vs abbreviations), so this PR leaves them alone.
  • Core root cause. Core's _note_scheduled_start_candidate keeps one stored kickoff through its grace period, which is what hid the favourite's kickoff. With this change, a favourites-only board only hits that when two favourites kick off within 15 minutes of each other.
  • Overlap. This doesn't touch the _fetch_todays_games / cache-key lines that claude/espn-canonical-scoreboard-keys changes. Whichever merges second will conflict only in manifest.json, CHANGELOG.md and plugins.json.

🤖 Generated with Claude Code

ChuckBuilds and others added 2 commits October 4, 2026 17:18
…s (3.18.7)

The live loop offered every game on the scoreboard to the idle back-off as
a kickoff to wake for. Each kickoff holds the poll at live cadence for 15
minutes, so on a college Saturday a favourites-only board fetched the whole
54-game scoreboard about every 30 s all day for games it then filtered out,
and a kickoff already being waited on kept a favourite's later kickoff from
being stored until its grace ran out (UGA 12:45 noticed at 12:59 in a replay
of 2026-10-03). Only games the live filter would show are offered now.

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

coderabbitai Bot commented Oct 4, 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: 0abd5b91-58c6-4d60-b450-739b9ed1343f
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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 5 complexity

Metric Results
Complexity 5

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.

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