Research-Stack/4-Infrastructure/shim/rrc_refactor_oracle.py

1069 lines
41 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
rrc_refactor_oracle.py — Chaos-game-driven RRC self-refactoring oracle.
Uses the Burgers representation chaos game engine to drive refactoring
decisions on the RRC domain manifold graph.
Loop per iteration:
1. Read current manifold graph (354 nodes, 33 edges)
2. Build adjacency matrix from graph edges
3. Run BurgersChaosGame quantum walk (eigenvector centrality)
4. Compute centrality deltas from previous iteration
5. Generate refactoring commands:
- LOW centrality → PRUNE (dead-end representation)
- HIGH centrality delta → PROMOTE (split into sub-specializations)
- SIMILAR centrality + strong edge → MERGE (redundant connection)
- LOW internal edge density → SPLIT cluster
6. Apply commands → new manifold graph (sacrificial copy)
7. Emit receipt with delta summary
8. Goto 1
"""
from __future__ import annotations
import argparse
import copy
import hashlib
import json
import math
import sys
import time
from collections import defaultdict
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Optional
import numpy as np
SHIM = Path(__file__).resolve().parent
sys.path.insert(0, str(SHIM))
from burgers_chaos_game import BurgersChaosGame # quantum walk engine
PRUNE_CENTRALITY_THRESHOLD = 0.01 # nodes below this get pruned
PROMOTE_DELTA_THRESHOLD = 0.05 # centrality delta above this gets promoted
MERGE_EDGE_SIMILARITY = 0.15 # centrality diff below this + edge = merge
CLUSTER_DENSITY_THRESHOLD = 0.1 # cluster density below this = split target
MAX_ITERATIONS = 10 # safety limit
MAX_MERGES_PER_ITER = 10 # optimal from SLO sweep (max speedup before community collapse)
MINIMUM_EDGE_DENSITY = 0.005 # if graph is sparser, trigger inference fallback
GRAPH_BUILDER = SHIM / "rrc_domain_manifold_graph.py"
MANIFOLD_ASSIGNMENT = SHIM.parent.parent / "shared-data/data/rrc_manifold_assignment_v1.json"
# Greek epigenetic state → PRUNE/MERGE preference
# Higher protect_level = less likely to be pruned or merged away
GREEK_PROTECT: dict[str, int] = {
"Φ": 5, # Stable — never prune, prefer as merge target
"Λ": 4, # Attractor — rarely prune
"Κ": 3, # Poised — prune only if centrality is extremely low
"Ρ": 3, # Regulated — same as Κ
"Σ": 2, # Symmetric — merge with caution
"Π": 2, # Potential — merge with caution
"Ω": 1, # Terminal — prune freely
"Ζ": 0, # Boundary — prune first
}
GREEK_COMPATIBLE: dict[str, list[str]] = {
"Φ": ["Λ", "Κ", "Σ"],
"Λ": ["Φ", "Ρ", "Π"],
"Κ": ["Φ", "Ω", "Ζ"],
"Ρ": ["Λ", "Ω", "Π"],
"Ω": ["Κ", "Ρ", "Ζ"],
"Σ": ["Φ", "Π", "Ζ"],
"Π": ["Λ", "Ρ", "Σ"],
"Ζ": ["Κ", "Ω", "Σ"],
}
# Route → keywords for graph node Greek annotation (same as rrc_manifold_assign.py)
ROUTE_GREEK_KEYWORDS: list[tuple[str, list[str], str, int, str, str]] = [
("thermodynamic_energy", [
"energy", "entropy", "heat", "carnot", "landauer", "temperature",
"thermodynamic", "thermal", "dissipation", "efficiency", "joule",
], "Φ", 0, "ambidextrous", "forward"),
("geometry_topology", [
"geodesic", "metric", "stereographic", "euclidean", "manifold",
"curvature", "riemann", "tensor", "topology", "holonomy",
"connection", "bundle", "chart", "topological", "topology",
], "Λ", 45, "left", "forward"),
("cognitive_load", [
"cognitive", "load", "emotional", "signal", "attention",
"salience", "novelty", "surprise", "gate",
], "Κ", 135, "left", "forward"),
("compression_route", [
"compress", "hutter", "encoding", "codec",
"bit", "rate", "distortion", "redundancy",
], "Σ", 225, "right", "reverse"),
("magnetic_signal", [
"magnetic", "magneto", "field", "wave", "plasma",
"flux", "induction", "mhd", "alfven",
], "Π", 270, "right", "reverse"),
("control_signal", [
"control", "gate", "overflow", "gain", "tuning",
"cascade", "feedback", "regulator", "threshold",
], "Ρ", 90, "ambidextrous", "forward"),
("chaotic_couch", [
"chaotic", "couch", "soliton", "turbulence", "vortex",
"strange", "attractor", "lyapunov",
], "Ω", 180, "ambidextrous", "reverse"),
("number_theory", [
"prime", "modulo", "congruence", "diophantine", "integer",
"arithmetic", "logarithm", "lower_bound", "bound", "number",
"pell", "exponential", "s-unit", "goormaghtigh",
], "Ζ", 315, "right", "reverse"),
]
# =========================================================================
def load_manifold_graph(path: Path) -> dict:
"""Load a domain_manifold_graph_v1 JSON."""
return json.loads(path.read_text())
def load_greek_assignment(path: Path | None = None) -> dict[str, dict]:
"""Load Greek epigenetic states from manifold assignment, keyed by equation name."""
if path is None:
path = MANIFOLD_ASSIGNMENT
if not path.exists():
print(f" Greek assignment not found at {path}, skipping enrichment",
file=sys.stderr)
return {}
data = json.loads(path.read_text())
greek_map: dict[str, dict] = {}
for eq in data.get("equations", []):
name = eq.get("name", "")
greek_map[name] = {
"greek": eq.get("greek_state", "Ζ"),
"phase": eq.get("greek_phase", 315),
"chirality": eq.get("greek_chirality", "right"),
"direction": eq.get("greek_direction", "reverse"),
"regime": eq.get("regime", ""),
"route": eq.get("route", ""),
}
print(f" Loaded {len(greek_map)} Greek states from assignment",
file=sys.stderr)
return greek_map
def enrich_graph_by_keywords(graph: dict) -> dict:
"""Annotate manifold graph nodes with Greek epigenetic state by keyword matching.
Uses the same route keyword patterns as rrc_manifold_assign.py but applied
at the graph-node level (domain category labels vs individual equation names).
Returns the graph with Greek state, phase, chirality, direction added to each node.
"""
for node in graph.get("nodes", []):
label = (node.get("label", "") + " " + node.get("id", "")).lower()
best_route = None
best_score = 0
best_greek = "Ζ"
best_phase = 315
best_chirality = "right"
best_direction = "reverse"
for route, keywords, greek, phase, chirality, direction in ROUTE_GREEK_KEYWORDS:
score = sum(1 for kw in keywords if kw.lower() in label)
if score > best_score:
best_score = score
best_route = route
best_greek = greek
best_phase = phase
best_chirality = chirality
best_direction = direction
node["greek_state"] = best_greek
node["greek_route"] = best_route or ""
node["greek_phase"] = best_phase
node["greek_chirality"] = best_chirality
node["greek_direction"] = best_direction
node["greek_match_score"] = best_score
return graph
def enrich_graph_with_greek(graph: dict, greek_map: dict[str, dict]) -> dict:
"""Annotate manifold graph nodes with Greek epigenetic state.
Two-phase strategy:
1. Try exact name/id match against the assignment equations (greek_map).
2. Fall back to keyword matching on graph node label + id.
"""
for node in graph.get("nodes", []):
label = node.get("label", "")
nid = node.get("id", "")
matched = greek_map.get(label) or greek_map.get(nid)
if matched is None:
for eq_name, gs in greek_map.items():
if eq_name.lower() in label.lower() or label.lower() in eq_name.lower():
matched = gs
break
if matched:
node["greek_state"] = matched["greek"]
node["greek_phase"] = matched["phase"]
node["greek_chirality"] = matched["chirality"]
node["greek_direction"] = matched["direction"]
node["greek_match_score"] = 10
continue
# Fallback: keyword matching at route level
label_lower = (label + " " + nid).lower()
best_route = None
best_score = 0
best_greek = "Ζ"
best_phase = 315
best_chirality = "right"
best_direction = "reverse"
for route, keywords, greek, phase, chirality, direction in ROUTE_GREEK_KEYWORDS:
score = sum(1 for kw in keywords if kw.lower() in label_lower)
if score > best_score:
best_score = score
best_route = route
best_greek = greek
best_phase = phase
best_chirality = chirality
best_direction = direction
node["greek_state"] = best_greek
node["greek_route"] = best_route or ""
node["greek_phase"] = best_phase
node["greek_chirality"] = best_chirality
node["greek_direction"] = best_direction
node["greek_match_score"] = best_score
return graph
def greek_spectrum(graph: dict) -> dict:
"""Compute Greek epigenetic state distribution across graph nodes."""
counts = defaultdict(int)
phase_counts = defaultdict(int)
chirality_counts = defaultdict(int)
direction_counts = defaultdict(int)
route_counts = defaultdict(int)
score_buckets = {"high": 0, "medium": 0, "low": 0, "none": 0}
for node in graph.get("nodes", []):
gs = node.get("greek_state", "Ζ")
counts[gs] += 1
phase_counts[node.get("greek_phase", 315)] += 1
chirality_counts[node.get("greek_chirality", "right")] += 1
direction_counts[node.get("greek_direction", "reverse")] += 1
route_counts[node.get("greek_route", "")] += 1
score = node.get("greek_match_score", 0)
if score >= 3:
score_buckets["high"] += 1
elif score >= 1:
score_buckets["medium"] += 1
elif score > 0:
score_buckets["low"] += 1
else:
score_buckets["none"] += 1
return {
"by_greek": dict(counts),
"by_phase": dict(phase_counts),
"by_chirality": dict(chirality_counts),
"by_direction": dict(direction_counts),
"by_route": dict(route_counts),
"match_quality": score_buckets,
}
def infer_edges_from_metadata(graph: dict) -> list[dict]:
"""Build edges from intrinsic node metadata without external access.
Covers all edge types that don't require live arXiv queries:
- kernel_internal: nodes sharing the same kernel
- kernel_hub: cross-kernel hub connections
- dimension_chain: adjacency along dimension axis
- shared_paper: shared paper IDs in node metadata (unverified)
- topic_overlap: token overlap in node labels
"""
nodes = graph.get("nodes", [])
edges = graph.get("edges", [])
existing_pairs = set()
for e in edges:
existing_pairs.add(tuple(sorted([e["source"], e["target"]])))
new_edges: list[dict] = []
added: set = set(existing_pairs)
def add(src: str, tgt: str, etype: str, **kw):
pair = tuple(sorted([src, tgt]))
if pair not in added:
added.add(pair)
new_edges.append({"source": src, "target": tgt, "type": etype, **kw})
# Group nodes by kernel
kernel_nodes: dict[str, list[dict]] = defaultdict(list)
for n in nodes:
kernel_nodes[n.get("kernel", "other")].append(n)
node_map = {n["id"]: n for n in nodes}
# Edge type 1: kernel_internal — 15% random within same kernel
import random
rng = random.Random(42)
for kernel, members in kernel_nodes.items():
if len(members) < 2:
continue
for i in range(len(members)):
for j in range(i + 1, len(members)):
if rng.random() < 0.15:
add(members[i]["id"], members[j]["id"],
"kernel_internal",
kernel=kernel,
dimension=members[i].get("dimension"))
# Edge type 2: kernel_hub — connect hubs (highest-degree node) across kernels
hubs: dict[str, str] = {}
for kernel, members in kernel_nodes.items():
hubs[kernel] = members[len(members) // 2]["id"] # deterministic hub
kernel_names = list(kernel_nodes.keys())
for i in range(len(kernel_names)):
for j in range(i + 1, len(kernel_names)):
add(hubs[kernel_names[i]], hubs[kernel_names[j]],
"kernel_hub",
from_kernel=kernel_names[i],
to_kernel=kernel_names[j])
# Edge type 3: dimension_chain — adjacent dimensions
dim_groups: dict[int, list[dict]] = defaultdict(list)
for n in nodes:
dim_groups[n.get("dimension", -1)].append(n)
for dim in sorted(dim_groups):
if dim + 1 in dim_groups:
a = dim_groups[dim][0]
b = dim_groups[dim + 1][0]
add(a["id"], b["id"], "dimension_chain",
from_dim=dim, to_dim=dim + 1)
# Edge type 4: shared_paper — unverified, from node metadata
paper_nodes: dict[str, list[str]] = defaultdict(list)
for n in nodes:
for pid in n.get("papers", []):
paper_nodes[pid].append(n["id"])
for pid, nids in paper_nodes.items():
for i in range(len(nids)):
for j in range(i + 1, len(nids)):
add(nids[i], nids[j], "shared_paper",
paper_id=pid, verified=False)
# Edge type 5: topic_overlap — label token overlap
for i in range(len(nodes)):
ni = nodes[i]
ni_tokens = set(ni.get("label", "").lower().split())
for j in range(i + 1, len(nodes)):
nj = nodes[j]
overlap = ni_tokens & set(nj.get("label", "").lower().split())
if len(overlap) >= 2:
add(ni["id"], nj["id"], "topic_overlap",
overlap_count=len(overlap),
shared_terms=list(overlap)[:5])
return new_edges
def build_or_load_graph(path: Path, skip_live: bool = False) -> tuple[dict, str]:
"""Load graph, ensuring minimum edge density.
Strategy:
1. Load graph from file
2. If density ≥ threshold: return as-is (origin: file)
3. If density < threshold and not skip_live: try live rebuild
4. If live rebuild fails or skip_live: apply intrinsic inference
Returns (graph, origin_string) where origin_string is one of:
"file" — loaded as-is, sufficient edges
"live" — rebuilt via external graph builder
"inferred" — fallback: edges built from node metadata
"""
graph = load_manifold_graph(path)
nodes = graph.get("nodes", [])
edges = graph.get("edges", [])
n = len(nodes)
density = (2 * len(edges)) / max(n * (n - 1), 1)
if density >= MINIMUM_EDGE_DENSITY:
return graph, "file"
print(f" Graph density {density:.6f} < threshold {MINIMUM_EDGE_DENSITY}",
file=sys.stderr)
# Try live rebuild
origin = "file"
if not skip_live and GRAPH_BUILDER.exists():
try:
print(f" Attempting live rebuild via {GRAPH_BUILDER.name}...",
file=sys.stderr)
import subprocess
r = subprocess.run(
[sys.executable, str(GRAPH_BUILDER)],
capture_output=True, text=True, timeout=120,
)
if r.returncode == 0 and path.exists():
graph = load_manifold_graph(path)
edges = graph.get("edges", [])
density = (2 * len(edges)) / max(n * (n - 1), 1)
if density >= MINIMUM_EDGE_DENSITY:
print(f" Live rebuild succeeded: {len(edges)} edges",
file=sys.stderr)
return graph, "live"
else:
print(f" Live rebuild produced {len(edges)} edges "
f"(density {density:.6f}), still too sparse",
file=sys.stderr)
else:
print(f" Live rebuild failed (rc={r.returncode}): "
f"{r.stderr.strip()[-200:]}", file=sys.stderr)
except (subprocess.TimeoutExpired, FileNotFoundError, OSError) as e:
print(f" Live rebuild exception: {e}", file=sys.stderr)
# Fallback: intrinsic inference
print(f" Falling back to intrinsic edge inference from metadata...",
file=sys.stderr)
new_edges = infer_edges_from_metadata(graph)
graph["edges"] = graph.get("edges", []) + new_edges
graph["stats"] = {
"total_nodes": len(nodes),
"total_edges": len(graph["edges"]),
"by_type": {t: sum(1 for e in graph["edges"] if e["type"] == t)
for t in set(e["type"] for e in graph["edges"])},
"inferred": True,
"inferred_edge_count": len(new_edges),
}
density = (2 * len(graph["edges"])) / max(len(nodes) * (len(nodes) - 1), 1)
print(f" Inference produced {len(new_edges)} new edges, "
f"density now {density:.6f}", file=sys.stderr)
return graph, "inferred"
def graph_to_adjacency(graph: dict) -> tuple[np.ndarray, list[str]]:
"""Convert domain manifold graph to adjacency matrix + node labels.
Nodes = unique node IDs from the graph.
Edges from the edge list.
Returns (N×N adjacency, [node_id_0, ..., node_id_{N-1}]).
"""
nodes = graph.get("nodes", [])
edges = graph.get("edges", [])
node_ids = [n["id"] for n in nodes]
id_to_idx = {nid: i for i, nid in enumerate(node_ids)}
N = len(node_ids)
A = np.zeros((N, N), dtype=np.float64)
for e in edges:
src = e.get("source", "")
tgt = e.get("target", "")
if src in id_to_idx and tgt in id_to_idx:
i, j = id_to_idx[src], id_to_idx[tgt]
A[i, j] = A[j, i] = 1.0
return A, node_ids
def graph_stats(graph: dict) -> dict:
"""Compute structural statistics of the manifold graph."""
nodes = graph.get("nodes", [])
edges = graph.get("edges", [])
# Count by kernel/dimension
kernel_counts: dict[str, int] = defaultdict(int)
dim_counts: dict[int, int] = defaultdict(int)
for n in nodes:
kernel_counts[n.get("kernel", "unknown")] += 1
dim_counts[n.get("dimension", -1)] += 1
edge_types: dict[str, int] = defaultdict(int)
for e in edges:
edge_types[e.get("type", "unknown")] += 1
return {
"num_nodes": len(nodes),
"num_edges": len(edges),
"density": (2 * len(edges)) / max(len(nodes) * (len(nodes) - 1), 1),
"kernel_counts": dict(kernel_counts),
"dimension_counts": dict(dim_counts),
"edge_type_counts": dict(edge_types),
}
# =========================================================================
# II. Refactoring Command Generator
# =========================================================================
def generate_refactoring_commands(
graph: dict,
centrality: np.ndarray,
node_ids: list[str],
prev_centrality: Optional[dict[str, float]] = None,
*,
greek_map: Optional[dict[str, dict]] = None,
prune_threshold: float = PRUNE_CENTRALITY_THRESHOLD,
promote_threshold: float = PROMOTE_DELTA_THRESHOLD,
merge_similarity: float = MERGE_EDGE_SIMILARITY,
max_merges: int = MAX_MERGES_PER_ITER,
) -> list[dict]:
"""Generate refactoring commands from centrality analysis.
When greek_map is provided, PRUNE/MERGE decisions are modulated by
Greek epigenetic state: stable states (Φ, Λ) are protected from
pruning; incompatible Greek states are deprioritized for merges.
Returns list of command dicts:
{ "action": "prune"|"promote"|"merge"|"split",
"reason": str, "nodes": [str, ...], "detail": Any }
"""
commands: list[dict] = []
nodes_list = graph.get("nodes", [])
node_lookup = {n["id"]: n for n in nodes_list}
# Build centrality map keyed by node ID for ID-based delta
cent_map: dict[str, float] = dict(zip(node_ids, map(float, centrality)))
prev_map: dict[str, float] = prev_centrality or {}
# --- PRUNE: nodes with very low centrality, modulated by Greek state ---
for i, nid in enumerate(node_ids):
node = node_lookup.get(nid, {})
gs = (greek_map or {}).get(nid, {}).get("greek") or node.get("greek_state", "Ζ")
protect = GREEK_PROTECT.get(gs, 0)
# Scale threshold: protected states need much lower centrality to be pruned
effective_threshold = prune_threshold * (1.0 / (1.0 + protect * 2))
if centrality[i] < effective_threshold:
commands.append({
"action": "prune",
"reason": (
f"centrality {centrality[i]:.4f} < effective threshold "
f"{effective_threshold:.4f} (greek={gs}, protect={protect})"
),
"nodes": [nid],
"detail": {
"label": node.get("label", nid),
"kernel": node.get("kernel", ""),
"centrality": float(centrality[i]),
"greek_state": gs,
"protect_level": protect,
},
})
# --- PROMOTE: nodes with rising centrality that are potential hubs ---
if prev_map:
for nid, cent in cent_map.items():
prev = prev_map.get(nid)
if prev is not None:
delta = cent - prev
if delta > promote_threshold:
node = node_lookup.get(nid, {})
commands.append({
"action": "promote",
"reason": f"centrality delta {delta:.4f} > threshold {promote_threshold}",
"nodes": [nid],
"detail": {
"label": node.get("label", nid),
"kernel": node.get("kernel", ""),
"centrality": cent,
"delta": round(delta, 6),
},
})
# --- MERGE: pairs with edge + similar centrality, modulated by Greek compatibility ---
adj, _ = graph_to_adjacency(graph)
merge_candidates: list[tuple[float, int, int]] = []
for i in range(len(node_ids)):
for j in range(i + 1, len(node_ids)):
if adj[i, j] > 0:
diff = abs(centrality[i] - centrality[j])
if diff < merge_similarity:
priority = centrality[i] * centrality[j]
# Boost priority for compatible Greek states
if greek_map is not None:
ni = node_lookup.get(node_ids[i], {})
nj = node_lookup.get(node_ids[j], {})
gs_i = (greek_map.get(node_ids[i], {}).get("greek")
or ni.get("greek_state", "Ζ"))
gs_j = (greek_map.get(node_ids[j], {}).get("greek")
or nj.get("greek_state", "Ζ"))
if gs_i in GREEK_COMPATIBLE.get(gs_j, []):
priority *= 1.5 # boost compatible merges
elif gs_i == gs_j:
priority *= 1.3 # same-state merges are safe
else:
priority *= 0.5 # incompatible states penalized
merge_candidates.append((priority, i, j))
# Rank by boosted centrality product and cap
merge_candidates.sort(reverse=True, key=lambda x: x[0])
for priority, i, j in merge_candidates[:max_merges]:
ni = node_lookup.get(node_ids[i], {})
nj = node_lookup.get(node_ids[j], {})
gs_i = ni.get("greek_state", "Ζ")
gs_j = nj.get("greek_state", "Ζ")
commands.append({
"action": "merge",
"reason": (
f"centrality prod {priority:.6f}, diff "
f"{abs(centrality[i] - centrality[j]):.4f}, "
f"greek={gs_i}×{gs_j}"
),
"nodes": [node_ids[i], node_ids[j]],
"detail": {
"labels": [ni.get("label", node_ids[i]),
nj.get("label", node_ids[j])],
"centralities": [float(centrality[i]),
float(centrality[j])],
"greek_states": [gs_i, gs_j],
"compatible": gs_i in GREEK_COMPATIBLE.get(gs_j, []),
},
})
return commands
# =========================================================================
# III. Refactoring Engine
# =========================================================================
def apply_refactoring(
graph: dict,
commands: list[dict],
dry_run: bool = True,
) -> dict:
"""Apply refactoring commands to produce a new graph.
In dry_run mode, only reports what would change.
In live mode, actually modifies the graph.
Returns the (possibly modified) graph and operation log.
"""
if dry_run:
return graph, commands # just report
new_graph = copy.deepcopy(graph)
nodes = new_graph.get("nodes", [])
edges = new_graph.get("edges", [])
removed_ids: set[str] = set()
operation_log: list[dict] = []
for cmd in commands:
action = cmd["action"]
if action == "prune":
for nid in cmd["nodes"]:
# Remove from node list
nodes[:] = [n for n in nodes if n["id"] != nid]
removed_ids.add(nid)
operation_log.append({
"action": "pruned",
"node_id": nid,
"reason": cmd["reason"],
})
# Remove edges incident to pruned nodes
edges[:] = [
e for e in edges
if e["source"] not in removed_ids
and e["target"] not in removed_ids
]
elif action == "merge":
# Keep the first node, remove the second
keep_id, remove_id = cmd["nodes"]
nodes[:] = [n for n in nodes if n["id"] != remove_id]
removed_ids.add(remove_id)
operation_log.append({
"action": "merged",
"kept": keep_id,
"removed": remove_id,
"reason": cmd["reason"],
})
# Reroute edges from removed to kept
for e in edges:
if e["source"] == remove_id:
e["source"] = keep_id
if e["target"] == remove_id:
e["target"] = keep_id
# Remove self-loops from reroute
edges[:] = [e for e in edges if e["source"] != e["target"]]
elif action == "promote":
for nid in cmd["nodes"]:
# Find the node
node = next((n for n in nodes if n["id"] == nid), None)
if node:
# Add a specialization suffix
new_id = f"{nid}__special"
new_node = copy.deepcopy(node)
new_node["id"] = new_id
new_node["label"] = node.get("label", "") + " (specialized)"
new_node["dimension"] = min(5, node.get("dimension", 0) + 1)
nodes.append(new_node)
operation_log.append({
"action": "promoted",
"original": nid,
"created": new_id,
"reason": cmd["reason"],
})
# Connect the new node back to the original
edges.append({
"source": nid,
"target": new_id,
"type": "specialization",
"promoted": True,
})
elif action == "split":
for nid in cmd["nodes"]:
node = next((n for n in nodes if n["id"] == nid), None)
if node:
split_a = f"{nid}__a"
split_b = f"{nid}__b"
for new_id in (split_a, split_b):
new_node = copy.deepcopy(node)
new_node["id"] = new_id
new_node["label"] = node.get("label", "") + (
" (A)" if new_id.endswith("__a") else " (B)"
)
nodes.append(new_node)
removed_ids.add(nid)
nodes[:] = [n for n in nodes if n["id"] != nid]
operation_log.append({
"action": "split",
"original": nid,
"created": [split_a, split_b],
"reason": cmd["reason"],
})
# Regenerate stats
new_edges = [e for e in edges if e["source"] not in removed_ids
and e["target"] not in removed_ids]
deduped = []
seen_pairs = set()
for e in new_edges:
pair = tuple(sorted([e["source"], e["target"]]))
if pair not in seen_pairs:
seen_pairs.add(pair)
deduped.append(e)
new_graph["edges"] = deduped
new_graph["stats"] = graph_stats(new_graph)
return new_graph, operation_log
# =========================================================================
# IV. Main Loop
# =========================================================================
def run_refactor_loop(
graph: dict,
max_iterations: int = MAX_ITERATIONS,
dry_run: bool = True,
*,
greek_map: Optional[dict[str, dict]] = None,
prune_threshold: float = PRUNE_CENTRALITY_THRESHOLD,
promote_threshold: float = PROMOTE_DELTA_THRESHOLD,
merge_similarity: float = MERGE_EDGE_SIMILARITY,
max_merges: int = MAX_MERGES_PER_ITER,
origin: str = "file",
) -> dict:
"""Run the chaos-game-driven refactoring loop.
Each iteration:
1. Build adjacency from current graph
2. Compute centrality via BurgersChaosGame
3. Compare with previous centrality
4. Generate commands
5. Apply commands
6. Check convergence: if no commands generated, stop
Returns full history as a receipt dict.
"""
iteration_history: list[dict] = []
current_graph = copy.deepcopy(graph)
prev_cent_map: dict[str, float] = {}
for iteration in range(max_iterations):
t0 = time.time()
# 1. Build adjacency
A, node_ids = graph_to_adjacency(current_graph)
n_nodes = A.shape[0]
if n_nodes == 0:
iteration_history.append({
"iteration": iteration,
"status": "empty_graph",
"runtime_s": round(time.time() - t0, 4),
})
break
# 2. Quantum walk centrality
game = BurgersChaosGame(A, node_ids)
centrality = game.eigenvector_centrality()
# Top 5 by centrality
ranked = game.rank_nodes(centrality)
top_5 = [(n, round(s, 6)) for n, s in ranked[:5]]
# 3. Generate commands
commands = generate_refactoring_commands(
current_graph, centrality, node_ids, prev_cent_map,
greek_map=greek_map,
prune_threshold=prune_threshold,
promote_threshold=promote_threshold,
merge_similarity=merge_similarity,
max_merges=max_merges,
)
n_prune = sum(1 for c in commands if c["action"] == "prune")
n_promote = sum(1 for c in commands if c["action"] == "promote")
n_merge = sum(1 for c in commands if c["action"] == "merge")
n_split = sum(1 for c in commands if c["action"] == "split")
iter_record = {
"iteration": iteration,
"runtime_s": round(time.time() - t0, 4),
"node_count": n_nodes,
"edge_count": len(current_graph.get("edges", [])),
"top_5_centrality": top_5,
"top_node": top_5[0] if top_5 else None,
"commands_generated": len(commands),
"command_breakdown": {
"prune": n_prune,
"promote": n_promote,
"merge": n_merge,
"split": n_split,
},
"preview_commands": [
{
"action": c["action"],
"nodes_preview": c["nodes"][:3],
"reason": c["reason"][:120],
}
for c in commands[:10] # first 10 for readability
],
}
iteration_history.append(iter_record)
# 4. Apply (or preview)
if not dry_run and commands:
new_graph, op_log = apply_refactoring(
current_graph, commands, dry_run=False,
)
current_graph = new_graph
iter_record["applied"] = len(op_log) if op_log else 0
# 5. Save current centrality for next iteration's delta
prev_cent_map = dict(zip(node_ids, map(float, centrality)))
# 6. Convergence
if not commands:
break
return {
"schema": "rrc_refactor_oracle_v1",
"claim_boundary": (
"chaos-game-quantum-walk-refactoring-oracle;"
"greek-epigenetic-enrichment"
),
"sacrificial_graph_source": "domain_manifold_graph_v1.json",
"graph_origin": origin,
"greek_spectrum": greek_spectrum(current_graph),
"parameters": {
"prune_centrality_threshold": PRUNE_CENTRALITY_THRESHOLD,
"promote_delta_threshold": PROMOTE_DELTA_THRESHOLD,
"merge_edge_similarity": MERGE_EDGE_SIMILARITY,
"max_iterations": max_iterations,
"max_merges_per_iter": max_merges,
"dry_run": dry_run,
},
"initial_stats": graph_stats(graph),
"iteration_history": iteration_history,
"final_stats": graph_stats(current_graph),
"summary": {
"total_iterations": len(iteration_history),
"total_commands": sum(
h["commands_generated"] for h in iteration_history
) if iteration_history else 0,
"converged": not iteration_history[-1]["commands_generated"]
if iteration_history else False,
"top_node_final": iteration_history[-1]["top_node"]
if iteration_history else None,
},
"final_graph": current_graph,
"computed_at": datetime.now(timezone.utc).isoformat(),
}
def main() -> int:
parser = argparse.ArgumentParser(
description="RRC Chaos-Game Refactoring Oracle"
)
parser.add_argument(
"--graph", "-g",
default="/tmp/rrc_sacrificial_manifold_v1.json",
help="Path to manifold graph JSON (default: sacrificial copy)",
)
parser.add_argument(
"--max-iterations", type=int, default=MAX_ITERATIONS,
)
parser.add_argument(
"--max-merges", type=int, default=MAX_MERGES_PER_ITER,
help="Max merges per iteration (default: %(default)s)",
)
parser.add_argument(
"--apply", action="store_true",
help="Actually apply refactoring (default: dry-run preview)",
)
parser.add_argument(
"--output", "-o", default=None,
help="Output receipt path",
)
parser.add_argument(
"--threshold-prune", type=float, default=PRUNE_CENTRALITY_THRESHOLD,
)
parser.add_argument(
"--threshold-promote", type=float, default=PROMOTE_DELTA_THRESHOLD,
)
parser.add_argument(
"--threshold-merge", type=float, default=MERGE_EDGE_SIMILARITY,
)
parser.add_argument(
"--no-live", action="store_true",
help="Skip live arxiv rebuild; force intrinsic fallback",
)
parser.add_argument(
"--save-graph", default=None,
help="Save final modified graph to this path (auto: input path if --apply)",
)
parser.add_argument(
"--greek-assignment", default=None,
help="Path to manifold assignment JSON with Greek states (default: shared-data auto-detect)",
)
args = parser.parse_args()
graph_path = Path(args.graph)
if not graph_path.exists():
print(f"ERROR: graph not found at {graph_path}", file=sys.stderr)
print("Run: cp <repo>/shared-data/data/domain_manifold_graph_v1.json "
"/tmp/rrc_sacrificial_manifold_v1.json", file=sys.stderr)
return 1
graph, origin = build_or_load_graph(graph_path, skip_live=args.no_live)
# Load Greek epigenetic states and enrich graph nodes
greek_path = Path(args.greek_assignment) if args.greek_assignment else None
greek_map = load_greek_assignment(greek_path)
if greek_map:
graph = enrich_graph_with_greek(graph, greek_map)
n_enriched = sum(1 for n in graph.get("nodes", [])
if n.get("greek_match_score", 0) >= 5)
else:
# Keyword-only enrichment when no assignment file is available
graph = enrich_graph_by_keywords(graph)
n_enriched = sum(1 for n in graph.get("nodes", [])
if n.get("greek_match_score", 0) >= 1)
greek_spec = greek_spectrum(graph)
n_high = greek_spec["match_quality"]["high"]
n_med = greek_spec["match_quality"]["medium"]
n_low = greek_spec["match_quality"]["low"]
n_none = greek_spec["match_quality"]["none"]
print(f" Greek enrichment: {n_enriched}/{len(graph.get('nodes', []))} "
f"nodes annotated (high={n_high}, med={n_med}, low={n_low}, none={n_none})",
file=sys.stderr)
print(f" Greek spectrum: {dict(greek_spec['by_greek'])}",
file=sys.stderr)
stats = graph_stats(graph)
print(f"RRC Refactoring Oracle — on sacrificial copy")
print(f" Origin: {origin}")
print(f" Initial: {stats['num_nodes']} nodes, {stats['num_edges']} edges, "
f"density {stats['density']:.6f}")
print(f" Dry run: {not args.apply}")
print(f" Max iterations: {args.max_iterations}")
print(f" Max merges/iter: {args.max_merges}")
print(f" Thresholds: prune={args.threshold_prune}, "
f"promote={args.threshold_promote}, "
f"merge={args.threshold_merge}")
if origin == "inferred":
print(f" Inferred edge count: "
f"{stats.get('edge_type_counts', {}).get('kernel_internal', 0)} "
f"kernel_internal, "
f"{stats.get('edge_type_counts', {}).get('shared_paper', 0)} "
f"shared_paper, "
f"{stats.get('edge_type_counts', {}).get('kernel_hub', 0)} "
f"kernel_hub, "
f"{stats.get('edge_type_counts', {}).get('dimension_chain', 0)} "
f"dimension_chain, "
f"{stats.get('edge_type_counts', {}).get('topic_overlap', 0)} "
f"topic_overlap")
print()
result = run_refactor_loop(
graph,
max_iterations=args.max_iterations,
dry_run=not args.apply,
greek_map=greek_map,
prune_threshold=args.threshold_prune,
promote_threshold=args.threshold_promote,
merge_similarity=args.threshold_merge,
max_merges=args.max_merges,
origin=origin,
)
# Print results
summary = result["summary"]
initial = result["initial_stats"]
final = result["final_stats"]
print(f"Refactoring Complete — {summary['total_iterations']} iterations")
print(f" Commands generated: {summary['total_commands']}")
print(f" Converged: {summary['converged']}")
print(f" Nodes: {initial['num_nodes']}{final['num_nodes']}")
print(f" Edges: {initial['num_edges']}{final['num_edges']}")
for h in result["iteration_history"]:
cmds = h["command_breakdown"]
top = h["top_node"]
print(
f" Iter {h['iteration']}: "
f"{h['node_count']} nodes, "
f"top={top[0] if top else '?'} ({top[1] if top else '?'}), "
f"commands: P{cmds['prune']}+M{cmds['merge']}"
f"+R{cmds['promote']}+S{cmds['split']}"
f" ({h['commands_generated']} total)"
)
# Save final graph if requested
if args.apply and args.save_graph is None:
args.save_graph = str(graph_path) # overwrite in-place by default
if args.save_graph and result.get("final_graph"):
save_path = Path(args.save_graph)
final_graph = result["final_graph"]
final_graph["stats"] = final_graph_stats = graph_stats(final_graph)
save_path.write_text(json.dumps(final_graph, indent=2, default=str))
print(f" Saved refactored graph to {save_path}")
# Update summary with actual final graph stats
result["final_stats"] = final_graph_stats
# Emit receipt
if args.output:
output_path = Path(args.output)
else:
output_path = SHIM / "rrc_refactor_oracle_receipt.json"
receipt = {k: v for k, v in result.items() if k != "final_graph"}
canonical = json.dumps(receipt, sort_keys=True, separators=(",", ":"))
receipt["receipt_sha256"] = hashlib.sha256(canonical.encode()).hexdigest()
output_path.write_text(json.dumps(receipt, indent=2, default=str))
print(f"\nReceipt: {output_path}")
print(f"SHA256: {receipt['receipt_sha256']}")
return 0
if __name__ == "__main__":
sys.exit(main())