#!/usr/bin/env python3 # -*- coding: utf-8 -*- """Debug-route gate (R-400) โ€” every control on the debug page must resolve to a handler, and every handler must be reachable from the page. WHY IT EXISTS. On 2026-08-31 the shipped debug page referenced 24 `/api/debug/...` addresses and the dispatcher answered 17. Seven controls did nothing, and three of those seven were not buttons at all: they fetch on page LOAD, so whole panels had been permanently empty and nobody had to click anything to be misled. This is the page an operator opens when something is already wrong. BOTH DIRECTIONS FAIL. A reference with no case is a dead control. A case with no reference is a handler nothing reaches โ€” the same defect mirrored, and the shape this project has now shipped eight times. Neither is a warning here. DELIBERATELY TEN LINES OF LOGIC. Two lists and a difference. Its value is that it cannot rot: a cleverer gate that understood routing would need maintaining, and an unmaintained gate is how the class hides in the first place. The dispatcher's EXACT-match switch with a NotFound default is what made the original defect visible, and this gate assumes exactly that shape โ€” do not make either clever. Run from controller/: python3 scripts/debug_route_gate.py """ import io import os import re import sys TEMPLATE = os.path.join("internal", "web", "templates", "debug.html") DISPATCH = os.path.join("internal", "web", "handler_debug.go") REF_RE = re.compile(r"/api/debug/([A-Za-z0-9/_-]+)") CASE_RE = re.compile(r'subpath\s*==\s*"([A-Za-z0-9/_-]+)"') def read(path): if not os.path.exists(path): print("DEBUG ROUTE GATE INCONCLUSIVE: %s not found (run from controller/)" % path) sys.exit(2) return io.open(path, encoding="utf-8").read() def main(): # Sets, not lists: the same address referenced by two controls is satisfied by one case (ยง8). refs = set(REF_RE.findall(read(TEMPLATE))) cases = set(CASE_RE.findall(read(DISPATCH))) dead = sorted(refs - cases) unreached = sorted(cases - refs) for name in dead: print("DEAD CONTROL %s references /api/debug/%s and %s has no case for it" % (TEMPLATE, name, DISPATCH)) for name in unreached: print("UNREACHED %s dispatches %r and %s never references it" % (DISPATCH, name, TEMPLATE)) if dead or unreached: print("DEBUG ROUTE GATE FAILED: %d dead control(s), %d unreached handler(s)" % (len(dead), len(unreached))) sys.exit(1) print("debug route gate OK - %d referenced address(es), all dispatched, none orphaned" % len(refs)) if __name__ == "__main__": main()