Explain an empty scoreboard instead of leaving the user guessing - #235
Conversation
Several plugins documented — or in one case offered in a picker — team
abbreviations that ESPN does not use, so copying them matched no team and
the plugin silently showed nothing.
odds-ticker's NHL picker was the only one where the user could not work
around it: it listed UTA (a retired code, labelled with the club's former
name "Utah Hockey Club" rather than "Utah Mammoth") and omitted the
Seattle Kraken entirely, so that team could not be selected at all. The
enum and labels are now generated from ESPN's team endpoint and match it
exactly at 32 teams.
The rest are description-only corrections to the favorite_teams examples:
basketball NBA GSW -> GS (Golden State Warriors)
basketball WNBA NYL -> NY (New York Liberty)
basketball WNBA LAS -> LA (Los Angeles Sparks)
basketball NCAAW UCONN -> CONN (UConn Huskies)
basketball NCAAW SCAR -> SC (South Carolina Gamecocks)
football NCAAFB BAMA -> ALA (Alabama Crimson Tide)
hockey NCAAWH WISC -> WIS (Wisconsin Badgers)
Each description now also says these are ESPN's codes and are not always
the ones you would guess, since that is the underlying trap.
Every code here was verified against
site.api.espn.com/apis/site/v2/sports/{sport}/{league}/teams?limit=1000.
The limit matters: without it the default page size truncates the NCAA
responses (362 of 755 teams) and makes valid codes look wrong.
Left alone deliberately: lacrosse-scoreboard's WISC/MINN/OSU and
BU/BC/MICH examples, and baseball-scoreboard's MiLB DUR/SWB/NOR, because
ESPN's lacrosse team endpoints return zero teams and the MiLB one 404s.
Unverifiable, so not guessed at.
No rendering code changed; the safety harness passes for all four plugins
at every size.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KEZK1P1Q1fu5pcuVrkrCFZ
Favorite teams are matched by exact ESPN abbreviation, so a code that is
not real matches no game and the plugin shows nothing — with no hint that
the code is the problem. Out of season, a perfectly correct code produces
the identical empty screen. The two were indistinguishable from the logs,
which is how a user ends up asking whether their config is broken when it
is only July.
Each of these plugins now says which case it is:
WARNING NFL favorite team 'GBP' is not a NFL team code. Closest match
is 'GB' (Green Bay Packers). Every code this league accepts is
listed at https://site.api.espn.com/.../nfl/teams?limit=1000.
INFO NFL favorite teams TB look correct, but the league has nothing
on until 06 August 2026. An empty display until then is
expected, not a configuration problem.
INFO NCAA Baseball favorite teams UGA look correct, but the season
has finished and the next one's fixtures are not published yet.
Suggestions rank word-initial matches first, because string similarity is
useless at three characters: 'MUN' scores identically against 'MAN' and
'SUN', so Manchester United and Sunderland tie and the answer is a coin
flip. Fragments are handled too ('BAMA' is inside 'Alabama' but
abbreviates nothing in it), and a code that only differs in case is told
so rather than guessed at.
Reading the schedule turned out to be the subtle part, and both traps are
real ESPN behaviour confirmed against live endpoints:
- An out-of-season league does not return an empty scoreboard. ESPN rolls
forward to the next day with fixtures, so in July the NHL endpoint
returns seven September games. Emptiness cannot be the signal.
- A *finished* season rolls nowhere and returns its last game instead,
months in the past — so dates must be filtered before the soonest one
means anything. Filtering on "later than now" then wrongly drops games
that started earlier today and reports a live slate as a dead season,
so the window is the last 24 hours.
Verified against every league these plugins cover: MLB, AFL, NRL and WNBA
correctly stay quiet; NFL, NCAA football, NHL, NBA and NCAA men's
basketball report their start dates; NCAA baseball and NCAA women's
hockey report finished seasons.
Safety, since this runs inside update():
- It runs on a daemon thread, so it never delays a frame.
- Once per league per process, re-armed only when the config changes.
- Every failure path is swallowed to a debug line. A plugin whose ESPN
endpoint returns no teams at all (college lacrosse) draws no conclusion
rather than calling a valid code wrong.
Each plugin ships its own copy of the module, since the loader gives
plugins no shared library to import from, under a plugin-unique name per
the module-collision rule. A test asserts the copies stay byte-identical
while they live in one checkout.
Tested: 30 unit tests; safety harness 24/24 PASS per plugin (168 renders,
zero failures); module-collision check clean. Validated end-to-end on real
hardware, where all four message paths appeared as intended with no errors.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KEZK1P1Q1fu5pcuVrkrCFZ
|
Warning Review limit reached
Next review available in: 10 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (26)
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. Comment |
Not up to standards ⛔🔴 Issues
|
| Category | Results |
|---|---|
| Security | 7 medium |
🟢 Metrics 719 complexity
Metric Results Complexity 719
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.
|
Merge order: land #229 and #234 first.
I merge-simulated all ten open PRs onto main. With #229 and #234 in first, the only conflict here is baseball's Resolution is simply to keep both entries, giving
|
Minor bumps (new user-facing feature) for the seven plugins #235 actually changes, each above main's post-#237 version: afl 1.2.0, baseball 1.21.0, basketball 1.9.0, football 2.10.0, hockey 1.6.0, lacrosse 1.6.0, nrl 1.2.0 odds-ticker is intentionally NOT bumped: its only change in #235 was the NHL picker correction (UTA->UTAH, +Seattle) that came from #234 and is already in main, so it has no net change here. The original bump list also targeted numbers main has since passed via #234/#236/#237/#239; corrected. plugins.json regenerated; every changed plugin is strictly above main. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KEZK1P1Q1fu5pcuVrkrCFZ
…s passed #235 landed while this PR was open and bumped both plugins past it -- baseball to 1.21.0 and football to 2.10.0 -- which stranded this branch's 1.20.4 / 2.9.4 below main. CI rejects a bump that is not above main's version, and users already on the higher version would never receive the change, so the fix is re-released on top rather than merged as-is: baseball-scoreboard 1.20.4 -> 1.21.1 football-scoreboard 2.9.4 -> 2.10.1 Conflicts and how each was resolved: - Both manifests: git collapsed the two competing head insertions into one entry, which silently drops the entry main shipped. Kept BOTH -- this branch's, renumbered and on top, then #235's 1.21.0 / 2.10.0 beneath it. - Both CHANGELOGs: same shape, same resolution. Neither release note is lost. - plugins.json: regenerated from main rather than merged textually (`git show origin/main:plugins.json > plugins.json && python3 update_registry.py`). The diff against main is exactly the two version bumps plus the regenerated timestamp. - Both manager.py files auto-merged: #235 added a favorite-check module and called it from a different region than the has_live_content() logging this branch rewrote. Verified on the merged tree: - the throttle changes are intact and the old unthrottled per-league logger.info lines are gone from both plugins - #235's favorite_check modules are present and still wired into both managers - safety harness 24/24 (baseball) and 16/16 (football), no golden drift - module-collision check clean across 42 plugins - manifest version, versions[0] and plugins.json latest_version agree - plugin test suites: same 4 baseball / 3 football failures as origin/main, each confirmed pre-existing against a worktree of the new main Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Udr6MfaFLUPhX5Fgo67Jf5
Why
Favorite teams are matched by exact ESPN abbreviation. A code that isn't real matches no game, so the plugin shows nothing — with no hint that the code is the problem. And out of season, a perfectly correct code produces the identical empty screen.
The two were indistinguishable from the logs. That's how a user ends up asking whether their config is broken when it's only July. This is the generalised version of the soccer fix in #233, applied to the other seven plugins that match teams by abbreviation.
What the user now sees
Getting the suggestion right
String similarity is useless at three characters —
MUNscores identically againstMANandSUN, so Manchester United and Sunderland tie and the suggestion is a coin flip. Instead, candidates that read as word-initial abbreviations rank first, then fragments, then similarity.GBPGB(Green Bay Packers)BAMAALA(Alabama Crimson Tide)SCARSC(South Carolina)UTAUTAH(Utah Mammoth)bosBOS— "codes are case-sensitive"ZZZZZZReading the schedule was the subtle part
Both of these are real ESPN behaviour, confirmed against live endpoints:
Filtering on "later than now" then introduces a third bug: it drops games that started earlier today and reports a live slate as a dead season. The window is therefore the last 24 hours, which is also timezone-proof.
Verified against every league these plugins cover:
Safety
This runs inside
update(), so it was built not to be able to hurt anything:AP_TOP_25) are excluded, so they're never reported as bad codes.Structure
Each plugin ships its own copy of the module — the loader gives plugins no shared library to import from — under a plugin-unique name per the module-collision rule in
CLAUDE.md. A test asserts the copies stay byte-identical while they live in one checkout, since silent drift is the obvious failure mode of copies.Testing
sys.modules, since the method importsrequestsin its own body).