Fix and check builders: every fix is built from fields; today's 27 fixes carry their templates

settings/builders.py renders a fix's command from a builder (template) and its fields; validate
refuses a config whose stored command no longer equals what its fields build; the Fixes screen and
the remote checks in the key editor rebuild through /api/build and /api/build-check. config.json
adopts templates for all 27 fixes and 5 remote checks (ProPresenter's restart loop and Ableton's
quoting normalised, same behaviour); tests/test_builders.py (174 tests pass). Deployed to NA Ingest.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 14:17:31 -04:00
co-authored by Claude Fable 5.1
parent 02d0c77cd9
commit 187dd464c0
8 changed files with 2014 additions and 214 deletions
+12
View File
@@ -31,6 +31,7 @@ from settings import PARENT, HERE # noqa: F401
import schema
import status_panel as sp
from settings import apply as applying
from settings import builders
from settings import keyguide, probes
log = logging.getLogger("status-settings")
@@ -644,6 +645,8 @@ class Handler(http.server.BaseHTTPRequestHandler):
if path == "/api/live/midi":
snap = site.read_json("snapshot.json", {}) or {}
return self.send(200, {"local": snap.get("midi"), "remote": snap.get("remote_midi")})
if path == "/api/builders":
return self.send(200, {"fixes": builders.template_list(site.cfg), "checks": builders.check_template_list()})
if path == "/api/facts":
return self.send(200, {"facts": COMPANION_FACTS})
if path == "/api/snapshot":
@@ -734,6 +737,15 @@ class Handler(http.server.BaseHTTPRequestHandler):
site.draft.clear()
self.discard_atem()
return self.send(200, {"ok": True})
if path in ("/api/build", "/api/build-check"):
cfg = (site.draft.read() or {}).get("config") or site.load()
try:
if path == "/api/build":
fix = builders.build(cfg, body.get("fix") or {})
return self.send(200, {"ok": True, "fix": fix, "label": builders.suggest_label(cfg, fix)})
return self.send(200, {"ok": True, "check": builders.build_check(cfg, body.get("check") or {})})
except ValueError as e:
return self.send(200, {"ok": False, "error": str(e)})
if path == "/api/validate":
cfg = schema.unmask(body.get("config") or (site.draft.read() or {}).get("config") or site.load(), site.load())
return self.send(200, self.check(cfg))