ROUTING learns stems the template does not name from the set (routing-learned.json); amber ones are fixed by hold/auto-fix from what the name says and earlier sets; START routes learned stems too

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-27 12:49:03 -04:00
co-authored by Claude Opus 5.5
parent 9551e043a7
commit a4d5fbe1aa
4 changed files with 112 additions and 8 deletions
+44 -1
View File
@@ -4,6 +4,8 @@ watchdog and the page builder show them. Run: python3 -m unittest discover -s t
import json
import logging
import os
import shutil
import tempfile
import sys
import unittest
from datetime import datetime
@@ -13,6 +15,7 @@ sys.path.insert(0, ROOT)
import make_page # noqa: E402
import readiness as rd # noqa: E402
rd.LEARNED_ROUTING = os.path.join(tempfile.mkdtemp(prefix="sp-learned-"), "routing-learned.json") # never the repo's
import status_panel as sp # noqa: E402
sp.log.addHandler(logging.NullHandler())
@@ -362,9 +365,49 @@ def live_set(**over):
class TestAbletonLive(unittest.TestCase):
def setUp(self):
d = tempfile.mkdtemp()
self.addCleanup(shutil.rmtree, d)
orig = rd.LEARNED_ROUTING
rd.LEARNED_ROUTING = os.path.join(d, "routing-learned.json")
self.addCleanup(setattr, rd, "LEARNED_ROUTING", orig)
def test_a_new_stem_is_learned_from_the_set(self):
"""User, 2026-10-27: the set's routing is right; learn the stems the template does not name."""
routing, _, changes = rd.mix_plan(RC, live_set())
self.assertNotIn("BANJO", " ".join(msgs(routing)))
self.assertIn("learned: BANJO goes to Ext. Out 7/8 GTRS (JEHOVAH)", routing.notes)
self.assertEqual(rd.learned_routing(), {"BANJO": ["Ext. Out", "7/8 GTRS"]})
self.assertEqual(rd.start_params(RC, [], "run")["routing"]["BANJO"], ["Ext. Out", "7/8 GTRS"])
# Next week the banjo lands on Keys: amber, and a hold (or auto-fix) moves it back (a banjo is a guitar).
over = live_set()
over["tracks"][-1] = dict(over["tracks"][-1], channel="5/6 Keys")
routing, _, changes = rd.mix_plan(RC, over)
self.assertIn("BANJO TO 5/6 KEYS", msgs(routing))
self.assertEqual([lv for lv, m, _ in routing.faults if m.startswith("BANJO")], [rd.WARN])
self.assertIn({"index": 16, "name": "70-Banjo [2026-10-21 132128]", "type": "Ext. Out", "channel": "7/8 GTRS"}, changes)
self.assertEqual(rd.learned_routing(), {"BANJO": ["Ext. Out", "7/8 GTRS"]})
def test_what_a_stem_is_by_its_name(self):
t = {rd.stem_name(k): v for k, v in RC["routing"].items()}
keys, gtrs, perc, vox = (list(t[k]) for k in ("PIANO", "EG 1", "PERC", "BGVS"))
for name, want in (("29-Synth FX", keys), ("30-Synth Loop", keys), ("33-Arps 1", keys), ("35-Bells", keys),
("49-Loop 1", perc), ("74-Shaker [2026-10-26 114326]", perc), ("75-Tambourine 1", perc),
("99-Drums [2026-10-26 114524]", perc), ("Sub Bass", list(t["SYNTH BASS"])), ("Mandolin", gtrs),
("Vox FX 2", vox), ("Choir 4", vox)):
self.assertEqual(rd.stem_kind(t, name), want, name)
self.assertIsNone(rd.stem_kind(t, "Click"))
# An unknown name goes where earlier sets had it; a new one that agrees with its name is learned.
rd.save_learned_routing({"WHISTLE": ["Ext. Out", "11/12 VOX"]})
over = live_set()
over["tracks"].append(dict(over["tracks"][-1], name="71-Whistle", index=17, channel="5/6 Keys"))
routing, _, changes = rd.mix_plan(RC, over)
self.assertIn("WHISTLE TO 5/6 KEYS", msgs(routing))
self.assertIn({"index": 17, "name": "71-Whistle", "type": "Ext. Out", "channel": "11/12 VOX"}, changes)
def test_routing_and_in_ears(self):
routing, ears, changes = rd.mix_plan(RC, live_set())
self.assertEqual(msgs(routing), ["BASS TO MASTER", "NEW STEM BANJO"])
self.assertEqual(msgs(routing), ["BASS TO MASTER"])
self.assertEqual(msgs(ears), ["EARS OFF JEHOVAH"])
self.assertIn("50-Keys 1 [2026-10-21 132128] in JEHOVAH: send A is at -inf", ears.as_dict()["details"])
# EG 13 is not in the template, but every EG goes to 7/8 GTRS; RESI and top-level tracks keep their -inf sends