Synced from resonance-engine-active - July 16 2026
This commit is contained in:
@@ -0,0 +1,240 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Differential hold-time A/B: perturbed vs unperturbed CONTROL from same checkpoint.
|
||||
Save to "." (daemon working dir), find checkpoint by glob.
|
||||
Cancels mass-leak drift — both runs share the same leak, difference isolates perturbation.
|
||||
|
||||
Mandatory sanity gate: Arm A (density, dead channel) MUST decay faster than Arm B (stress).
|
||||
If density == stress, the measurement is still broken — STOP.
|
||||
"""
|
||||
import zmq, json, time, struct, glob, os
|
||||
import numpy as np
|
||||
|
||||
# Daemon's working dir is /mnt/d/resonance-engine-active
|
||||
CKPT_DIR = "/mnt/d/resonance-engine-active"
|
||||
|
||||
def main():
|
||||
ctx = zmq.Context()
|
||||
|
||||
cp = ctx.socket(zmq.PUB); cp.connect("tcp://127.0.0.1:5557")
|
||||
ack_sub = ctx.socket(zmq.SUB); ack_sub.connect("tcp://127.0.0.1:5559")
|
||||
ack_sub.setsockopt_string(zmq.SUBSCRIBE, "")
|
||||
coarse_sub = ctx.socket(zmq.SUB); coarse_sub.connect("tcp://127.0.0.1:5561")
|
||||
coarse_sub.setsockopt_string(zmq.SUBSCRIBE, "")
|
||||
time.sleep(1.0)
|
||||
|
||||
# Drain
|
||||
for s in [coarse_sub, ack_sub]:
|
||||
while True:
|
||||
try: s.recv(flags=zmq.NOBLOCK)
|
||||
except zmq.ZMQError: break
|
||||
|
||||
def send_cmd(d):
|
||||
cp.send_string(json.dumps(d))
|
||||
time.sleep(0.05)
|
||||
|
||||
def wait_ack(cmd_name, timeout=8.0):
|
||||
ack_sub.setsockopt(zmq.RCVTIMEO, int(timeout * 1000))
|
||||
start = time.time()
|
||||
while time.time() - start < timeout:
|
||||
try:
|
||||
ack = json.loads(ack_sub.recv_string())
|
||||
if ack.get("ack") == cmd_name:
|
||||
ack_sub.setsockopt(zmq.RCVTIMEO, -1)
|
||||
return ack
|
||||
except zmq.ZMQError:
|
||||
pass
|
||||
ack_sub.setsockopt(zmq.RCVTIMEO, -1)
|
||||
return None
|
||||
|
||||
def drain_coarse():
|
||||
while True:
|
||||
try: coarse_sub.recv(flags=zmq.NOBLOCK)
|
||||
except zmq.ZMQError: break
|
||||
|
||||
def collect_coarse(n_frames):
|
||||
coarse_sub.setsockopt(zmq.RCVTIMEO, 90000)
|
||||
frames = []
|
||||
while len(frames) < n_frames:
|
||||
try:
|
||||
data = coarse_sub.recv()
|
||||
if len(data) >= 16 + 4 * 6144 and data[:4] == b"KGCF":
|
||||
cycle = struct.unpack_from("<I", data, 4)[0]
|
||||
vals = np.frombuffer(data, dtype=np.float32, count=6144, offset=16)
|
||||
field = vals.reshape(32, 32, 6).astype(np.float64)
|
||||
frames.append((cycle, field))
|
||||
except zmq.ZMQError:
|
||||
break
|
||||
coarse_sub.setsockopt(zmq.RCVTIMEO, -1)
|
||||
return frames
|
||||
|
||||
# ========== SETTLE ==========
|
||||
print(f"Settling for 2600 cycles...")
|
||||
drain_coarse()
|
||||
time.sleep(2)
|
||||
skip = collect_coarse(260)
|
||||
print(f"Settle complete. Last cycle: {skip[-1][0]}")
|
||||
|
||||
# ========== SAVE CHECKPOINT ==========
|
||||
# Daemon treats path as a directory; save to "." = daemon's cwd = CKPT_DIR
|
||||
# Remove any old test checkpoint written by this script
|
||||
for f in glob.glob(f"{CKPT_DIR}/ckpt_*_test.bin"):
|
||||
os.remove(f)
|
||||
|
||||
send_cmd({"cmd": "save_state", "path": "."})
|
||||
ack = wait_ack("save_state", timeout=12.0)
|
||||
if ack is None or ack.get("status") != "ok":
|
||||
print(f"FAIL: save_state failed. ACK: {ack}")
|
||||
exit(1)
|
||||
save_cycle = ack.get("cycle", 0)
|
||||
print(f"Checkpoint saved at cycle {save_cycle}")
|
||||
|
||||
# Find the actual checkpoint file
|
||||
time.sleep(0.5)
|
||||
ckpt_files = sorted(glob.glob(f"{CKPT_DIR}/ckpt_*.bin"))
|
||||
# Filter to the one just created (closest to save_cycle)
|
||||
ckpt_path = None
|
||||
for f in ckpt_files:
|
||||
# Parse cycle from filename
|
||||
basename = os.path.basename(f)
|
||||
parts = basename.replace(".bin", "").split("_c")
|
||||
if len(parts) == 2:
|
||||
try:
|
||||
fcycle = int(parts[1])
|
||||
if abs(fcycle - save_cycle) < 100: # within 100 cycles
|
||||
ckpt_path = basename
|
||||
break
|
||||
except ValueError:
|
||||
pass
|
||||
if ckpt_path is None:
|
||||
# Fallback: use latest
|
||||
ckpt_path = os.path.basename(ckpt_files[-1])
|
||||
print(f"Using checkpoint: {ckpt_path}")
|
||||
|
||||
# ========== CONTROL RUN ==========
|
||||
print("\n=== CONTROL RUN (no perturbation) ===")
|
||||
drain_coarse()
|
||||
time.sleep(1)
|
||||
control_frames = collect_coarse(260)
|
||||
print(f"Control: {len(control_frames)} frames, cycles {control_frames[0][0]} - {control_frames[-1][0]}")
|
||||
|
||||
# ========== LOAD CHECKPOINT ==========
|
||||
print(f"\nLoading checkpoint for Arm A...")
|
||||
send_cmd({"cmd": "load_state", "path": ckpt_path})
|
||||
ack = wait_ack("load_state", timeout=15.0)
|
||||
if ack is None or ack.get("status") != "ok":
|
||||
print(f"FAIL: load_state failed. ACK: {ack}")
|
||||
exit(1)
|
||||
drain_coarse()
|
||||
time.sleep(2)
|
||||
skip = collect_coarse(60)
|
||||
print(f"Post-load settle: last cycle {skip[-1][0]}")
|
||||
|
||||
# ========== PERTURBED RUN (Arm A: density) ==========
|
||||
print("\n=== ARM A: inject_density ===")
|
||||
drain_coarse()
|
||||
time.sleep(0.5)
|
||||
send_cmd({"cmd": "inject_density", "x": 512.0, "y": 512.0, "sigma": 16.0, "strength": 0.1})
|
||||
time.sleep(0.5)
|
||||
perturb_a = collect_coarse(260)
|
||||
print(f"Arm A: {len(perturb_a)} frames")
|
||||
|
||||
# ========== LOAD CHECKPOINT again for Arm B ==========
|
||||
print(f"\nLoading checkpoint for Arm B...")
|
||||
send_cmd({"cmd": "load_state", "path": ckpt_path})
|
||||
ack = wait_ack("load_state", timeout=15.0)
|
||||
if ack is None or ack.get("status") != "ok":
|
||||
print(f"FAIL: load_state failed for Arm B")
|
||||
exit(1)
|
||||
drain_coarse()
|
||||
time.sleep(2)
|
||||
skip = collect_coarse(60)
|
||||
print(f"Post-load settle: last cycle {skip[-1][0]}")
|
||||
|
||||
# ========== PERTURBED RUN (Arm B: stress) ==========
|
||||
print("\n=== ARM B: perturb_stress ===")
|
||||
drain_coarse()
|
||||
time.sleep(0.5)
|
||||
send_cmd({"cmd": "perturb_stress", "x": 512.0, "y": 512.0, "sigma": 16.0, "strength": 0.1})
|
||||
time.sleep(0.5)
|
||||
perturb_b = collect_coarse(260)
|
||||
print(f"Arm B: {len(perturb_b)} frames")
|
||||
|
||||
# ========== ANALYSIS ==========
|
||||
print("\n" + "=" * 60)
|
||||
print("DIFFERENTIAL HOLD-TIME ANALYSIS")
|
||||
print("=" * 60)
|
||||
|
||||
n = min(len(control_frames), len(perturb_a), len(perturb_b))
|
||||
control_arrays = np.stack([f[1] for f in control_frames[:n]])
|
||||
diffs = np.diff(control_arrays, axis=0)
|
||||
baseline_noise = np.mean(diffs ** 2)
|
||||
threshold = 0.05 * baseline_noise
|
||||
print(f"Baseline noise: {baseline_noise:.6e}")
|
||||
print(f"Return threshold (5% of baseline noise): {threshold:.6e}")
|
||||
|
||||
def compute_hold_time(perturb_frames, label):
|
||||
distances = []
|
||||
for i in range(n):
|
||||
d = np.mean((perturb_frames[i][1] - control_frames[i][1]) ** 2)
|
||||
distances.append(d)
|
||||
distances = np.array(distances)
|
||||
|
||||
print(f"\n{label}:")
|
||||
print(f" Distance range: [{distances[0]:.6e}, {distances[-1]:.6e}]")
|
||||
print(f" Frames above threshold: {np.sum(distances >= threshold)}/{n}")
|
||||
|
||||
hold_idx = None
|
||||
for i in range(10, n - 5):
|
||||
if distances[i] < threshold and np.all(distances[i:i + 5] < threshold):
|
||||
hold_idx = i
|
||||
break
|
||||
|
||||
if hold_idx is not None:
|
||||
hold_cycles = hold_idx * 10
|
||||
print(f" Returned at frame {hold_idx} (~{hold_cycles} cycles)")
|
||||
else:
|
||||
hold_cycles = n * 10
|
||||
print(f" Never returned within window ({hold_cycles} cycles)")
|
||||
|
||||
# Bootstrap CI
|
||||
np.random.seed(42)
|
||||
boot_samples = []
|
||||
for _ in range(100):
|
||||
idx = np.random.choice(n, n, replace=True)
|
||||
boot_d = np.array([np.mean((perturb_frames[j][1] - control_frames[j][1]) ** 2) for j in idx if j < n])
|
||||
boot_hold = None
|
||||
for j in range(10, n - 5):
|
||||
if boot_d[j] < threshold and np.all(boot_d[j:j + 5] < threshold):
|
||||
boot_hold = j
|
||||
break
|
||||
boot_samples.append(float(boot_hold * 10) if boot_hold is not None else float(n * 10))
|
||||
|
||||
ci_low = np.percentile(boot_samples, 2.5)
|
||||
ci_high = np.percentile(boot_samples, 97.5)
|
||||
print(f" Hold-time: {hold_cycles} cycles, 95% CI: [{ci_low:.0f}, {ci_high:.0f}]")
|
||||
return hold_cycles, ci_low, ci_high
|
||||
|
||||
ht_a, lo_a, hi_a = compute_hold_time(perturb_a, "Arm A: inject_density")
|
||||
ht_b, lo_b, hi_b = compute_hold_time(perturb_b, "Arm B: perturb_stress")
|
||||
|
||||
# ========== SANITY GATE ==========
|
||||
print("\n" + "=" * 60)
|
||||
print("SANITY GATE: Does density decay faster than stress?")
|
||||
print("=" * 60)
|
||||
print(f" Arm A (density): {ht_a} cycles, CI [{lo_a:.0f}, {hi_a:.0f}]")
|
||||
print(f" Arm B (stress): {ht_b} cycles, CI [{lo_b:.0f}, {hi_b:.0f}]")
|
||||
|
||||
if ht_a < ht_b:
|
||||
print(f" GATE PASS: density ({ht_a}) < stress ({ht_b}) — instrument is working.")
|
||||
elif ht_a > ht_b:
|
||||
print(f" ANOMALOUS: density ({ht_a}) > stress ({ht_b}) — unexpected, investigate.")
|
||||
else:
|
||||
print(f" GATE FAIL: density ({ht_a}) == stress ({ht_b}) — instrument STILL broken.")
|
||||
print(f" STOP. Do NOT proceed to sweep engine until this is fixed.")
|
||||
|
||||
cp.close(); ack_sub.close(); coarse_sub.close(); ctx.term()
|
||||
print("\nDone.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user