Both bugs were pinned AS-IS by the B0 characterization suite so this
phase could change them knowingly. Both fixes are adoptions of code the
corresponding plugins already ship, not new inventions.
Hockey: the extractor read competitor["statistics"] unguarded, so a
competitor arriving without that array raised KeyError inside the
generator and the WHOLE event was discarded -- valid scores and status
included. Shot/save counts now default to 0, which is already what the
suite expects for an empty statistics array.
Baseball: for live games the extractor read game_event["status"], the
event TOP-LEVEL status, to get the inning. Real ESPN events duplicate
status there, but MiLB events (synthesized from the MLB Stats API into
an ESPN-like shape) populate only the competition-level one, so the
lookup raised a bare KeyError and dropped the event. It now reads the
competition-level status that _extract_game_details_common has already
validated, so it cannot be missing at that point.
The two characterization tests that pinned the old behaviour are
rewritten to assert the fix rather than deleted, so the suite still
documents the edge case -- and still totals 94.
CHANGELOG records these plus the live-clock change from aaabc61 under
Changed/Fixed, since all three are user-visible. The two new promotion
suites join the CI unit job (449 tests).
Verified: unit job 449 passed, plugin-safety job 60 passed, and the
hockey (16) and baseball (24) plugin harnesses render clean at every
panel size.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FgbA8SMutQQpXkMG8LMmC4
4.0 KiB
Changelog
Notable changes to the LEDMatrix core. The version below is the value of
src.__version__, which the plugin loader reports to compatibility checks and
which plugin manifests reference via ledmatrix_min_version.
Why this file exists: the plugin monorepo bundles fallback copies of several
core modules (see docs/plugin-development/08-shared-sports-code.md in
ledmatrix-plugins). A plugin
may delete its bundled copy only when its manifest floors on the first core
release that ships the module — which requires module additions to be recorded
here, against a version number. When you add a module plugins will import via
src.*, note it in the Unreleased section and bump src/__init__.py in the
release that ships it.
Unreleased
Added
-
src/element_style.py— per-element style resolver backing thex-style-elementsconfig-schema extension. Already consumed (behind guarded imports with classic fallbacks) by theof-the-day,ledmatrix-music, andfootball-scoreboardplugins. -
Core unit-test CI job enrolling the previously unenrolled suites (skin system, data sources, API extractors, scroll helper, adaptive layout, loader compatibility warning) plus new characterization tests for
src/base_classes/sports.pyahead of the shared sports-code unification. -
src/base_classes/sports/—sports.pyis now a package (core.py+modes.py). The import path is unchanged:from src.base_classes.sports import SportsCorestill works. -
Nine methods promoted onto the sports base classes from the plugins' bundled copies, plus the override points
_favorite_key,_config_schema_pathand_font_rootand the class attributesFINAL_PERIOD/CLOCK_COUNTS_DOWN. Seedocs/SPORTS_UNIFICATION.md. A plugin may start calling these once its manifest floorsledmatrix_min_versionat the release that ships them.
Changed
- Live games are no longer dropped when the feed omits a game clock.
SportsLive._is_game_really_overpreviously (in the baseball and UFC plugin lineages) coerced a missing or non-string clock to the literal"0:00"and then treated the game as finished onceperiod >= 4. Baseball has no game clock andperiodis the inning, so live MLB games disappeared from the scoreboard from the 5th inning onward; UFC was affected the same way. The clock check is now skipped when the clock is unusable, and the period threshold is the per-sportFINAL_PERIOD(hockey ends in P3). Sports whose clocks count up — soccer, AFL, NRL — setCLOCK_COUNTS_DOWN = Falseand never run the check at all, since0:00there means kickoff rather than expiry.
Fixed
FontManagerresolvesassets/fontsagainst the core install root instead of the process working directory, so font loading works when the process starts elsewhere (e.g. the plugin safety harness on CI).- Hockey events whose competitors carry no
statisticsarray are no longer discarded. The extractor readcompetitor["statistics"]unguarded, so aKeyErrorinside the generator dropped the entire event despite valid scores and status; shot counts now fall back to0. - Live baseball events that populate status only at the competition level are
no longer discarded. The extractor read the event top-level
game_event["status"]for the inning; real ESPN events duplicate it, but MiLB events synthesized from the MLB Stats API do not, so the lookup raised a bareKeyError. It now reads the already-validated competition-level status. SportsCore._resolve_project_pathresolved relative logo directories against<root>/srcinstead of the repo root aftersports.pybecame a package — the class bodies moved byte-identically but__file__gained a directory. Both it and_font_rootnow derive from one_INSTALL_ROOTconstant.
3.1.0
Baseline for this changelog. Highlights already shipped at this version: skin system for sports scoreboards (#419), Vegas continuous-scroll overhaul (#423), plugin update surfacing (#421).