From 94aebd54450f19724992e61ccbb89d6e020a1e8b Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 2 Aug 2026 17:51:17 -0400 Subject: [PATCH] docs(sports): the sunset rule needs enforcement, not just a declared floor Conditions 1 and 2 were written as if declaring `ledmatrix_min_version` protected users running an older core. Reading the core, it does not: - The loader's compatibility check is advisory -- it logs and continues. - It does not even warn for the users most at risk: it skips entirely when the core's parsed version is below 2.0.0, and the v3.1.0 release ships __version__ = "1.0.0" (tagged 2026-05-31, string bumped 2026-07-12). - Neither StoreManager.install_plugin nor .update_plugin compares the core version at all, so a routine store update delivers a plugin that floors above the user's core. Delete a bundled copy under those conditions and the plugin raises ModuleNotFoundError at load; the core marks it ERROR, logs one line, and carries on -- the user silently loses that scoreboard. Adds condition 3 (the core must enforce the floor at install/update time, and have done so long enough that few users predate it), records the exact exc.name a missing module raises so guard sets are written correctly, and points at phase B6 in the core repo. Notes that the two documents must change together. No plugin code changes; no version bumps. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Udr6MfaFLUPhX5Fgo67Jf5 --- .../08-shared-sports-code.md | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/docs/plugin-development/08-shared-sports-code.md b/docs/plugin-development/08-shared-sports-code.md index 3886ddfc..cb28cb52 100644 --- a/docs/plugin-development/08-shared-sports-code.md +++ b/docs/plugin-development/08-shared-sports-code.md @@ -103,18 +103,42 @@ Assignment still works and overrides the resolved value, which is what ## The sunset rule -A plugin may **delete** its local copy of a converged module only when both are -true: +A plugin may **delete** its local copy of a converged module only when all three +are true: 1. The plugin's manifest declares `ledmatrix_min_version` **at or above the first core release that ships the module** (check the core CHANGELOG; the core exposes its version as `src.__version__`). 2. The safety harness passes with the local copy removed. - -Until then, keep the guarded try-core/except-local import: the loader's -compatibility check is **advisory only** (it logs a warning and never blocks), -so the `except ImportError` fallback is the real protection for users running -an older core. +3. The core **enforces** that floor at install/update time, and has done so long + enough that few users run a core without the enforcement. + +Condition 3 is new, and it is the one that matters. Conditions 1 and 2 were +written as if declaring a floor protected anyone; it does not: + +- The loader's compatibility check is **advisory only** — it logs a warning and + never blocks. +- It doesn't even warn for the users most at risk. It skips entirely when the + core's parsed version is below `2.0.0`, and the `v3.1.0` release ships + `__version__ = "1.0.0"` (tagged 2026-05-31; the string was not bumped to + `"3.1.0"` until 2026-07-12, six weeks later). +- Neither `StoreManager.install_plugin` nor `.update_plugin` compares the core + version at all. `update_plugin` compares the plugin's manifest version against + the registry's `latest_version` and nothing else — so a store update happily + delivers a plugin that floors above the user's core. + +Delete the copy anyway and the plugin raises `ModuleNotFoundError` at load; the +core catches it, marks the plugin `ERROR`, logs one line, and carries on. The +user just loses that scoreboard with no explanation. + +**Until condition 3 holds, keep the guarded try-core/except-local import** — the +fallback is the only real protection. Note that the guard must name the exact +dotted path: a missing `src/common/sports_scroll.py` raises with +`exc.name == 'src.common.sports_scroll'`, which `{"src"}` does not match. + +The core-side plan for condition 3 is phase **B6** in the core repo's +`docs/SPORTS_UNIFICATION.md`. Keep these two documents in agreement — if you +change the sunset rule here, change it there in the same PR. ### Worked example: the scroll display