mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-08-13 12:00:34 +00:00
130 lines
5.1 KiB
Python
130 lines
5.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Witness routed math templates through the Tang9K symbol surface.
|
|
|
|
This converts top entries from eigen_solved_math_router.py into short
|
|
Surface-0 payloads. The FPGA still only witnesses substitution/hash/counts;
|
|
the host owns the full template ranking and codec logic.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import importlib.util
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
|
|
DEFAULT_ROUTER = Path("4-Infrastructure/shim/eigen_solved_math_router_compression.json")
|
|
SURFACE_PATH = Path("4-Infrastructure/shim/tang9k_hutter_symbol_surface.py")
|
|
|
|
|
|
def load_surface_module():
|
|
spec = importlib.util.spec_from_file_location("tang9k_hutter_symbol_surface", SURFACE_PATH)
|
|
if spec is None or spec.loader is None:
|
|
raise RuntimeError(f"cannot load {SURFACE_PATH}")
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
def template_payload(entry: dict[str, Any], max_len: int = 16) -> bytes:
|
|
name = str(entry.get("model_name") or entry.get("family") or "template")
|
|
# Keep a readable bank-local token: uppercase, underscores become spaces,
|
|
# punctuation drops. This intentionally targets the tiny hardware LUT.
|
|
normalized = []
|
|
for ch in name.upper().replace("_", " "):
|
|
if ch.isalnum() or ch == " ":
|
|
normalized.append(ch)
|
|
token = "".join(normalized).strip() or "TEMPLATE"
|
|
return token.encode("ascii", "ignore")[:max_len]
|
|
|
|
|
|
def witness_entry(surface, entry: dict[str, Any], seq: int, port: str | None, baud: int, retries: int) -> dict[str, Any]:
|
|
payload = template_payload(entry)
|
|
frame = surface.build_frame(seq, payload)
|
|
expected = surface.receipt_for_payload(payload)
|
|
result = {
|
|
"schema": "tang9k_routed_template_witness_v1",
|
|
"model_name": entry.get("model_name"),
|
|
"family": entry.get("family"),
|
|
"evidence_tier": entry.get("evidence_tier"),
|
|
"routed_score": entry.get("routed_score"),
|
|
"payload_ascii": payload.decode("ascii", "replace"),
|
|
"payload_hex": payload.hex(),
|
|
"frame_hex": frame.hex(),
|
|
"expected": expected,
|
|
"expected_led_reservoir": surface.led_reservoir_address(
|
|
surface.pbacs_cmyk_state_for_payload(payload), expected["mapped_count"]
|
|
),
|
|
}
|
|
if port:
|
|
raw = surface.send_serial(port, baud, frame, retries=retries)
|
|
result["hardware_receipt_hex"] = raw.hex()
|
|
if raw:
|
|
try:
|
|
parsed = surface.parse_receipt(raw)
|
|
result["hardware_receipt"] = parsed
|
|
result["hardware_led_reservoir"] = surface.led_reservoir_address(
|
|
surface.pbacs_cmyk_state_for_payload(payload), parsed["mapped_count"]
|
|
)
|
|
result["hardware_matches_expected"] = (
|
|
parsed["status"] == 0
|
|
and parsed["hash16"] == expected["hash16"]
|
|
and parsed["mapped_count"] == expected["mapped_count"]
|
|
and parsed["literal_count"] == expected["literal_count"]
|
|
)
|
|
except ValueError as exc:
|
|
result["hardware_receipt"] = None
|
|
result["hardware_matches_expected"] = False
|
|
result["hardware_note"] = str(exc)
|
|
else:
|
|
result["hardware_receipt"] = None
|
|
result["hardware_matches_expected"] = False
|
|
result["hardware_note"] = "no UART receipt received"
|
|
return result
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--router-json", type=Path, default=DEFAULT_ROUTER)
|
|
parser.add_argument("--limit", type=int, default=5)
|
|
parser.add_argument("--seq-base", type=lambda value: int(value, 0), default=0xE0)
|
|
parser.add_argument("--port")
|
|
parser.add_argument("--baud", type=int, default=115200)
|
|
parser.add_argument("--retries", type=int, default=5)
|
|
parser.add_argument("--out", type=Path)
|
|
args = parser.parse_args()
|
|
|
|
router = json.loads(args.router_json.read_text(encoding="utf-8"))
|
|
surface = load_surface_module()
|
|
witnesses = []
|
|
for index, entry in enumerate(router.get("entries", [])[: args.limit]):
|
|
witnesses.append(
|
|
witness_entry(
|
|
surface=surface,
|
|
entry=entry,
|
|
seq=(args.seq_base + index) & 0xFF,
|
|
port=args.port,
|
|
baud=args.baud,
|
|
retries=args.retries,
|
|
)
|
|
)
|
|
bundle = {
|
|
"schema": "tang9k_routed_template_witness_bundle_v1",
|
|
"claim_boundary": "FPGA witnesses compact template tokens only; ranking and model validity remain host-side.",
|
|
"router_json": str(args.router_json),
|
|
"witness_count": len(witnesses),
|
|
"hardware_count": sum(1 for item in witnesses if item.get("hardware_matches_expected")),
|
|
"witnesses": witnesses,
|
|
}
|
|
text = json.dumps(bundle, indent=2, ensure_ascii=False)
|
|
if args.out:
|
|
args.out.parent.mkdir(parents=True, exist_ok=True)
|
|
args.out.write_text(text + "\n", encoding="utf-8")
|
|
print(text)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|