Files
LEDMatrix/CHANGELOG.md
T
Claude 2486bdb249 fix(sports): stop dropping hockey and baseball events on optional feed keys
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
2026-08-01 16:25:32 +00:00

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 the x-style-elements config-schema extension. Already consumed (behind guarded imports with classic fallbacks) by the of-the-day, ledmatrix-music, and football-scoreboard plugins.

  • 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.py ahead of the shared sports-code unification.

  • src/base_classes/sports/sports.py is now a package (core.py + modes.py). The import path is unchanged: from src.base_classes.sports import SportsCore still works.

  • Nine methods promoted onto the sports base classes from the plugins' bundled copies, plus the override points _favorite_key, _config_schema_path and _font_root and the class attributes FINAL_PERIOD / CLOCK_COUNTS_DOWN. See docs/SPORTS_UNIFICATION.md. A plugin may start calling these once its manifest floors ledmatrix_min_version at the release that ships them.

Changed

  • Live games are no longer dropped when the feed omits a game clock. SportsLive._is_game_really_over previously (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 once period >= 4. Baseball has no game clock and period is 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-sport FINAL_PERIOD (hockey ends in P3). Sports whose clocks count up — soccer, AFL, NRL — set CLOCK_COUNTS_DOWN = False and never run the check at all, since 0:00 there means kickoff rather than expiry.

Fixed

  • FontManager resolves assets/fonts against 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 statistics array are no longer discarded. The extractor read competitor["statistics"] unguarded, so a KeyError inside the generator dropped the entire event despite valid scores and status; shot counts now fall back to 0.
  • 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 bare KeyError. It now reads the already-validated competition-level status.
  • SportsCore._resolve_project_path resolved relative logo directories against <root>/src instead of the repo root after sports.py became a package — the class bodies moved byte-identically but __file__ gained a directory. Both it and _font_root now derive from one _INSTALL_ROOT constant.

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).