Skip to content

fix(hockey): derive the ESPN season window instead of pinning it to 2025-26 - #324

Merged
ChuckBuilds merged 2 commits into
mainfrom
fix/hockey-season-rollover
Aug 23, 2026
Merged

fix(hockey): derive the ESPN season window instead of pinning it to 2025-26#324
ChuckBuilds merged 2 commits into
mainfrom
fix/hockey-season-rollover

Conversation

@ChuckBuilds

Copy link
Copy Markdown
Owner

Season-readiness pass over football-scoreboard and hockey-scoreboard ahead of the openers (NFL ~Sept 10, NHL ~Oct 7). Most of what I checked is already correct — details at the bottom — but two things were worth changing.

The pinned season window

hockey-scoreboard/data_fetcher.py::_get_season_date_range computed now and then ignored it:

now = datetime.now()                    # never used
season_start = datetime(2025, 10, 1)
season_end   = datetime(2026, 6, 30)

That string goes straight into the request as ?dates={range}, so once the 2026-27 season opened it would have kept asking ESPN for last season. It now derives the year with the same August rollover rule nhl_managers.py already uses, so the two agree on which season is current instead of drifting apart:

date before after
2026-07-31 20251001-20260630 20251001-20260630
2026-08-22 20251001-20260630 20261001-20270630
2026-10-07 (opener) 20251001-20260630 20261001-20270630
2027-08-01 20251001-20260630 20271001-20280630

Reachability, stated plainly: data_fetcher.py is imported only by debug_tb_games.py, so this is not on the runtime path today — the live fetchers already derive their windows correctly. I still think it's worth fixing: the committed debug script would pull the wrong season, and anyone wiring the module back in inherits a bug that surfaces once a year.

Writing the test also turned up a function-local from datetime import datetime shadowing the module import. Patching the module attribute had no effect, which is precisely why this couldn't be tested before.

The missing football guard

hockey-scoreboard has test_empty_mode_signals_no_content.py, added after the bug where an empty mode reported success and sat on a blank panel for its full duration. football-scoreboard had no equivalent — and the two ship separate forks of sports.py, so a fix in one lineage never reaches the other.

That failure mode is exactly the state both plugins are in right now: pre-season, with recent and live empty while upcoming fills in. Confirmed the new test catches it — making SportsRecent.display return None fails 3 checks.

Football's fork also overrides display() on SportsLive, which hockey's doesn't. Its only non-delegating paths are return False (disabled) and return True (celebration); the empty case falls through to super().display(). So SportsLive gets a targeted disabled-path check rather than being forced through the stand-in, which can't satisfy super().

What I checked that was already fine

  • Season rollover on the live path — both nfl_managers.py and nhl_managers.py derive dynamically and both flipped on 2026-08-01. NFL now requests 20260801-20270301 (covers a ~Feb 2027 Super Bowl); NHL 20260901-20270801 (covers a June 2027 Cup).
  • Schemas — both valid Draft-07; a default config generated from each validates cleanly.
  • Widgets — both use only checkbox-group and color-picker, both registered in the web UI.
  • Team pickers — NFL 32 (LV/LAC/LAR/WSH, no OAK/SD/STL/WAS); NHL 32 (UTAH present, relocated ARI gone).
  • Config wiring — every schema option is read. This took three passes to establish: keys reached via f-strings (f"{mode_type}_mode_duration", f"{result}_color"), via helpers taking the key as a parameter (_scroll_card_option), and via hockey's nested→flat resolve_value(["teams","favorite_teams"], ["favorite_teams"]) all look unwired to a naive scan. I chased each one to the call site rather than trusting the counts.
  • Display contract — no bare returns or implicit-None fall-throughs in either plugin's display() or its delegates.

One thing left, for you

hockey.defaults.season_cache_duration_seconds (also in lacrosse-scoreboard) is declared with x-advanced, a default of 86400 and min/max bounds — and is read nowhere in either repo. It's a knob users can set that does nothing. Removing it is a user-facing schema change, so I've left it; say the word and I'll drop it from both.

football-scoreboard's version (2.19.1) and versions[0] (2.18.1) are drifted, one of the eight I flagged on #314. Not touched here since nothing shipped changed in that plugin.

Verification

football 16 passed, hockey 12 passed (up from 15 and 11). The season test fails 9 checks against the previous code.

Not verified on hardware — both rigs have been unreachable all day.

🤖 Generated with Claude Code

https://claude.ai/code/session_01STMbQE4YctTacQXfbYqKuW

@coderabbitai

coderabbitai Bot commented Aug 22, 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: 7236086e-f4f2-44df-bd5f-bdd58ca05064


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 22, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 25 complexity

Metric Results
Complexity 25

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 force-pushed the fix/hockey-season-rollover branch from 98e0f3c to 8dc588f Compare August 23, 2026 15:48
ChuckBuilds pushed a commit that referenced this pull request Aug 23, 2026
Continuing the season-readiness sweep from #324 across the other sports
plugins.

The WNBA window was:

    # WNBA season typically runs from May to September
    datestring = f"{season_year}0501-{season_year}0930"

The regular season does end in September. The playoffs and Finals do not --
2024's Finals ended on 20 October, 2025's in mid-October. Both fetch calls
pass this string as `dates=` and there is no date-less fallback, so no
postseason game was ever fetched: the scoreboard went blank exactly when the
games matter most. The window now closes on 1 November.

Timing: the 2026 regular season ends in early September and the postseason
runs from mid-September into October, so this would have started dropping
games within weeks.

The other three leagues in this plugin were checked and are correct, so they
are covered by the test rather than changed:

  NBA       1 October start, flips on 1 October, reaches the June Finals
  NCAA M/W  no date window at all -- ESPN's `season` parameter, keyed to the
            year the season ENDS, flipping on 1 November ahead of the
            early-November openers

Swept every other sports plugin for the same shape. Only hockey-scoreboard's
data_fetcher.py had pinned dates, fixed separately in #324; MLB, MiLB, NFL,
NCAA FB and NCAA hockey all derive their windows correctly and cover their
postseasons.

Tests: 6 of the new checks fail against the previous window. Suite 12 passed.

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

Copy link
Copy Markdown
Owner Author

Force-pushed to correct the branch scope — worth flagging since the history changed.

This branch had picked up four commits that don't belong to it (#322's soccer registry fix and #323's youtube-stats fix). My mistake: an earlier merge-order test ran git checkout -B /tmp/mergetest origin/main 2>/dev/null, and a branch name starting with / is invalid. The 2>/dev/null swallowed that error, so the test merges landed on my local main instead, and every branch cut afterwards inherited them.

Nothing was wrong with the code — all four PRs were green — but merging this one would have silently merged #322 and #323 with it.

The branch is now a single commit on top of origin/main, touching only its own files. No review comments existed on it, so nothing was lost. Tests re-run on the rebuilt branch and still pass.

claude added 2 commits August 23, 2026 12:03
…025-26

Season-readiness check ahead of the NFL and NHL openers.

_get_season_date_range computed `now` and then ignored it, building its range
from literal datetimes:

    now = datetime.now()          # never used
    season_start = datetime(2025, 10, 1)
    season_end   = datetime(2026, 6, 30)

The result goes straight into the request as `?dates={range}`, so once the
2026-27 season opened this would have kept asking ESPN for last season's
window. It now derives the year with the same August rollover rule
nhl_managers.py uses, so the two agree on which season is current rather than
drifting apart.

Reachability, stated plainly: data_fetcher.py is imported only by
debug_tb_games.py, so this is not on the runtime path today -- the live
fetchers (nhl_managers.py and the two NCAA managers) already derive their
windows correctly. It is still worth fixing: the committed debug script would
have pulled the wrong season, and anyone wiring this module back in inherits a
bug that only shows up once a year.

Also removes a function-local `from datetime import datetime`. The module
already imports it, and the local one shadowed it -- patching the module
attribute had no effect, which is why the derivation could not be tested.

Adds test_season_date_range.py: the window follows the calendar across the
July/August boundary and rolls again the next year, NCAA ends in March rather
than June, an unknown league still gets a current window, and no literal
season year survives in the range builder. 9 of its checks fail against the
previous code.

Also adds test_empty_mode_signals_no_content.py to football-scoreboard, which
had no equivalent of hockey's guard. The two ship separate forks of sports.py,
so a fix in one lineage does not reach the other, and the failure it guards --
an empty mode reporting success and sitting on a blank panel for its whole
duration -- is exactly the state both plugins are in right now, before their
openers. Confirmed it catches the regression: making SportsRecent.display
return None fails 3 checks.

Football needs no version bump; CI excludes root-level test_*.py from the
gate, and nothing shipped changed there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01STMbQE4YctTacQXfbYqKuW
#316 merged and set hockey-scoreboard to 1.13.4 without adding a changelog
entry, so rebasing this branch left both claiming the same version and the
version-bump gate failed. Moves this change to 1.13.5 and realigns the
changelog with it.

Note 1.13.4 still has no entry of its own; that is #316's to fill, not mine
to invent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01STMbQE4YctTacQXfbYqKuW
@ChuckBuilds
ChuckBuilds force-pushed the fix/hockey-season-rollover branch from 8dc588f to 04e9d84 Compare August 23, 2026 16:06
@ChuckBuilds
ChuckBuilds merged commit b5253c5 into main Aug 23, 2026
4 checks passed
@ChuckBuilds
ChuckBuilds deleted the fix/hockey-season-rollover branch August 23, 2026 16:21
ChuckBuilds added a commit that referenced this pull request Aug 23, 2026
Continuing the season-readiness sweep from #324 across the other sports
plugins.

The WNBA window was:

    # WNBA season typically runs from May to September
    datestring = f"{season_year}0501-{season_year}0930"

The regular season does end in September. The playoffs and Finals do not --
2024's Finals ended on 20 October, 2025's in mid-October. Both fetch calls
pass this string as `dates=` and there is no date-less fallback, so no
postseason game was ever fetched: the scoreboard went blank exactly when the
games matter most. The window now closes on 1 November.

Timing: the 2026 regular season ends in early September and the postseason
runs from mid-September into October, so this would have started dropping
games within weeks.

The other three leagues in this plugin were checked and are correct, so they
are covered by the test rather than changed:

  NBA       1 October start, flips on 1 October, reaches the June Finals
  NCAA M/W  no date window at all -- ESPN's `season` parameter, keyed to the
            year the season ENDS, flipping on 1 November ahead of the
            early-November openers

Swept every other sports plugin for the same shape. Only hockey-scoreboard's
data_fetcher.py had pinned dates, fixed separately in #324; MLB, MiLB, NFL,
NCAA FB and NCAA hockey all derive their windows correctly and cover their
postseasons.

Tests: 6 of the new checks fail against the previous window. Suite 12 passed.


Claude-Session: https://claude.ai/code/session_01STMbQE4YctTacQXfbYqKuW

Co-authored-by: Claude <noreply@anthropic.com>
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