108 lines
3.6 KiB
Python
108 lines
3.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Live parity harness for the persona_gate gap port (#2479 tranche, GO).
|
|
|
|
Runs the LIVE Python oracle (_py_decide / decide dispatch, embedder down
|
|
via a dead OLLAMA_URL on BOTH sides) against the Go binary's py-decide
|
|
command over every py_decide truth input plus extra live edge cases.
|
|
100% parity required. No socket, no model, no journal: the only IO is
|
|
the in-process decision itself.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
REPO = Path(__file__).resolve().parents[1]
|
|
os.environ["RUNE_COGNITION_CORE"] = "python"
|
|
os.environ["OLLAMA_URL"] = "http://127.0.0.1:9" # embedder down BOTH sides
|
|
|
|
sys.path.insert(0, str(REPO / "src"))
|
|
import rune.persona_gate as pg # noqa: E402
|
|
|
|
GO_DIR = REPO / "src" / "go" / "persona-gate"
|
|
|
|
|
|
def go_py_decide(text, rules):
|
|
wire = [dict(r, words=sorted(r["words"])) for r in rules]
|
|
out = subprocess.run(
|
|
["go", "run", ".", "py-decide", "--rules", json.dumps(wire), text],
|
|
cwd=GO_DIR, capture_output=True, text=True,
|
|
env={**os.environ, "OLLAMA_URL": "http://127.0.0.1:9"},
|
|
timeout=120,
|
|
)
|
|
if out.returncode != 0:
|
|
raise RuntimeError(f"go run failed: {out.stderr}")
|
|
return json.loads(out.stdout)
|
|
|
|
|
|
def norm(d):
|
|
d = json.loads(json.dumps(d))
|
|
if d.get("cited") is None:
|
|
d["cited"] = None
|
|
if d.get("engaged") is None:
|
|
d["engaged"] = []
|
|
return d
|
|
|
|
|
|
def mk_rule(text, topic="operating", priority=5, restrictive=False, user_rule=False):
|
|
words = pg._py_lex(text)
|
|
return {
|
|
"text": text, "topic": topic, "priority": priority,
|
|
"restrictive": restrictive, "user_rule": user_rule,
|
|
"words": set(words),
|
|
"core": " ".join(sorted(words)),
|
|
}
|
|
|
|
|
|
cases = []
|
|
|
|
# 1. every frozen py_decide input, replayed LIVE (embedder down on both sides)
|
|
truth = json.loads((GO_DIR / "truth.json").read_text())
|
|
for row in truth["rows"]:
|
|
if row["fn"] == "py_decide":
|
|
rules = [dict(r, words=set(r["words"])) for r in row["rules"]]
|
|
cases.append((f"frozen:{row['name']}", row["text"], rules))
|
|
|
|
# 2. extra live edge cases
|
|
R = [
|
|
mk_rule("never publish dangerous devices", topic="constitution", priority=0,
|
|
restrictive=True, user_rule=True),
|
|
mk_rule("keep the memory store tidy", priority=3),
|
|
mk_rule("protect the live game environment from cold calculation"),
|
|
]
|
|
LIVE = [
|
|
("", R),
|
|
("never publish the foundry vtt system", R),
|
|
("I NEVER ignore a point raised in review", R),
|
|
("update the github for the memory project", R),
|
|
("what time is it", R),
|
|
("the devices are dangerous and must be tested", R),
|
|
("homemade AK47 devices", R),
|
|
("tidy up the store please", R),
|
|
("protect live games from calculation", R),
|
|
(" surrounded by whitespace ", R),
|
|
("ÉMIGRÉ café devices naïve", R),
|
|
("w" * 400, R),
|
|
("no rules at all", []),
|
|
("must override bypass force the gate", R),
|
|
]
|
|
for i, (text, rules) in enumerate(LIVE):
|
|
cases.append((f"live:{i}", text, rules))
|
|
|
|
fails = 0
|
|
for name, text, rules in cases:
|
|
oracle = norm(pg._py_decide(text, [dict(r) for r in rules]))
|
|
dispatch = norm(pg.decide(text, [dict(r) for r in rules]))
|
|
assert oracle == dispatch, f"{name}: decide dispatch != _py_decide"
|
|
go = norm(go_py_decide(text, rules))
|
|
if go != oracle:
|
|
fails += 1
|
|
print(f"PARITY FAIL {name}\n go: {json.dumps(go, ensure_ascii=False)}\n"
|
|
f" oracle: {json.dumps(oracle, ensure_ascii=False)}")
|
|
|
|
print(f"live parity: {len(cases) - fails}/{len(cases)} cases ({len(cases)} py_decide inputs, "
|
|
f"decide dispatch == _py_decide on all)")
|
|
sys.exit(1 if fails else 0)
|