Repository navigation
Sports: date on recent games, and stop drawing 88 config controls that cannot affect anything - #527
Merged
ChuckBuilds merged 3 commits intoSep 24, 2026
Conversation
…hing (1.48.0)
Adds the date of a finished game to both Recent displays, and stops drawing
five settings that are inert in every baseball league.
THE DATE. The full-screen (switch) Recent scoreboard has drawn one along its
bottom edge since it was written, but it drew game_date raw -- the "9/23" the
extractor emits -- so it was the one date on the board that ignored every
date-format setting: a panel set to "abbrev" read "Sep 23" on its upcoming
screen and "9/23" here. It now goes through switch_date_format like the
upcoming screen, which changes nothing on an untouched panel because that key
defaults to "numeric" and numeric returns the raw text. New
scroll_card.switch_recent_show_date (default true) is the off switch that did
not exist.
The scroll and Vegas Recent card drew no date at all. Five of the eight sibling
scoreboards already draw one there, so this closes a drift gap -- but their
placement does not transfer: they centre the recent score and leave the bottom
edge free, while this card puts the score at display_height-14, so the free
strip is above it. scroll_card.recent_show_date (default false) adds the date,
formatted by the shared date_format; scroll_card.recent_date_position picks
own_row, top_line, or auto, which measures the fonts and panel in use rather
than assuming a size. An explicit own_row with no room draws nothing rather
than overprinting the score.
Verified at all eight harness sizes in all three positions. check_plugin's own
mlb_recent render is empty (27 lit pixels -- no finished game in its mock
slate), so that PASS proves nothing about this card; it was rendered directly
instead, bounds-checked with records and odds on. Both paths also confirmed on
a 512x64 panel.
INERT SETTINGS, now "x-display": "hidden" -- still declared, so a config
already carrying one keeps validating and nothing is lost on upgrade:
* other_games_divisions (all three leagues) -- ESPN publishes FBS/FCS group
rosters for college-football alone, so the lookup resolves nothing and the
filter fails open.
* other_games_min_quality and show_ranking (all three) -- no baseball league
publishes a poll. NCAA Baseball included: measured 2026-09-24,
baseball/college-baseball/rankings answers 404 while /scoreboard and
/standings on the same slug answer 200. Out of season is not the
explanation -- men's college lacrosse and hockey are equally out of season
and both answer 200 with real poll blocks. show_ranking was worse than
inert, because the rank badge replaces the record, so ticking it erased
the records show_records was drawing.
* scroll_delay -- its own description has read "ignored" for releases.
* customization.layout.ranking -- no reader; layout.record positions the
badge.
THE FETCH. _league_has_rankings gated the quality-filter call site but not the
two show_ranking ones. The gate moved to the top of _fetch_team_rankings,
covering every caller at once, and is narrowed by one measured exception
(_NO_POLL_COLLEGE_LEAGUES) so NCAA Baseball's old "ranked" default stops
requesting too. Its default is now "any" -- what every board already showed,
since "ranked" with no poll lets everything through.
MILB LEVELS. milb.sport_ids (Triple-A / Double-A / High-A / Single-A) is now
declared and forwarded. BaseMiLBManager has read it since it was written, but
_adapt_config_for_manager is a whitelist that never carried the key, so no
value a user could write ever arrived -- which is also why the schema had
never declared it. Empty or unusable input falls back to all four levels.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ET8e5weDrb5Ju5QTKLU7zh
The same audit that produced baseball 1.48.0, applied to the other eight
lineages. The sports scoreboards are copies of each other, and a schema is
easier to copy than to re-derive, so three settings were carried into plugins
whose leagues cannot use them.
HIDDEN -- "x-display": "hidden", so each stays declared and a config already
carrying it keeps validating; only the form control goes away:
soccer 32, basketball 13, hockey 8, afl 6, nrl 6, football 5, lacrosse 4,
ufc 1.
* other_games_divisions (25) -- the FBS/FCS/Other checkboxes. ESPN publishes
those group rosters for college football alone (_DIVISION_GROUPS_BY_LEAGUE,
identical in all nine copies), so everywhere else the lookup resolves
nothing and the filter fails open. Soccer offered them on the Champions
League and the World Cup.
* other_games_min_quality (19) -- "ranked" needs a poll; without one the
check fails open and the setting has one meaningful value.
* show_ranking (16) -- worse than inert. The rank badge REPLACES the record,
so on a pollless league ticking it erased the records show_records was
drawing.
* scroll_delay (14) -- every copy's own description has read "Kept so saved
configs still load; ignored" for releases. ufc reads it into a local and
discards it, with a comment saying so.
* customization.layout.ranking (1, basketball) -- no reader.
WHICH LEAGUES HAVE A POLL IS MEASURED, not inferred from the
"college"/"ncaa" heuristic. ESPN's /rankings was probed for every scoreboard
league on 2026-09-24:
college-football 200 (125 teams) mlb, nba, wnba, nfl, nhl 404
mens/womens-college-basketball 200 (50 each) minor-league-baseball 400
mens/womens-college-hockey 200 (4 / 5) afl, rugby-league 3 404
mens/womens-college-lacrosse 200 (28 / 33) soccer eng.1 404
college-baseball 404 <-- the heuristic's blind spot
Left visible accordingly: football ncaa_fb, basketball ncaam/ncaaw, hockey and
lacrosse ncaa_mens/ncaa_womens. Asserted, not assumed -- see
scripts/test_inert_settings_are_hidden.py.
THE FETCH. _league_has_rankings gated the quality-filter call site but not the
show_ranking ones, so ticking Show Ranking on a pollless league sent two
requests an hour to endpoints that cannot answer. The gate moved to the top of
_fetch_team_rankings in all eight, covering every caller and unable to drift
apart again. lacrosse and ufc serve no pollless league, so the port changes
nothing there; it is carried because sports.py is copied, not shared, and a fix
living in eight of nine copies is how the last one gets missed.
NOT DONE, deliberately: on a pollless league an empty rank table makes
show_ranking ERASE the record rather than fall back to it, in every lineage
except basketball, whose _get_team_annotation already returns the record.
Hiding and gating covers anyone configuring fresh, but a config saved with
show_ranking: true still hits it. Porting basketball's fallback would also
change what a poll-backed college board draws for an unranked team (blank
today, the record after), so it is a display decision rather than cleanup.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ET8e5weDrb5Ju5QTKLU7zh
scripts/test_inert_settings_are_hidden.py encodes the measured league->poll map
and fails if any of the nine lineages draws other_games_divisions outside
college football, or other_games_min_quality / show_ranking on a league with no
poll, or scroll_delay, or customization.layout.ranking. It also checks the
other half of the promise -- that the poll-backed blocks are still offered --
that every hidden property explains itself, and that _fetch_team_rankings
consults _league_has_rankings in every copy.
Encoding the map here rather than in nine schemas means the next league ESPN
adds or drops is one edit, and a schema that quietly regains a dead control
fails CI instead of shipping.
Two fixes it flushed out:
* test_poll_choice.py pinned its probe to probe.league = <plugin id>, which
is not a league name any lineage ever sees. Harmless while nothing
consulted it; now that _fetch_team_rankings is gated, a probe claiming to
be in league "baseball-scoreboard" short-circuits and the badge table comes
back empty. It now uses a synthetic "ncaa-poll-probe" -- deliberately not a
real slug, since "college-baseball" would also fail against baseball's
measured exception.
* sports_drift_baseline.json records SportsCore._league_has_rankings as
intended divergence. baseball narrows the shared heuristic by one league;
ufc carries an inline copy of the original. The difference is deliberate
and documented at both sites.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ET8e5weDrb5Ju5QTKLU7zh
Contributor
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (56)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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 |
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 153 |
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
merged commit Sep 24, 2026
9e78866
into
fix/baseball-update-yields-within-budget
3 of 5 checks passed
ChuckBuilds
added a commit
that referenced
this pull request
Sep 25, 2026
…etch gated (9 plugins) (#523) * fix(baseball): return update() inside the slot the core grants it Found soaking on a 256x64 rig: every cold-cache start logged "Plugin baseball-scoreboard update() timed out" at ERROR. At startup the display controller hands each plugin whatever is left of a shared deadline (display_controller._update_plugins), so the slot shrinks as it works down the plugin list. Baseball's slot was 15.4s and 15.96s on two consecutive boots -- the varying value is what gave it away as a share of a deadline rather than a fixed timeout. This plugin waited 25s on its six parallel managers. A 25s wait inside a ~15s slot can only ever end one way: the core kills the call and logs an ERROR, and this method's own timeout branch -- the one that names *which* managers are slow -- never runs. The plugin's timeout was longer than the budget it was given, so it could never use it. The wait is now 10s, in a named constant documented against the core's budget, with a test asserting it stays under the smallest slot measured on hardware and is not re-inlined at the call site. Nothing was lost before and nothing is lost now, which is what makes yielding early safe: shutdown(cancel_futures=True) only cancels managers that have not started, and all six start immediately, so in-flight fetches run to completion and populate their caches either way. A plugin cut off at startup is also immediately due again, so the scheduled tick picks it up -- the core's own docstring says as much. The difference is that returning under our own steam turns a core-level ERROR into a plugin WARNING naming the slow managers. The expensive part of a cold start is the NCAA baseball season fetch -- 5,500 events, ~10s on the rig -- which the background service already runs off-thread; this does not change that. Verified on the rig: baseball 1.47.0 plus this change, no ERROR on a warm restart, and the card path confirmed working end-to-end on a live MLB game (headshot prefetch wrote four new 192x192 files, zero draw errors). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014RRtqXDCnvnY6EQwhT5CV9 * Sports: date on recent games, and stop drawing 88 config controls that cannot affect anything (#527) * feat(baseball): date on recent games; hide config that cannot do anything (1.48.0) Adds the date of a finished game to both Recent displays, and stops drawing five settings that are inert in every baseball league. THE DATE. The full-screen (switch) Recent scoreboard has drawn one along its bottom edge since it was written, but it drew game_date raw -- the "9/23" the extractor emits -- so it was the one date on the board that ignored every date-format setting: a panel set to "abbrev" read "Sep 23" on its upcoming screen and "9/23" here. It now goes through switch_date_format like the upcoming screen, which changes nothing on an untouched panel because that key defaults to "numeric" and numeric returns the raw text. New scroll_card.switch_recent_show_date (default true) is the off switch that did not exist. The scroll and Vegas Recent card drew no date at all. Five of the eight sibling scoreboards already draw one there, so this closes a drift gap -- but their placement does not transfer: they centre the recent score and leave the bottom edge free, while this card puts the score at display_height-14, so the free strip is above it. scroll_card.recent_show_date (default false) adds the date, formatted by the shared date_format; scroll_card.recent_date_position picks own_row, top_line, or auto, which measures the fonts and panel in use rather than assuming a size. An explicit own_row with no room draws nothing rather than overprinting the score. Verified at all eight harness sizes in all three positions. check_plugin's own mlb_recent render is empty (27 lit pixels -- no finished game in its mock slate), so that PASS proves nothing about this card; it was rendered directly instead, bounds-checked with records and odds on. Both paths also confirmed on a 512x64 panel. INERT SETTINGS, now "x-display": "hidden" -- still declared, so a config already carrying one keeps validating and nothing is lost on upgrade: * other_games_divisions (all three leagues) -- ESPN publishes FBS/FCS group rosters for college-football alone, so the lookup resolves nothing and the filter fails open. * other_games_min_quality and show_ranking (all three) -- no baseball league publishes a poll. NCAA Baseball included: measured 2026-09-24, baseball/college-baseball/rankings answers 404 while /scoreboard and /standings on the same slug answer 200. Out of season is not the explanation -- men's college lacrosse and hockey are equally out of season and both answer 200 with real poll blocks. show_ranking was worse than inert, because the rank badge replaces the record, so ticking it erased the records show_records was drawing. * scroll_delay -- its own description has read "ignored" for releases. * customization.layout.ranking -- no reader; layout.record positions the badge. THE FETCH. _league_has_rankings gated the quality-filter call site but not the two show_ranking ones. The gate moved to the top of _fetch_team_rankings, covering every caller at once, and is narrowed by one measured exception (_NO_POLL_COLLEGE_LEAGUES) so NCAA Baseball's old "ranked" default stops requesting too. Its default is now "any" -- what every board already showed, since "ranked" with no poll lets everything through. MILB LEVELS. milb.sport_ids (Triple-A / Double-A / High-A / Single-A) is now declared and forwarded. BaseMiLBManager has read it since it was written, but _adapt_config_for_manager is a whitelist that never carried the key, so no value a user could write ever arrived -- which is also why the schema had never declared it. Empty or unusable input falls back to all four levels. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ET8e5weDrb5Ju5QTKLU7zh * fix(sports): stop drawing 75 config controls that cannot affect anything The same audit that produced baseball 1.48.0, applied to the other eight lineages. The sports scoreboards are copies of each other, and a schema is easier to copy than to re-derive, so three settings were carried into plugins whose leagues cannot use them. HIDDEN -- "x-display": "hidden", so each stays declared and a config already carrying it keeps validating; only the form control goes away: soccer 32, basketball 13, hockey 8, afl 6, nrl 6, football 5, lacrosse 4, ufc 1. * other_games_divisions (25) -- the FBS/FCS/Other checkboxes. ESPN publishes those group rosters for college football alone (_DIVISION_GROUPS_BY_LEAGUE, identical in all nine copies), so everywhere else the lookup resolves nothing and the filter fails open. Soccer offered them on the Champions League and the World Cup. * other_games_min_quality (19) -- "ranked" needs a poll; without one the check fails open and the setting has one meaningful value. * show_ranking (16) -- worse than inert. The rank badge REPLACES the record, so on a pollless league ticking it erased the records show_records was drawing. * scroll_delay (14) -- every copy's own description has read "Kept so saved configs still load; ignored" for releases. ufc reads it into a local and discards it, with a comment saying so. * customization.layout.ranking (1, basketball) -- no reader. WHICH LEAGUES HAVE A POLL IS MEASURED, not inferred from the "college"/"ncaa" heuristic. ESPN's /rankings was probed for every scoreboard league on 2026-09-24: college-football 200 (125 teams) mlb, nba, wnba, nfl, nhl 404 mens/womens-college-basketball 200 (50 each) minor-league-baseball 400 mens/womens-college-hockey 200 (4 / 5) afl, rugby-league 3 404 mens/womens-college-lacrosse 200 (28 / 33) soccer eng.1 404 college-baseball 404 <-- the heuristic's blind spot Left visible accordingly: football ncaa_fb, basketball ncaam/ncaaw, hockey and lacrosse ncaa_mens/ncaa_womens. Asserted, not assumed -- see scripts/test_inert_settings_are_hidden.py. THE FETCH. _league_has_rankings gated the quality-filter call site but not the show_ranking ones, so ticking Show Ranking on a pollless league sent two requests an hour to endpoints that cannot answer. The gate moved to the top of _fetch_team_rankings in all eight, covering every caller and unable to drift apart again. lacrosse and ufc serve no pollless league, so the port changes nothing there; it is carried because sports.py is copied, not shared, and a fix living in eight of nine copies is how the last one gets missed. NOT DONE, deliberately: on a pollless league an empty rank table makes show_ranking ERASE the record rather than fall back to it, in every lineage except basketball, whose _get_team_annotation already returns the record. Hiding and gating covers anyone configuring fresh, but a config saved with show_ranking: true still hits it. Porting basketball's fallback would also change what a poll-backed college board draws for an unranked team (blank today, the record after), so it is a display decision rather than cleanup. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ET8e5weDrb5Ju5QTKLU7zh * test(sports): enforce that no scoreboard draws an inert control scripts/test_inert_settings_are_hidden.py encodes the measured league->poll map and fails if any of the nine lineages draws other_games_divisions outside college football, or other_games_min_quality / show_ranking on a league with no poll, or scroll_delay, or customization.layout.ranking. It also checks the other half of the promise -- that the poll-backed blocks are still offered -- that every hidden property explains itself, and that _fetch_team_rankings consults _league_has_rankings in every copy. Encoding the map here rather than in nine schemas means the next league ESPN adds or drops is one edit, and a schema that quietly regains a dead control fails CI instead of shipping. Two fixes it flushed out: * test_poll_choice.py pinned its probe to probe.league = <plugin id>, which is not a league name any lineage ever sees. Harmless while nothing consulted it; now that _fetch_team_rankings is gated, a probe claiming to be in league "baseball-scoreboard" short-circuits and the badge table comes back empty. It now uses a synthetic "ncaa-poll-probe" -- deliberately not a real slug, since "college-baseball" would also fail against baseball's measured exception. * sports_drift_baseline.json records SportsCore._league_has_rankings as intended divergence. baseball narrows the shared heuristic by one league; ufc carries an inline copy of the original. The difference is deliberate and documented at both sites. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ET8e5weDrb5Ju5QTKLU7zh --------- Co-authored-by: Claude <noreply@anthropic.com> * Keep the scoreboard manifests pure ASCII Five manifests picked up raw UTF-8 (em dashes, the ▲/▼ indicator) in older release notes when this branch re-serialised them; main stores those characters as \u escapes. The core's load_manifest() opens the file in the platform encoding, which is cp1252 on Windows, so a raw UTF-8 byte aborts a harness run there. Escaped back; the parsed JSON is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * baseball test: stop shadowing the built-in TimeoutError (Codacy) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Started as "why does the MLB config show FBS and FCS settings that only apply to NCAA College sports?" — and the answer turned out to apply to every scoreboard.
The date on recent games (baseball)
The full-screen Recent scoreboard already drew one — but raw, as
game_date, so it was the only date on the board that ignored every date-format setting. A panel set toabbrevread "Sep 23" on its upcoming screen and "9/23" here. On a 512×64 panel:It now goes through
switch_date_format, which changes nothing on an untouched panel (that key defaults tonumeric, and numeric returns the raw text).scroll_card.switch_recent_show_dateis the off switch that never existed.The scroll/Vegas card drew no date at all. Five of the eight siblings already do, so this closes a drift gap — but their placement doesn't transfer: they centre the recent score and use the free bottom edge, while this card puts the score at
display_height - 14, so the free strip is above it.recent_date_positionisown_row/top_line/auto; auto measures the fonts and panel in use rather than assuming a size, and an explicitown_rowwith no room draws nothing rather than overprinting the score.88 config controls that cannot affect anything
other_games_divisionsis the FBS/FCS taxonomy: ESPN publishes those rosters for college football alone, so everywhere else the lookup resolves nothing and the filter fails open. Soccer offered the checkboxes on the Champions League and the World Cup.show_rankingwas worse than inert — the rank badge replaces the record, so on a pollless league ticking it erased the recordsshow_recordswas drawing:Each setting is now
"x-display": "hidden"— still declared, so a config already carrying it keeps validating and nothing is lost on upgrade. Verified: all nine schemas are valid Draft-07 and every hidden key still validates inside a defaults-derived config.Which leagues have a poll is measured, not inferred
The code's heuristic is
"college" in league or "ncaa" in league. I probed ESPN's/rankingsfor every scoreboard league on 2026-09-24 and it has a blind spot:college-baseball's slug is right —
/scoreboardand/standingsanswer 200 on it — and out of season isn't the explanation, since college lacrosse and hockey are equally out of season and answer 200 with real poll blocks. So baseball narrows the heuristic with_NO_POLL_COLLEGE_LEAGUES, and NCAA Baseball'srankeddefault (which made every enabled rig fetch hourly for a poll that can't arrive, while failing open and filtering nothing) becomesany.Left visible where a poll genuinely exists: football
ncaa_fb, basketballncaam/ncaaw, hockey and lacrossencaa_mens/ncaa_womens. Asserted, not assumed.Also: UFC has a real poll (24 blocks, 133 entries) the heuristic gates out — but its ranks are keyed on
athlete, notteam, so_fetch_team_rankingswould return{}anyway. Correctly not offered; supporting it needs a new extractor, not a gate change.The fetch, and one new setting
_league_has_rankingsgated the quality-filter call site but not theshow_rankingones, so ticking Show Ranking on a pollless league sent two requests an hour to endpoints that cannot answer. The gate moved to the top of_fetch_team_rankingsin all nine, covering every caller.milb.sport_ids(Triple-A / Double-A / High-A / Single-A) is now declared and forwarded.BaseMiLBManagerhas read it since it was written, but_adapt_config_for_manageris a whitelist that never carried the key — which is also why the schema had never declared it.Verification
Two things worth knowing about that evidence:
check_plugin'smlb_recentrender is empty (27 lit pixels — no finished game in its mock slate), so that PASS proves nothing about the recent card. I rendered the card directly at all eight harness sizes instead, bounds-checked with records and odds on, and confirmed both paths on a real 512×64 panel.test_espn_date_ranges.py::test_the_lookback_window_recovers_from_a_rejected_rangepasses in isolation and reproduces identically (62/1/1) with this branch's football edits reverted. Not caused here.scripts/test_inert_settings_are_hidden.pynow carries the league→poll map and fails CI if any lineage regains a dead control — one edit when ESPN changes, instead of nine schemas.Deliberately not done
show_rankingerases the record rather than falling back, in every lineage except basketball (whose_get_team_annotationalready returns the record). Hiding and gating covers fresh configs; one saved withshow_ranking: truestill hits it. Porting basketball's fallback would also change what a poll-backed college board draws for an unranked team — blank today, the record after — so it's a display decision, not cleanup. Documented in the new test file.🤖 Generated with Claude Code
https://claude.ai/code/session_01ET8e5weDrb5Ju5QTKLU7zh
Summary by CodeRabbit