Research-Stack/4-Infrastructure/shim/validate_rrc_predictions.py
Brandon Schneider 835299fd9a fix(lean+shim): enforce lean-coding rules across audit surface
## Lean fixes

- RRCLogogramProjection.lean: replace `native_decide` → `decide` in 5
  compiler-surface theorem witnesses (semantic_tear_projects_after_repair,
  semantic_tear_does_not_merge, semantic_tear_uses_quarantine_lane,
  unrepaired_tear_does_not_project, ordinary_logogram_projects_and_merges).
  All 5 pass under `decide`; no logic change.

- PistSimulation.lean: add `-- expect: <value>` to every `#eval`/`#eval!`
  block across §6–§11 (~104 annotation lines). Document 8 undocumented
  `ofRawInt` magic integers in fixtureSpectralWindow (10.0, 20.0, 100.0,
  40.0, 20.0, 10.0, 5.0, 5.0 × 65536).

- DynamicCanal.lean: add `-- expect:` to all 15 #eval witness blocks in
  §17 (fixed-point constructors, DIAT encoding, coarse-graining tests).

- MISignal.lean: add `-- expect: 131072` to both #eval witnesses.

- Functions/BracketedCalculus.lean: add `-- expect: 327680` to #eval.

- AVMIsa/Emit.lean, RRC/Emit.lean, RRC/ReceiptDensity.lean, ReceiptCore.lean:
  previously-staged `-- expect:` additions (from prior session) carried
  forward in this commit.

## Python shim fixes

- Add `# PARTIAL BOUNDARY: contains domain logic; not a provable surface.
  Port to Lean/RRC before treating as authoritative.` to 9 shim files:
  pist_trace_classify_mcp.py, genus0_sphere_shell_demo.py,
  routing_benchmark.py, route_repair_v14a.py, pist_prove_and_classify.py,
  label_canary_theorems.py, validate_rrc_predictions.py,
  pist_receipt_density_injector.py, rrc_pist_shape_alignment.py.

## Build baseline

  lake build Compiler  →  3311 jobs, 0 errors
  lake build           →  3567 jobs, 0 errors

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-26 23:17:40 -05:00

351 lines
15 KiB
Python

#!/usr/bin/env python3
"""Batch-validate pist-decompose with matrix diagnostics and exact spectrum.
Reads docs/rrc_equation_classification.md, runs each equation through
pist-decompose, collects diagnostics:
- Are crossing matrices unique?
- Does exact spectrum classify better than convergence proxy?
"""
# PARTIAL BOUNDARY: contains domain logic; not a provable surface. Port to Lean/RRC before treating as authoritative.
import json
import os
import re
import subprocess
import sys
import tempfile
from collections import Counter, defaultdict
def require_path(obj, *path):
cur = obj
for key in path:
if key not in cur:
raise KeyError(f"Missing path: {'.'.join(path)} in result")
cur = cur[key]
return cur
PIST_DECOMPOSE = os.environ.get(
"PIST_DECOMPOSE_BIN",
"/home/allaun/.local/share/opencode/worktree/"
"0b42981cf7f7d5e172b1e93f8d4bb64a3dd63962/Turn-and-Burn/infra/rust/"
"ene-rds/target/release/pist-decompose",
)
RRC_FILE = os.path.join(os.path.dirname(__file__), "../..",
"docs/rrc_equation_classification.md")
def parse_rrc_table(path: str) -> list[dict]:
with open(path) as f:
text = f.read()
# Counts section (for header info)
counts_section = text.split("## Counts By RRC Shape")[-1].split("## ")[0]
print(f" Counts section: {sum(int(m[0]) for m in [re.findall(r'\|\s*`\w+`\s*\|\s*(\d+)', line) for line in counts_section.split(chr(10))] if m)} total", file=sys.stderr)
# Sample Projections section
equations = []
sample_section = text.split("## Sample Projections")[-1].split("## ")[0]
for line in sample_section.split("\n"):
parts = [p.strip().replace("`", "") for p in line.split("|")]
if len(parts) >= 5 and parts[1] and parts[2] and parts[3]:
eq_name = parts[1]
shape = parts[2]
status = parts[3]
equations.append({"equation": eq_name, "shape": shape, "status": status})
print(f" Sample section: {len(equations)} equations", file=sys.stderr)
return equations
MATH_OPERATORS = {
"adjusted", "overflow", "gate", "offload", "barrier", "temperature",
"efficiency", "stress", "mapping", "projection", "loss", "equations",
"field", "domain", "load", "threshold", "heat", "magnetic", "core",
"source", "target", "emotional", "trauma", "historical", "effective",
"raw", "total", "protective", "residual", "bandwidth", "cognitive",
}
MATH_VARIABLES = {
"cognitive_load", "emotional_load", "emotional_offload", "field_mapping",
"source_domain", "target_domain", "heat_loss", "magnetic_projection",
"core_equations", "bandwidth", "threshold", "overflow", "gate",
"temperature", "barrier", "efficiency", "stress", "protective",
"historical", "trauma", "emotional", "effective", "raw", "total",
"residual", "field", "source", "target", "core", "heat", "magnetic",
"projection", "mapping", "loss", "equations", "domain", "load",
}
MATH_CONSTANTS = {"pi", "e", "phi", "tau", "gamma", "delta", "lambda"}
def parse_equation(equation_text: str) -> dict:
"""Parse an equation name into structural math features."""
parts = equation_text.replace("-", "_").split("_")
parts = [p for p in parts if p]
ops = []
vars_seen = []
consts_seen = []
for p in parts:
if p in MATH_OPERATORS:
ops.append(p)
elif p in MATH_CONSTANTS:
consts_seen.append(p)
else:
vars_seen.append(p)
op_counts = {}
for op_name in ["adjusted", "overflow", "gate", "offload", "mapping", "projection", "loss"]:
op_counts[op_name] = ops.count(op_name)
depth = len(parts) if len(parts) <= 16 else 16
node_count = max(1, len(parts) * 2 - 1)
branching = max(1, len(set(parts)) / max(1, len(parts)))
symbol_entropy = 0.0
if len(parts) > 1:
import math
from collections import Counter
counts = Counter(parts)
total = len(parts)
symbol_entropy = -sum((c / total) * math.log2(c / total) for c in counts.values())
return {
"equation_text": equation_text,
"normalized_equation": "_".join(sorted(parts)),
"operators": list(set(ops)),
"variables": list(set(vars_seen)),
"constants": consts_seen,
"operator_counts": op_counts,
"ast_metrics": {
"node_count": node_count,
"depth": depth,
"branching_factor": round(branching, 4),
"symbol_entropy": round(symbol_entropy, 4),
},
}
def build_proof_metrics(shape: str) -> dict:
"""Heuristic proof metrics based on RRCShape class."""
if shape == "CognitiveLoadField":
return {"tactic_count": 3, "dependency_count": 2, "rewrite_count": 5, "simp_count": 8}
elif shape == "SignalShapedRouteCompiler":
return {"tactic_count": 4, "dependency_count": 3, "rewrite_count": 3, "simp_count": 6}
elif shape == "ProjectableGeometryTopology":
return {"tactic_count": 5, "dependency_count": 4, "rewrite_count": 7, "simp_count": 10}
elif shape == "CadForceProbeReceipt":
return {"tactic_count": 6, "dependency_count": 5, "rewrite_count": 4, "simp_count": 7}
elif shape == "LogogramProjection":
return {"tactic_count": 8, "dependency_count": 6, "rewrite_count": 9, "simp_count": 12}
else:
return {"tactic_count": 2, "dependency_count": 1, "rewrite_count": 2, "simp_count": 4}
def build_receipt(eq: dict) -> dict:
"""Build a structural receipt with enriched math features."""
struct = parse_equation(eq["equation"])
proof = build_proof_metrics(eq["shape"])
domain = eq["shape"].replace("CognitiveLoadField", "analysis") \
.replace("SignalShapedRouteCompiler", "topology") \
.replace("ProjectableGeometryTopology", "geometry") \
.replace("CadForceProbeReceipt", "physics") \
.replace("LogogramProjection", "symbolic") \
.replace("HoldForUnlawfulOrUnderspecifiedShape", "unknown")
return {
"receipt_version": "rrc-proof-receipt-v2",
"theorem_name": eq["equation"],
**struct,
"domain": domain,
"theorem_statement": f"{eq['equation']} is a {eq['shape']} equation",
"proof_script": f"by native_decide -- {eq['shape']}",
"imports": ["Semantics", "RRCShape"],
"dependencies": ["RRCLogogramProjection.lean"],
"source_hash": struct["normalized_equation"],
"environment_hash": f"lean4-v4.30.0-{eq['shape']}",
"status": "verified",
"kernel_checked": True,
"elapsed_ms": 42,
"proof_metrics": proof,
"metrics": {
"statement_chars": len(eq["equation"]),
"proof_chars": len(eq["shape"]),
"dependency_count": proof["dependency_count"],
"import_count": len(struct.get("operators", [])) + 2,
"tactic_count": proof["tactic_count"],
"ast_depth_estimate": struct["ast_metrics"]["depth"],
},
}
def classify(eq: dict, cmdline: str = "") -> dict:
receipt = build_receipt(eq)
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
json.dump(receipt, f)
fpath = f.name
try:
extra = cmdline.split()
result = subprocess.run(
[PIST_DECOMPOSE, fpath, "--num-leaves", "8"] + extra,
capture_output=True, text=True, timeout=15,
)
if result.returncode != 0:
return {"error": result.stderr[:200], "equation": eq["equation"]}
return json.loads(result.stdout)
finally:
os.unlink(fpath)
def main():
print("Loading RRC equation classification...", flush=True)
equations = parse_rrc_table(RRC_FILE)
print(f"Loaded {len(equations)} equations", flush=True)
predictions = []
errors = []
matrix_hashes = Counter()
canonical_hashes = Counter()
for i, eq in enumerate(equations):
print(f" [{i+1}/{len(equations)}] {eq['equation']:40s}", end="", flush=True)
result = classify(eq, "")
if "error" in result:
print(f"ERROR: {result['error'][:60]}", flush=True)
errors.append(result)
continue
mhash = require_path(result, "braid", "matrix_hash")[:16]
chash = require_path(result, "canonical_hash")[:16]
proxy_label = require_path(result, "rrc_shape", "proxy", "label")
exact_label = require_path(result, "rrc_shape", "exact", "label")
zmp = require_path(result, "spectral", "zero_mode_proxy_count")
sym_ev = require_path(result, "spectral", "symmetric_eigenvalues") or [0.0] * 8
sv_raw = result.get("spectral", {}).get("singular_values")
if sv_raw is None:
singular_v = [0.0] * 8
else:
singular_v = [float(v) if v is not None else 0.0 for v in sv_raw]
lap_zero = require_path(result, "spectral", "laplacian_zero_count")
rank = require_path(result, "spectral", "rank_estimate")
cd = require_path(result, "braid", "crossing_density")
sent = require_path(result, "braid", "strand_entropy")
gap = require_path(result, "spectral", "symmetric_spectral_gap")
matrix_hashes[mhash] += 1
canonical_hashes[chash] += 1
print(f"{proxy_label:35s} | exact={exact_label:30s} | ZMP={zmp} | hash={mhash} | "
f"rank={rank} | lap_zero={lap_zero} | gap={gap:.3f}",
flush=True)
predictions.append({
"equation": eq["equation"],
"ground_truth": eq["shape"],
"proxy_pred": proxy_label,
"exact_pred": exact_label,
"zmp": zmp,
"eigenvalues": [round(v, 4) for v in sym_ev],
"singular_values": [round(v, 4) for v in singular_v],
"laplacian_zero_count": lap_zero,
"rank_estimate": rank,
"crossing_density": cd,
"strand_entropy": sent,
"spectral_gap": round(gap, 4),
"matrix_hash": mhash,
"canonical_hash": chash,
})
# ── Diagnostics Report ──
print("\n" + "=" * 70, flush=True)
print("DIAGNOSTICS", flush=True)
print("=" * 70)
print(f"\nEquations processed: {len(predictions)}")
print(f"Errors: {len(errors)}")
print(f"Unique canonical hashes: {len(canonical_hashes)} / {len(predictions)}")
print(f"Unique matrix hashes: {len(matrix_hashes)} / {len(predictions)}")
# Duplicate analysis
dup_matrices = {h: c for h, c in matrix_hashes.items() if c > 1}
dup_canonical = {h: c for h, c in canonical_hashes.items() if c > 1}
if dup_matrices:
print(f"\nColliding matrix hashes ({len(dup_matrices)} groups):")
for h, c in sorted(dup_matrices.items(), key=lambda x: -x[1])[:10]:
eqs = [p["equation"] for p in predictions if p["matrix_hash"] == h]
print(f" {h} appears {c}x: {', '.join(eqs[:5])}")
if dup_canonical:
print(f"\nColliding canonical hashes ({len(dup_canonical)} groups):")
for h, c in sorted(dup_canonical.items(), key=lambda x: -x[1])[:10]:
eqs = [p["equation"] for p in predictions if p["canonical_hash"] == h]
print(f" {h} appears {c}x: {', '.join(eqs[:5])}")
else:
print("\nNo canonical hash collisions — every equation has a unique receipt fingerprint.")
# ── Classifier Accuracy ──
print("\n" + "=" * 70, flush=True)
print("CLASSIFIER ACCURACY", flush=True)
print("=" * 70)
for label, pred_key in [("PROXY (ZMP threshold)", "proxy_pred"), ("EXACT (spectral classifier)", "exact_pred")]:
correct = sum(1 for p in predictions if p[pred_key] == p["ground_truth"])
total = len(predictions)
acc = correct / total * 100 if total > 0 else 0
print(f"\n{label}: {correct}/{total} = {acc:.1f}%")
# Per class
classes = sorted(set(p["ground_truth"] for p in predictions) |
set(p[pred_key] for p in predictions))
print(f" {'Class':35s} {'Count':>6} {'Correct':>8} {'Acc':>6}")
print(f" {'-'*35} {'-'*6} {'-'*8} {'-'*6}")
for cls in classes:
cls_total = sum(1 for p in predictions if p["ground_truth"] == cls)
cls_correct = sum(1 for p in predictions if p["ground_truth"] == cls and p[pred_key] == cls)
print(f" {cls:35s} {cls_total:6d} {cls_correct:8d} {(cls_correct/cls_total*100 if cls_total else 0):5.1f}%")
# ── ZMP Distribution by Ground Truth ──
print(f"\n ZMP distribution by ground truth:")
zmp_by_gt = defaultdict(list)
for p in predictions:
zmp_by_gt[p["ground_truth"]].append(p["zmp"])
for gt in sorted(zmp_by_gt.keys()):
vals = zmp_by_gt[gt]
print(f" {gt:35s} mean={sum(vals)/len(vals):.2f} min={min(vals)} max={max(vals)} uniq={len(set(vals))}")
# ── Spectral Feature Distribution ──
print(f"\n Spectral feature ranges:")
for key, label in [("laplacian_zero_count", "Lap zero count"),
("rank_estimate", "Rank estimate"),
("crossing_density", "Crossing density"),
("strand_entropy", "Strand entropy"),
("spectral_gap", "Spectral gap")]:
vals = [p.get(key, 0) for p in predictions]
uniq = len(set(vals))
print(f" {label:25s}: uniq={uniq:2d} min={min(vals):.4f} max={max(vals):.4f} {'' if uniq > 1 else '(SINGLETON — no discriminative power)'}")
# ── Save report ──
report = {
"summary": {
"total": len(predictions),
"errors": len(errors),
"unique_matrix_hashes": len(matrix_hashes),
"unique_canonical_hashes": len(canonical_hashes),
"proxy_accuracy": sum(1 for p in predictions if p["proxy_pred"] == p["ground_truth"]) / len(predictions) if predictions else 0,
"exact_accuracy": sum(1 for p in predictions if p["exact_pred"] == p["ground_truth"]) / len(predictions) if predictions else 0,
"matrix_hash_collisions": sum(1 for h, c in matrix_hashes.items() if c > 1),
"canonical_hash_collisions": sum(1 for h, c in canonical_hashes.items() if c > 1),
},
"per_class_proxy": {},
"per_class_exact": {},
"zmp_distribution": {gt: {"mean": sum(v)/len(v), "min": min(v), "max": max(v), "unique": len(set(v))}
for gt, v in zmp_by_gt.items()},
"predictions": predictions,
}
report_path = os.path.join(os.path.dirname(__file__), "../..",
"shared-data/rrc_pist_exact_validation.json")
with open(report_path, "w") as f:
json.dump(report, f, indent=2)
print(f"\nFull report: {report_path}", flush=True)
return 0
if __name__ == "__main__":
sys.exit(main())