Files
resonance-engine/fractonaut_calibrate.py
T
2026-06-08 18:34:31 +07:00

185 lines
7.4 KiB
Python

"""fractonaut_calibrate.py - regression test for Fractonaut.
Run AFTER restarting Fractonaut with the new prompt. Drives the lattice
through 4 known states, declares the injection state to Fractonaut, asks
for an observation, grades it for forbidden/required patterns.
"""
import zmq, json, time, urllib.request, sys
from datetime import datetime
from pathlib import Path
CMD_PORT = 5557
FRACTO_API = "http://127.0.0.1:28822"
DWELL_BASELINE = 90
DWELL_STATE = 240
INJ_INTERVAL = 60
LEFT_X, RIGHT_X, CENTER_Y, SIGMA = 400, 624, 512, 48
OUT_DIR = Path(f"/mnt/d/Resonance_Engine/traj/calibrate_{datetime.now().strftime('%Y%m%dT%H%M%S')}")
OUT_DIR.mkdir(parents=True, exist_ok=True)
OUT_FILE = OUT_DIR / "calibration.jsonl"
ctx = zmq.Context()
cmd = ctx.socket(zmq.PUB)
cmd.connect(f"tcp://127.0.0.1:{CMD_PORT}")
time.sleep(0.5)
def send(d):
cmd.send_string(json.dumps(d)); time.sleep(0.05)
def log(m):
print(f"[{datetime.now().strftime('%H:%M:%S')}] {m}", flush=True)
def set_inj(state):
body = json.dumps({"state": state}).encode()
req = urllib.request.Request(f"{FRACTO_API}/set_injection_state",
data=body, headers={"Content-Type":"application/json"}, method="POST")
try:
with urllib.request.urlopen(req, timeout=5) as r:
return json.loads(r.read())
except Exception as e:
log(f" WARN set_inj({state}) failed: {e}")
return None
def ask(question, timeout=180):
body = json.dumps({"question": question}).encode()
req = urllib.request.Request(f"{FRACTO_API}/ask",
data=body, headers={"Content-Type":"application/json"}, method="POST")
t0 = time.time()
try:
with urllib.request.urlopen(req, timeout=timeout) as r:
return json.loads(r.read()).get("response",""), time.time()-t0
except Exception as e:
return f"(error: {e})", time.time()-t0
FORBIDDEN_ALWAYS = [
"left site","right site","left half","right half",
"pushed harder","side dominant","side is dominant",
"collapse","decay","amplifying trend",
"the buy side","the sell side",
]
FORBIDDEN_QUIESCENT = ["buy","sell","market","injection","inject","pulse"]
REQUIRED_QUIESCENT = ["quiescent","baseline","within","operating range","operating point"]
REQUIRED_ACTIVE = ["inject","pulse"]
# Phrases that flip a forbidden word into a denial / negation context.
# If the forbidden word appears within ~50 chars after any of these, it's
# NOT an assertive claim and should be allowed.
DENIAL_MARKERS = [
"no ", "not ", "without ", "rather than ", "no longer ",
"absence of ", "absent", "any directional ", "any external ",
"any market ", "any inject", "any pulse", "any buy", "any sell",
]
def _is_denied(text_lower, word_pos, word):
"""Return True if the occurrence of `word` at word_pos in text_lower
appears in a denial context (preceded within ~80 chars by a denial marker)."""
window_start = max(0, word_pos - 80)
preceding = text_lower[window_start:word_pos]
for marker in DENIAL_MARKERS:
if marker in preceding:
return True
return False
def _find_assertive(text_lower, word):
"""Find the first occurrence of `word` that is NOT in a denial context.
Returns the position, or -1 if all occurrences are denied."""
start = 0
while True:
pos = text_lower.find(word, start)
if pos == -1:
return -1
if not _is_denied(text_lower, pos, word):
return pos
start = pos + 1
def grade(state, response):
r = response.lower()
fails = []
for f in FORBIDDEN_ALWAYS:
if f in r:
pos = r.find(f)
if not _is_denied(r, pos, f):
fails.append(f"forbidden_always: '{f}'")
if state in ("BASELINE","KHRA_ELEVATED","GIXX_ELEVATED"):
for f in FORBIDDEN_QUIESCENT:
if _find_assertive(r, f) != -1:
fails.append(f"forbidden_in_quiescent (assertive): '{f}'")
if state == "BASELINE":
if not any(req in r for req in REQUIRED_QUIESCENT):
fails.append("missing_required_quiescent")
if state == "ALL_ON":
# For ALL_ON we need at least one ASSERTIVE mention of injection
if not any(_find_assertive(r, req) != -1 for req in REQUIRED_ACTIVE):
fails.append("missing_required_active (assertive)")
return ("PASS" if not fails else "FAIL"), fails
def run_state(name, khra, gixx, inject, dwell, inj_state):
log(f"=== STATE: {name} khra={khra} gixx={gixx} inject={inject} inj_state={inj_state} ===")
send({"cmd":"set_khra_amp","amp":khra})
send({"cmd":"set_gixx_amp","amp":gixx})
set_inj(inj_state)
log(f" dwell {dwell}s...")
t_start = time.time()
deadline = t_start + dwell
next_inj = t_start
while time.time() < deadline:
if inject and time.time() >= next_inj:
send({"cmd":"inject_density","x":LEFT_X,"y":CENTER_Y,"sigma":SIGMA,"strength":+0.15})
send({"cmd":"inject_density","x":RIGHT_X,"y":CENTER_Y,"sigma":SIGMA,"strength":-0.15})
log(f" injected dipole at t+{int(time.time()-t_start)}s")
next_inj = time.time() + INJ_INTERVAL
time.sleep(1)
q = (f"State {name}. Describe the substrate right now in 3-5 sentences. "
f"Only call out channels flagged with ! or !!. If nothing is flagged, "
f"say the substrate is in its quiescent operating range and stop.")
resp, took = ask(q)
verdict, fails = grade(name, resp)
log(f" [{name}] fracto ({took:.1f}s) {verdict}")
for f in fails:
log(f" FAIL: {f}")
log(f" response: {resp[:300]}{'...' if len(resp)>300 else ''}")
with open(OUT_FILE, "a") as fh:
fh.write(json.dumps({
"ts": datetime.now().isoformat(),
"state": name, "khra": khra, "gixx": gixx, "inject": inject,
"inj_state": inj_state, "verdict": verdict, "fails": fails,
"response": resp, "took_s": took,
}) + "\n")
return verdict
def main():
log("=== fractonaut_calibrate ===")
log(f"out: {OUT_DIR}")
try:
with urllib.request.urlopen(f"{FRACTO_API}/status", timeout=5) as r:
st = json.loads(r.read())
log(f"fracto OK: model={st['model']} cycle={st['cycle']} inj_state={st.get('injection_state','?')}")
except Exception as e:
log(f"FATAL: Fractonaut not reachable: {e}")
sys.exit(1)
verdicts = []
try:
verdicts.append(("BASELINE", run_state("BASELINE", 0.030, 0.008, False, DWELL_BASELINE, "INACTIVE")))
verdicts.append(("KHRA_ELEVATED", run_state("KHRA_ELEVATED", 0.050, 0.008, False, DWELL_STATE, "INACTIVE")))
verdicts.append(("GIXX_ELEVATED", run_state("GIXX_ELEVATED", 0.030, 0.024, False, DWELL_STATE, "INACTIVE")))
verdicts.append(("ALL_ON", run_state("ALL_ON", 0.050, 0.024, True, DWELL_STATE, "ACTIVE")))
finally:
log("=== RESTORE baseline ===")
send({"cmd":"set_khra_amp","amp":0.030})
send({"cmd":"set_gixx_amp","amp":0.008})
set_inj("UNKNOWN")
log(" (finally) baseline restored")
log("")
log("=== SUMMARY ===")
p = sum(1 for _,v in verdicts if v=="PASS")
f = sum(1 for _,v in verdicts if v=="FAIL")
for n,v in verdicts:
log(f" {n:<16} {v}")
log(f" TOTAL: {p} PASS / {f} FAIL")
log(f" file: {OUT_FILE}")
sys.exit(0 if f==0 else 1)
if __name__ == "__main__":
main()