PR #544's change, ported onto the api_v3 package split (#553). Identical
behaviour; only the placement of the new code differs.
The original added 508 lines to web_interface/blueprints/api_v3.py, which #553
deletes, so every hunk of it would conflict irreconcilably. Ported by AST:
26 new top-level items sorted to where the split puts each kind --
__init__.py 2 imports, 11 constants, 7 helpers
starlark.py 4 routes (/starlark/editor/{apps,status,start,stop})
misc.py 2 routes (/integrations/mqtt-bridge{,/config})
Everything outside api_v3.py -- the Tools partial, the installer scripts, the
JS tests -- applied unchanged.
Routes: 111 from the split plus these 6 = 117, and the url-map snapshot is
regenerated to match, which is exactly what test_api_v3_url_map.py is designed
to make you do when routes are added.
Full Python suite: 4,278 passed, 68 skipped, 0 failed. The JS tests this PR
ships could not be run here -- node is not installed on this machine -- so
test/js/dom/test_tools_sections.js is unverified.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014RRtqXDCnvnY6EQwhT5CV9
web_interface/blueprints/api_v3.py held 111 routes, 56 helpers and 181
functions in one module -- 9% of the core by line count and three times the
next largest file. It becomes a package of nine route modules grouped by path
segment, plus __init__.py for the shared imports, constants, Blueprint and
helpers.
Every route module decorates the SAME api_v3 Blueprint object, so endpoint
names stay api_v3.<function>, the URL map is unchanged and app.py is untouched.
Verified: 111 routes before, 111 after, byte-identical rules, endpoints and
methods, and every endpoint still on the one blueprint.
plugins 3,867 config 1,178 starlark 692 system 619
fonts 452 misc 398 wifi 361 display 326 backup 212
__init__ 1,787 (imports, constants, Blueprint, 56 helpers)
Two things the URL-map check could not catch, both found by running the suite:
1. PROJECT_ROOT = Path(__file__).parent.parent.parent. Moving the code one
directory deeper made that resolve to web_interface/ instead of the project
root. Nothing failed at import; it surfaced as ~110 tests failing with 404s
and "installation script not found", because every path built from it was
one level too shallow. Now parents[3], and test_api_v3_url_map.py asserts
PROJECT_ROOT/run.py exists so the next move cannot repeat it.
2. Module-attribute patching. Tests do
monkeypatch.setattr(api_v3_module, "_BACKUP_EXPORT_DIR", ...) and a route
module that binds such a name by value never sees the patch. The shared code
therefore stays in __init__.py rather than moving to a _common submodule --
it has to live on the module the tests patch -- and the eleven names tests
patch are read back through the package (_pkg.X) instead of bound by value.
Those eleven were found by AST-scanning every setattr in the test tree, not
by guessing; "time" is among them, used to drive a fake clock through the
second-resolution credential-backup filenames.
Test changes are confined to what genuinely moved: patch targets that now name
the owning route module, imports of helpers, and six tests that scan the api_v3
source as a file and now read the package directory.
Full suite: 4,278 passed, 68 skipped, 0 failed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014RRtqXDCnvnY6EQwhT5CV9
The 3.2.0 section described the unified sports library but none of the
install-path work that landed in #428 and #431 -- which matters more than a
normal changelog omission, because the sunset rule keys on this section to
tell plugin authors what a given floor buys them.
The headline addition: 3.2.0 is the first release that *enforces*
ledmatrix_min_version. Before it the floor was advisory, so a plugin could
declare one and still be delivered to a core that could not run it. That is
the property B6 waits on, and it is now stated where a plugin author will
look for it -- along with the caveat that a core reporting below 2.0.0 is
treated as unknown rather than old and is never blocked.
Also records compatibility.py (and that it does not yet read
compatible_versions), check_release_version.py and its workflow, the
install-preservation fix, the reentrant-lock deadlock fix, and the
web_interface version re-export.
No version bump: 3.2.0 is unreleased, so this describes the release being
cut rather than a new one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Udr6MfaFLUPhX5Fgo67Jf5