"""Verify the Searchlight handler-set fix (Gitea #61, input-path audit cause #1). Searchlight's MessageHandlerSet was DEFAULT-CONSTRUCTED (entryCount 0, no parent chain), so Receiver::Receive dropped its "ToggleLamp" message (id 3) in silence. Before the fix the identical rig produced: [btntest] PRESS 0x14 at poll 400 [msg] UNHANDLED: Searchlight has no handler for message id 3 -- silently dropped The binary's table @0051120c holds exactly one entry { 3, "ToggleLamp", @004b860c }. PASS = the UNHANDLED line is GONE **and** a [light] line shows commandedOn flipping. Uses the real click seam (BT_BTNTEST, L4PADRIO.cpp:393), not a synthetic call. Kills only the PID it spawns. """ import os import re import subprocess import sys import time REPO = r"C:\git\bt411" LOG = os.path.join(REPO, "scratchpad_lamp.log") if os.path.exists(LOG): os.remove(LOG) env = dict(os.environ) env.update({ "BT_START_INSIDE": "1", "BT_DEV_GAUGES": "1", "BT_FIRE_LOG": "1", # enables the [light] proof line "BT_HEAT_LOG": "1", # press 0x14 (the searchlight button) at poll 400, release at 900, twice over # the run so we see the toggle go ON then back OFF. "BT_BTNTEST": "0x14,400,900", "BT_LOG": LOG, }) proc = subprocess.Popen( [os.path.join(REPO, "build", "Release", "btl4.exe"), "-egg", "LAST.EGG"], cwd=os.path.join(REPO, "content"), env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) print("pid", proc.pid) try: deadline = time.time() + 240 seen_release = False while time.time() < deadline: if os.path.exists(LOG): t = open(LOG, errors="replace").read() if "RELEASE 0x14" in t: seen_release = True break time.sleep(2) time.sleep(8) finally: proc.terminate() time.sleep(1) t = open(LOG, errors="replace").read() if os.path.exists(LOG) else "" btn = re.findall(r"^\[btntest\].*$", t, re.M) light = re.findall(r"^\[light\].*$", t, re.M) unh_sl = re.findall(r"^\[msg\] UNHANDLED.*Searchlight.*$", t, re.M) unh_any = re.findall(r"^\[msg\] UNHANDLED.*$", t, re.M) print("\n=============== RESULT ===============") print("reached the button press:", seen_release) for l in btn[:6]: print(" ", l[:130]) print("\n[light] toggle lines:", len(light)) for l in light[:6]: print(" ", l[:150]) print("\n[msg] UNHANDLED mentioning Searchlight:", len(unh_sl)) for l in unh_sl[:4]: print(" ", l[:140]) print("\nall other UNHANDLED pairs still open:", len(unh_any) - len(unh_sl)) for l in [x for x in unh_any if "Searchlight" not in x][:10]: print(" ", l[:140]) lit = [l for l in light if "reported lightState 0 -> 1" in l] ok = light and not unh_sl and lit print("\nVERDICT:", "PASS -- ToggleLamp handled AND the lamp actually lit (lightState 0 -> 1)" if ok else ("still UNHANDLED -- the chain did not take" if unh_sl else ("handler ran but lightState never reached 1 -- the toggle does not reach the lamp" if light else "no [light] line -- handler bound but the gate refused"))) sys.exit(0 if ok else 2)