217 lines
8.3 KiB
Python
217 lines
8.3 KiB
Python
"""khra_gixx_probe.py — 3-test probe of lattice parameter response.
|
|
|
|
Tests Claude Desktop's channel architecture using set_khra_amp + set_gixx_amp
|
|
+ inject_density. Asks Fractonaut to qualitatively describe each state.
|
|
|
|
States:
|
|
0. BASELINE (Khra=0.030, Gixx=0.008, no injection) - 2 min stabilise
|
|
1. KHRA_ELEVATED (Khra=0.050, Gixx=0.008, no injection) - 8 min
|
|
2. GIXX_ELEVATED (Khra=0.030, Gixx=0.024, no injection) - 8 min
|
|
3. ALL_ON (Khra=0.050, Gixx=0.024, opposing inject) - 8 min
|
|
4. RESTORE (back to baseline)
|
|
|
|
Total wall-clock: ~28 min.
|
|
|
|
The Fractonaut /ask query at end of each state asks for a qualitative
|
|
field description, not a number restatement. Saves all responses to
|
|
JSONL for side-by-side comparison.
|
|
"""
|
|
|
|
import zmq, json, time, urllib.request, sys
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
|
|
CMD_ADDR = "tcp://127.0.0.1:5557"
|
|
FRACTO_URL = "http://127.0.0.1:28822/ask"
|
|
TEL_ADDR = "tcp://127.0.0.1:5556"
|
|
OUT = Path(f"/mnt/d/Resonance_Engine/traj/probe_{datetime.now().strftime('%Y%m%dT%H%M%S')}")
|
|
OUT.mkdir(parents=True, exist_ok=True)
|
|
JSONL = OUT / "probe_observations.jsonl"
|
|
LOG = OUT / "probe.log"
|
|
|
|
# Wall-clock seconds per state (after baseline stabilise)
|
|
DWELL_S = 480 # 8 min — enough for field to fully equilibrate to new amps
|
|
BASELINE_S = 120 # 2 min stabilise at start
|
|
INJECT_PERIOD_S = 60 # for state 3, re-inject every 60s (capped strength 0.15)
|
|
|
|
BASELINE_KHRA = 0.030
|
|
BASELINE_GIXX = 0.008
|
|
ELEV_KHRA = 0.050
|
|
ELEV_GIXX = 0.024
|
|
|
|
LEFT_X, RIGHT_X, CENTER_Y = 400, 624, 512
|
|
SIGMA = 48
|
|
INJ_STRENGTH = 0.15
|
|
|
|
|
|
def log(msg):
|
|
ts = datetime.now().strftime("%H:%M:%S")
|
|
line = f"[{ts}] {msg}"
|
|
print(line, flush=True)
|
|
with open(LOG, "a") as f:
|
|
f.write(line + "\n")
|
|
|
|
|
|
def send_cmd(pub, payload):
|
|
pub.send_string(json.dumps(payload))
|
|
time.sleep(0.05)
|
|
|
|
|
|
def ask_fracto(state_name, question):
|
|
body = json.dumps({"question": question}).encode()
|
|
req = urllib.request.Request(FRACTO_URL, data=body,
|
|
headers={"Content-Type": "application/json"}, method="POST")
|
|
t0 = time.time()
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=180) as r:
|
|
res = json.loads(r.read())
|
|
resp = res.get("response", "")
|
|
except Exception as e:
|
|
resp = f"(error: {e})"
|
|
elapsed = time.time() - t0
|
|
entry = {
|
|
"ts": datetime.now().isoformat(),
|
|
"state": state_name,
|
|
"question": question,
|
|
"response": resp,
|
|
"elapsed_s": round(elapsed, 2),
|
|
}
|
|
with open(JSONL, "a") as f:
|
|
f.write(json.dumps(entry) + "\n")
|
|
log(f" [{state_name}] fracto ({elapsed:.1f}s, {len(resp)} chars):")
|
|
for line in resp.splitlines():
|
|
log(f" {line}")
|
|
return resp
|
|
|
|
|
|
def sample_telemetry(tel_sub, n=20):
|
|
"""Drain n recent telemetry frames and return summary stats."""
|
|
frames = []
|
|
t_end = time.time() + 3.0
|
|
while len(frames) < n and time.time() < t_end:
|
|
try:
|
|
msg = tel_sub.recv_string(zmq.NOBLOCK)
|
|
frames.append(json.loads(msg))
|
|
except zmq.Again:
|
|
time.sleep(0.05)
|
|
if not frames:
|
|
return None
|
|
keys = ["asymmetry", "coherence", "vel_max", "vel_var", "vorticity_mean",
|
|
"stress_xx", "stress_yy", "stress_xy"]
|
|
avg = {}
|
|
for k in keys:
|
|
vals = [f[k] for f in frames if k in f]
|
|
if vals:
|
|
avg[k] = sum(vals) / len(vals)
|
|
avg["cycle"] = frames[-1].get("cycle")
|
|
avg["n"] = len(frames)
|
|
return avg
|
|
|
|
|
|
def state_question(state, tel):
|
|
if tel is None:
|
|
return f"[{state}] No telemetry available."
|
|
return (
|
|
f"You are now in probe state: {state}. The lattice has been at these "
|
|
f"parameter settings for at least 5 minutes. Recent telemetry averages: "
|
|
f"asymmetry={tel.get('asymmetry',0):.2f}, coherence={tel.get('coherence',0):.4f}, "
|
|
f"vel_max={tel.get('vel_max',0):.4f}, vel_var={tel.get('vel_var',0):.6f}, "
|
|
f"vorticity_mean={tel.get('vorticity_mean',0):.4f}, "
|
|
f"stress_xx={tel.get('stress_xx',0):.6f}, stress_yy={tel.get('stress_yy',0):.6f}, "
|
|
f"stress_xy={tel.get('stress_xy',0):.6f}. "
|
|
f"Describe the QUALITATIVE character of this field state. Is the velocity "
|
|
f"field ordered or turbulent? Is the stress isotropic or directional? "
|
|
f"How does this state DIFFER from a baseline lattice (Khra=0.030, Gixx=0.008, "
|
|
f"no injection)? Be specific about which metrics changed and what the "
|
|
f"physical meaning is. 4-6 sentences. No bullet lists."
|
|
)
|
|
|
|
|
|
def main():
|
|
log(f"=== khra_gixx_probe ===")
|
|
log(f"out: {OUT}")
|
|
|
|
ctx = zmq.Context.instance()
|
|
pub = ctx.socket(zmq.PUB)
|
|
pub.connect(CMD_ADDR)
|
|
tel_sub = ctx.socket(zmq.SUB)
|
|
tel_sub.connect(TEL_ADDR)
|
|
tel_sub.setsockopt_string(zmq.SUBSCRIBE, "")
|
|
log("ZMQ connected; warming up 3s...")
|
|
time.sleep(3)
|
|
|
|
try:
|
|
# ─── State 0: BASELINE ───
|
|
log("\n=== STATE 0: BASELINE (Khra=0.030, Gixx=0.008, no inject) ===")
|
|
send_cmd(pub, {"cmd": "set_khra_amp", "value": BASELINE_KHRA})
|
|
send_cmd(pub, {"cmd": "set_gixx_amp", "value": BASELINE_GIXX})
|
|
log(f" dwelling {BASELINE_S}s for field to stabilise...")
|
|
time.sleep(BASELINE_S)
|
|
tel = sample_telemetry(tel_sub)
|
|
log(f" telemetry sample: {tel}")
|
|
ask_fracto("BASELINE", state_question("BASELINE", tel))
|
|
|
|
# ─── State 1: KHRA_ELEVATED ───
|
|
log("\n=== STATE 1: KHRA_ELEVATED (Khra=0.050, Gixx=0.008) ===")
|
|
send_cmd(pub, {"cmd": "set_khra_amp", "value": ELEV_KHRA})
|
|
send_cmd(pub, {"cmd": "set_gixx_amp", "value": BASELINE_GIXX})
|
|
log(f" dwelling {DWELL_S}s...")
|
|
time.sleep(DWELL_S)
|
|
tel = sample_telemetry(tel_sub)
|
|
log(f" telemetry sample: {tel}")
|
|
ask_fracto("KHRA_ELEVATED", state_question("KHRA_ELEVATED", tel))
|
|
|
|
# ─── State 2: GIXX_ELEVATED ───
|
|
log("\n=== STATE 2: GIXX_ELEVATED (Khra=0.030, Gixx=0.024) ===")
|
|
send_cmd(pub, {"cmd": "set_khra_amp", "value": BASELINE_KHRA})
|
|
send_cmd(pub, {"cmd": "set_gixx_amp", "value": ELEV_GIXX})
|
|
log(f" dwelling {DWELL_S}s...")
|
|
time.sleep(DWELL_S)
|
|
tel = sample_telemetry(tel_sub)
|
|
log(f" telemetry sample: {tel}")
|
|
ask_fracto("GIXX_ELEVATED", state_question("GIXX_ELEVATED", tel))
|
|
|
|
# ─── State 3: ALL_ON ───
|
|
log("\n=== STATE 3: ALL_ON (Khra=0.050, Gixx=0.024, +inject) ===")
|
|
send_cmd(pub, {"cmd": "set_khra_amp", "value": ELEV_KHRA})
|
|
send_cmd(pub, {"cmd": "set_gixx_amp", "value": ELEV_GIXX})
|
|
log(f" dwelling {DWELL_S}s with periodic injections (every {INJECT_PERIOD_S}s)...")
|
|
t_end = time.time() + DWELL_S
|
|
next_inject = time.time()
|
|
while time.time() < t_end:
|
|
if time.time() >= next_inject:
|
|
# opposing dipole: left buy positive, right sell negative
|
|
send_cmd(pub, {"cmd": "inject_density", "x": LEFT_X, "y": CENTER_Y,
|
|
"sigma": SIGMA, "strength": +INJ_STRENGTH})
|
|
send_cmd(pub, {"cmd": "inject_density", "x": RIGHT_X, "y": CENTER_Y,
|
|
"sigma": SIGMA, "strength": -INJ_STRENGTH})
|
|
log(f" injected dipole at t+{int(time.time()-(t_end-DWELL_S))}s")
|
|
next_inject = time.time() + INJECT_PERIOD_S
|
|
time.sleep(0.5)
|
|
tel = sample_telemetry(tel_sub)
|
|
log(f" telemetry sample: {tel}")
|
|
ask_fracto("ALL_ON", state_question("ALL_ON", tel))
|
|
|
|
# ─── State 4: RESTORE ───
|
|
log("\n=== STATE 4: RESTORE to baseline ===")
|
|
send_cmd(pub, {"cmd": "set_khra_amp", "value": BASELINE_KHRA})
|
|
send_cmd(pub, {"cmd": "set_gixx_amp", "value": BASELINE_GIXX})
|
|
log(f" baseline restored. Probe complete.")
|
|
log(f" observations: {JSONL}")
|
|
|
|
finally:
|
|
# ALWAYS restore baseline on any exit path
|
|
try:
|
|
send_cmd(pub, {"cmd": "set_khra_amp", "value": BASELINE_KHRA})
|
|
send_cmd(pub, {"cmd": "set_gixx_amp", "value": BASELINE_GIXX})
|
|
log(" (finally) baseline restored")
|
|
except Exception as e:
|
|
log(f" (finally) restore failed: {e}")
|
|
pub.close(0)
|
|
tel_sub.close(0)
|
|
ctx.term()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|