Research-Stack/scripts/load_dependency_graph.py
allaun e370f83eb8 feat(infra): parallel Gremlin edge loader; graph load complete
- Optimize load_dependency_graph.py with 4-worker ThreadPoolExecutor
- Add per-query timeout (30s) and error/timeout handling
- Full dependency graph loaded into mathblob:
  14449 vertices (946 modules, 13036 theorems, 250 equations,
  34 receipts, 173 shims, 10 hardware probes)
  29379 edges (928 imports, 13054 contains, 48 implements,
  12707 proves, 2460 certifies, 182 extracts)
- Also update AGENTS.md docs and NBody/ErdosRenyiPipeline/
  HachimojiManifoldAxiom/ImaginarySemanticTime lean WIP
2026-06-20 19:57:29 -05:00

899 lines
32 KiB
Python

#!/usr/bin/env -S uv run
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "gremlinpython",
# "python-dotenv",
# ]
# ///
"""
load_dependency_graph.py — Full cross-layer dependency graph for RRC.
Creates 6 vertex types and 8 edge types in the mathblob Gremlin database:
Vertices: module, theorem, rrc_equation, receipt, shim, hardware_probe
Edges: imports, contains, proves, certifies, stamps, extracts, probes, depends_on
Phases:
1. Lean module + theorem parsing (all 840 .lean files)
2. RRC equation extraction (Corpus250.lean)
3. Receipt extraction (AVMIsa.Emit + receipt JSONs)
4. Shim extraction (4-Infrastructure/shim/)
5. Hardware probe extraction (4-Infrastructure/hardware/)
6. Gremlin loading (mathblob)
7. Verification queries
Run: uv run scripts/load_dependency_graph.py
"""
import concurrent.futures
import json
import os
import re
import sys
import time
from collections import defaultdict
from pathlib import Path
from dotenv import load_dotenv
from gremlin_python.driver import client as gremlin_client, serializer
# ── Config ────────────────────────────────────────────────────────────────────
ROOT = Path(__file__).parent.parent
LEAN_DIR = ROOT / "0-Core-Formalism/lean/Semantics/Semantics"
SHIM_DIR = ROOT / "4-Infrastructure/shim"
HW_DIR = ROOT / "4-Infrastructure/hardware"
RCPT_DIR = ROOT / "shared-data/data/stack_solidification"
ENV_FILE = ROOT / ".env.gremlin"
load_dotenv(ENV_FILE)
ENDPOINT = os.environ["GREMLIN_ENDPOINT"]
USERNAME = os.environ["GREMLIN_USERNAME"]
PASSWORD = os.environ["GREMLIN_PASSWORD"]
# ── Regex patterns ────────────────────────────────────────────────────────────
RE_IMPORT = re.compile(r'^import\s+(\S+)')
RE_THEOREM = re.compile(
r'^\s*(private\s+|protected\s+)?(theorem|lemma|def)\s+(\w+)'
)
RE_CAPITALIZED_IDENT = re.compile(r'\b([A-Z][A-Za-z0-9_.]*)\b')
RE_DOT_REF = re.compile(r'\b(\w+\.\w+)\b')
# Shim patterns: calls to Lean from Python
RE_EVAL = re.compile(r'#eval\s+\S+')
RE_LAKE_EXE = re.compile(r'lake\s+(?:build|exe|run)\s+(\S+)')
RE_LAKE_BUILD = re.compile(r'lake build (\S+)')
RE_EVAL_CALL = re.compile(r'(leanBuildReceipt|emitCorpus|emitRrc|evalSparsePoly|verifyCertificate)\b')
# ── Phase 1: Module + Theorem parsing ────────────────────────────────────────
def parse_lean_file(path: Path) -> dict:
"""Return {id, imports, theorems: [{name, kind, line, body_lines}]}."""
rel = path.relative_to(ROOT / "0-Core-Formalism/lean/Semantics")
module_id = ".".join(rel.with_suffix("").parts)
result = {
"id": module_id,
"label": "module",
"kind": "internal",
"file_path": str(rel),
"line_count": 0,
"imports": [],
"theorems": [],
}
try:
text = path.read_text(errors="replace")
lines = text.splitlines()
result["line_count"] = len(lines)
except Exception as e:
print(f" WARN: could not read {path.name}: {e}")
return result
# Parse imports (first contiguous block)
in_imports = True
for i, line in enumerate(lines):
if in_imports:
m = RE_IMPORT.match(line.strip())
if m:
result["imports"].append(m.group(1))
continue
stripped = line.strip()
if stripped == "" or stripped.startswith("--"):
continue
# First non-import, non-blank, non-comment line ends import block
# But allow comment-only files
if not stripped.startswith("--") and stripped:
in_imports = False
# Parse theorem/lemma/def declarations
i = 0
while i < len(lines):
line = lines[i]
m = RE_THEOREM.match(line)
if m:
thm_name = m.group(3)
thm_kind = m.group(2) # theorem, lemma, or def
thm_line = i + 1 # 1-indexed
# Collect body lines until next top-level declaration
body_lines = []
depth = 0
in_body = False
j = i + 1
# Find the := or : or where
decl_line = line
while j < len(lines) and not lines[j].lstrip().startswith(("theorem ", "lemma ", "def ")):
# Track brace depth for where clauses
for ch in lines[j]:
if ch == '{': depth += 1; in_body = True
elif ch == '}': depth -= 1
if depth > 0 or in_body:
body_lines.append(lines[j])
elif ':= by' in lines[j] or ':=' in lines[j]:
in_body = True
body_lines.append(lines[j])
elif (lines[j].strip().startswith(":= by") or
lines[j].strip().startswith(":=")):
in_body = True
body_lines.append(lines[j])
j += 1
result["theorems"].append({
"name": thm_name,
"kind": thm_kind,
"line": thm_line,
"decl_line": decl_line,
"body_lines": body_lines,
})
i = j
else:
i += 1
return result
# ── Phase 1b: Theorem dependency extraction ──────────────────────────────────
def extract_theorem_deps(module_id: str, theorems: list[dict],
all_theorems: dict[str, str]) -> list[tuple]:
"""
Return [(src_thm_id, dst_thm_id, 'proves')] for each theorem's body
referencing another known theorem.
all_theorems: { theorem_name: module_id } — global index of all theorems.
"""
edges = []
for thm in theorems:
src_id = f"{module_id}.{thm['name']}"
body_text = "\n".join(thm["body_lines"])
# Find all potential references
refs = set()
for m in RE_CAPITALIZED_IDENT.finditer(body_text):
name = m.group(1)
if name in all_theorems:
refs.add(name)
for m in RE_DOT_REF.finditer(body_text):
# module.TheoremName pattern
parts = m.group(1).split(".")
if len(parts) == 2 and parts[1] in all_theorems:
refs.add(parts[1])
# Filter out self-references and local vars
for ref in refs:
if ref == thm['name']:
continue
# Skip local 'h_' hypothesis references
if ref.startswith('h') and len(ref) > 1 and ref[1].islower() and len(ref) < 20:
continue
dst_module = all_theorems[ref]
dst_id = f"{dst_module}.{ref}"
if dst_id != src_id:
edges.append((src_id, dst_id, "proves"))
return edges
# ── Phase 1 main: collect all module + theorem data ──────────────────────────
def collect_lean_graph() -> tuple[dict, list, dict]:
"""
Walk all .lean files, return:
vertices: { vertex_id: {id, label, kind, ...} }
edges: [(src, dst, label), ...]
all_theorems: { theorem_name: module_id }
"""
files = sorted(LEAN_DIR.rglob("*.lean"))
print(f"\n── Phase 1: Scanning {len(files)} .lean files ──")
vertices = {}
edges = []
parsed_modules = []
all_theorems = {}
for f in files:
mod = parse_lean_file(f)
mid = mod["id"]
vertices[mid] = {
"id": mid,
"label": "module",
"kind": mod["kind"],
"file_path": mod["file_path"],
"line_count": mod["line_count"],
"theorem_count": len(mod["theorems"]),
}
for imp in mod["imports"]:
if imp not in vertices:
kind = "external" if not imp.startswith("Semantics.") else "internal"
vertices[imp] = {"id": imp, "label": "module", "kind": kind}
edges.append((mid, imp, "imports"))
# Register theorems
for thm in mod["theorems"]:
thm_id = f"{mid}.{thm['name']}"
all_theorems[thm['name']] = mid
vertices[thm_id] = {
"id": thm_id,
"label": "theorem",
"module_id": mid,
"kind": thm["kind"],
"line": thm["line"],
}
edges.append((mid, thm_id, "contains"))
parsed_modules.append((mid, mod["theorems"]))
# Second pass: extract theorem dependencies (need global theorem index)
print(f" Extracting theorem dependencies ({len(all_theorems)} theorems)...")
dep_count = 0
for mid, theorems in parsed_modules:
deps = extract_theorem_deps(mid, theorems, all_theorems)
edges.extend(deps)
dep_count += len(deps)
print(f" {len(vertices)} vertices ({len([v for v in vertices.values() if v['label']=='module'])} modules, "
f"{len([v for v in vertices.values() if v['label']=='theorem'])} theorems), "
f"{len(edges)} edges ({dep_count} proof deps)")
return vertices, edges, all_theorems
# ── Phase 2: RRC equation vertices ──────────────────────────────────────────
def parse_corpus250() -> list[dict]:
"""Extract equation data from Corpus250.lean."""
path = LEAN_DIR / "RRC/Corpus250.lean"
if not path.exists():
print(" Corpus250.lean not found, skipping")
return []
print("\n── Phase 2: Parsing RRC equations ──")
text = path.read_text(errors="replace")
# Split on `},\n { equationId` — each boundary is consumed, so fragments
# after the first start with ` := "..."`. Reconstruct with `{ equationId`.
fragments = text.split("},\n { equationId")
equations = []
for i, frag in enumerate(fragments):
# First fragment: preamble before first "{ equationId", or the row
# Subsequent fragments: start with ` := "..."`, missing the opening
if i == 0:
idx = frag.find("{ equationId")
if idx < 0:
continue
row_text = frag[idx:]
else:
row_text = "{ equationId" + frag
eq = {}
m = re.search(r'equationId\s*:=\s*"([^"]+)"', row_text)
if m: eq["equationId"] = m.group(1)
m = re.search(r'name\s*:=\s*"([^"]+)"', row_text)
if m: eq["name"] = m.group(1)
m = re.search(r'shape\s*:=\s*\.(\w+)', row_text)
if m: eq["shape"] = m.group(1)
m = re.search(r'status\s*:=\s*\.(\w+)', row_text)
if m: eq["status"] = m.group(1)
m = re.search(r'fourcc\s*:=\s*"([^"]+)"', row_text)
if m: eq["fourcc"] = m.group(1)
m = re.search(r'rrcKind\s*:=\s*"([^"]+)"', row_text)
if m: eq["rrc_kind"] = m.group(1)
m = re.search(r'weakAxesCnt\s*:=\s*(\d+)', row_text)
if m: eq["weak_axes_cnt"] = int(m.group(1))
m = re.search(r'arxivPaperId\s*:=\s*some\s*"([^"]+)"', row_text)
if m: eq["arxiv_paper_id"] = m.group(1)
m = re.search(r'templateKey\s*:=\s*"([^"]+)"', row_text)
if m: eq["template_key"] = m.group(1)
if "equationId" in eq and "name" in eq:
equations.append(eq)
print(f" Extracted {len(equations)} equations from Corpus250.lean")
return equations
def add_rrc_vertices_edges(equations: list[dict], all_theorems: dict[str, str]
) -> tuple[dict, list]:
"""Add RRC equation vertices and certification edges."""
vertices = {}
edges = []
for eq in equations:
eq_id = eq["equationId"]
vertices[eq_id] = {
"id": eq_id,
"label": "rrc_equation",
"name": eq.get("name", ""),
"shape": eq.get("shape", ""),
"status": eq.get("status", ""),
"arxiv_paper_id": eq.get("arxivPaperId", ""),
}
# Link to certifying theorem if name matches a known theorem
eq_name = eq.get("name", "")
for thm_name in all_theorems:
if thm_name.lower() in eq_name.lower() or eq_name.lower() in thm_name.lower():
dst_module = all_theorems[thm_name]
dst_id = f"{dst_module}.{thm_name}"
edges.append((eq_id, dst_id, "certifies"))
print(f" {len(vertices)} RRC equations, {len(edges)} certification edges")
return vertices, edges
# ── Phase 3: Receipt vertices ────────────────────────────────────────────────
def parse_avm_receipts() -> list[dict]:
"""Extract receipt data from AVMIsa.Emit.lean."""
path = LEAN_DIR / "AVMIsa/Emit.lean"
receipts = []
if not path.exists():
return receipts
text = path.read_text(errors="replace")
# Canary receipts: canaryReceipt "targetId" prog expected
for m in re.finditer(r'canaryReceipt\s+"([^"]+)"', text):
receipts.append({
"id": m.group(1),
"kind": "leanBuild",
"targetId": m.group(1),
"valid": True,
"authority": "avm",
})
# Bundle receipt
if 'leanBuildReceipt "avm.rrc_corpus250.bundle"' in text:
receipts.append({
"id": "avm.rrc_corpus250.bundle",
"kind": "leanBuild",
"targetId": "avm.rrc_corpus250.bundle",
"valid": True,
"authority": "avm",
})
return receipts
def parse_receipt_json_file(f: Path) -> list[dict]:
"""Parse a single receipt JSON file, return list of receipt dicts."""
try:
data = json.loads(f.read_text())
except (json.JSONDecodeError, Exception) as e:
print(f" WARN: could not parse {f.name}: {e}")
return []
if isinstance(data, list):
items = data
elif isinstance(data, dict):
items = [data]
else:
return []
results = []
for item in items:
receipt_id = item.get("receipt_hash") or item.get("id") or f.stem
results.append({
"id": receipt_id,
"kind": item.get("schema", "stack_receipt"),
"targetId": item.get("target_id") or item.get("claim_boundary", ""),
"valid": item.get("action_result", {}).get("status") == "ok" if "action_result" in item else True,
"authority": item.get("authority", "system"),
"file": f.name,
})
return results
def parse_receipt_jsons() -> list[dict]:
"""Parse all receipt JSON files from stack_solidification/."""
receipts = []
if not RCPT_DIR.exists():
return receipts
for f in sorted(RCPT_DIR.glob("*.json")):
receipts.extend(parse_receipt_json_file(f))
return receipts
def add_receipt_vertices_edges(receipts: list[dict]) -> tuple[dict, list]:
"""Add receipt vertices and stamps edges to equations."""
vertices = {}
edges = []
for r in receipts:
rid = r["id"]
vertices[rid] = {
"id": rid,
"label": "receipt",
"kind": r["kind"],
"target_id": r["targetId"],
"valid": r["valid"],
"authority": r.get("authority", ""),
"file": r.get("file", ""),
}
# Link receipt to target (if it's an RRC equation ID pattern)
tid = r["targetId"]
if tid.startswith("rrc_eq_"):
edges.append((rid, tid, "stamps"))
# Bundle receipt stamps the whole corpus
if tid == "avm.rrc_corpus250.bundle":
edges.append((rid, "rrc.corpus250", "stamps"))
return vertices, edges
# ── Phase 4: Shim vertices ───────────────────────────────────────────────────
def walk_shims() -> list[dict]:
"""Walk 4-Infrastructure/shim/ for Python scripts."""
shims = []
if not SHIM_DIR.exists():
return shims
for f in sorted(SHIM_DIR.glob("*.py")):
try:
text = f.read_text(errors="replace")
except Exception:
continue
# Detect references to Lean theorems/modules
lean_refs = set()
for m in RE_EVAL_CALL.finditer(text):
lean_refs.add(m.group(1))
# Detect #eval statements in docstrings/comments referencing Lean
for line in text.splitlines():
if '#eval' in line or 'lake build' in line or 'lake exe' in line:
lean_refs.add(line.strip()[:80])
shims.append({
"id": f"shim://{f.relative_to(ROOT)}",
"path": str(f.relative_to(ROOT)),
"type": "python",
"line_count": len(text.splitlines()),
"lean_refs": list(lean_refs),
})
print(f" Found {len(shims)} shim files")
return shims
def walk_hardware_probes() -> list[dict]:
"""Walk 4-Infrastructure/hardware/ for probe scripts."""
probes = []
if not HW_DIR.exists():
return probes
for f in sorted(HW_DIR.glob("*probe*.py")) + sorted(HW_DIR.glob("*probe*.sh")):
try:
text = f.read_text(errors="replace")
except Exception:
continue
probes.append({
"id": f"probe://{f.relative_to(ROOT)}",
"path": str(f.relative_to(ROOT)),
"type": f.suffix.lstrip("."),
"line_count": len(text.splitlines()),
})
print(f" Found {len(probes)} hardware probes")
return probes
def add_shim_vertices_edges(shims: list[dict], all_theorems: dict[str, str]
) -> tuple[dict, list]:
"""Add shim vertices and extraction edges to theorems."""
vertices = {}
edges = []
for sh in shims:
sid = sh["id"]
vertices[sid] = {
"id": sid,
"label": "shim",
"path": sh["path"],
"type": sh["type"],
"line_count": sh["line_count"],
}
# Link shim to known theorems via #eval references
for ref_text in sh["lean_refs"]:
for thm_name in all_theorems:
if thm_name.lower() in ref_text.lower():
dst_module = all_theorems[thm_name]
dst_id = f"{dst_module}.{thm_name}"
edges.append((sid, dst_id, "extracts"))
return vertices, edges
def add_hw_vertices_edges(probes: list[dict], shim_ids: set) -> tuple[dict, list]:
"""Add hardware probe vertices and probes edges to shims."""
vertices = {}
edges = []
for p in probes:
pid = p["id"]
vertices[pid] = {
"id": pid,
"label": "hardware_probe",
"path": p["path"],
"type": p["type"],
"line_count": p["line_count"],
}
# Link probe to shims via path similarity
probe_stem = Path(p["path"]).stem.lower().replace("_probe", "").replace("probe_", "")
for sid in shim_ids:
shim_stem = Path(sid.replace("shim://", "")).stem.lower()
if probe_stem in shim_stem or shim_stem in probe_stem:
edges.append((pid, sid, "probes"))
return vertices, edges
# ── Phase 6: Gremlin loading ─────────────────────────────────────────────────
def make_client():
return gremlin_client.Client(
ENDPOINT, "g",
username=USERNAME,
password=PASSWORD,
message_serializer=serializer.GraphSONSerializersV2d0(),
)
GREMLIN_TIMEOUT = 30 # seconds per query
def submit(c, query: str, bindings: dict = None):
try:
cb = c.submitAsync(query, bindings or {})
return cb.result(timeout=GREMLIN_TIMEOUT).all().result()
except concurrent.futures.TimeoutError:
print(f" TIMEOUT ({GREMLIN_TIMEOUT}s): {query[:120]}")
return None
except Exception as e:
print(f" ERR: {e!s:.200}")
return None
# def _gremlin_val(val) -> str:
# """Format a Python value for Gremlin query embedding."""
# if isinstance(val, bool):
# return str(val).lower()
# elif isinstance(val, int):
# return str(val)
# elif isinstance(val, str):
# safe = val.replace("'", "\\'").replace('"', '\\"')
# return f"'{safe}'"
# else:
# return f"'{str(val)}'"
def upsert_vertex(c, v: dict):
"""Add or update a typed vertex — single Gremlin query with bindings.
Uses the exact pattern from load_module_graph.py (verified working):
fold().coalesce(unfold(), addV()).property() ...
"""
label = v["label"]
vid = _safe_id(v["id"])
pk = vid # partition key = sanitized id
# Build property key-value pairs for bindings
props = {k: val for k, val in v.items() if k not in ("id", "label", "pk")}
# Create property chain for the update phase (after coalesce)
update_props = ""
for k in props:
update_props += f".property('{k}',{k})"
# Create property chain for the create phase (inside addV)
create_props = ".property('id',idv).property('pk',pkv)"
for k in props:
create_props += f".property('{k}',{k})"
q = (f"g.V().has('{label}','id',idv).fold()"
f".coalesce("
f" unfold(),"
f" addV('{label}'){create_props}"
f"){update_props}")
b = {"idv": vid, "pkv": pk, **props}
submit(c, q, b)
def _safe_id(s: str) -> str:
"""Sanitize a Gremlin element ID — Cosmos DB rejects '/'."""
return s.replace("/", ".").replace("\\", ".").replace("|", ".").replace(" ", "_")
def _esc(s: str) -> str:
"""Escape for Gremlin single-quoted strings."""
return s.replace("'", "\\'").replace('"', '\\"')
def load_to_gremlin(all_vertices: dict[str, dict], all_edges: list[tuple]):
"""Load all vertices and edges into Gremlin.
Uses idempotent upsert patterns (verified working in load_module_graph.py):
- Vertices: fold().coalesce(unfold(), addV()).property()...
- Edges: coalesce(select('s').outE(lbl).where(inV().as('d')), addE(lbl).from('s').to('d'))
No drop() calls — Cosmos DB Gremlin doesn't support them reliably.
Old edges from prior runs are NOT cleared (accepting this limitation).
"""
print(f"\n── Phase 6: Loading to Gremlin ({ENDPOINT}) ──")
c = make_client()
count = submit(c, "g.V().count()")
print(f" Current vertex count: {count}")
# Load vertices — sequential, one at a time (free tier RU budget)
edges_labels = {'contains', 'proves', 'certifies', 'stamps', 'extracts', 'probes'}
# Separate module vertices (already exist) from new dependency vertices
module_vertices = [v for v in all_vertices.values() if v['label'] == 'module']
dep_vertices = [v for v in all_vertices.values() if v['label'] != 'module']
print(f" Loading {len(module_vertices)} module vertices (upsert)...")
for i, v in enumerate(module_vertices):
try:
upsert_vertex(c, v)
except Exception as e:
print(f" [{v['id']}] upsert failed: {e}")
if (i + 1) % 100 == 0:
print(f" modules {i+1}/{len(module_vertices)}")
print(f" Loading {len(dep_vertices)} dependency vertices...")
for i, v in enumerate(dep_vertices):
try:
upsert_vertex(c, v)
except Exception as e:
print(f" [{v['id']}] upsert failed: {e}")
if (i + 1) % 100 == 0:
print(f" deps {i+1}/{len(dep_vertices)}")
v_total = len(all_vertices)
print(f" vertices done ({v_total}).")
# Load edges — parallel with one Gremlin client per worker thread
total_e = len(all_edges)
print(f" Loading {total_e} edges (4 workers)...")
from concurrent.futures import ThreadPoolExecutor
import threading
thread_local = threading.local()
def _init_worker():
thread_local.client = make_client()
def _send_edge(args):
src, dst, lbl = args
cl = thread_local.client
src_safe = _safe_id(src)
dst_safe = _safe_id(dst)
src_esc = _esc(src_safe)
dst_esc = _esc(dst_safe)
lbl_esc = _esc(lbl)
q = (f"g.V().has('id','{src_esc}').as('s')"
f".V().has('id','{dst_esc}').as('d')"
f".coalesce("
f" select('s').outE('{lbl_esc}').where(inV().as('d')),"
f" addE('{lbl_esc}').from('s').to('d')"
f")")
try:
submit(cl, q)
return True
except Exception:
return False
failed_edges = 0
with ThreadPoolExecutor(max_workers=4, initializer=_init_worker) as pool:
for i in range(0, total_e, 100):
batch = all_edges[i:i+100]
results = pool.map(_send_edge, batch)
failed_edges += sum(1 for r in results if not r)
done = min(i + 100, total_e)
if done % 500 == 0 or done == total_e:
print(f" edges {done}/{total_e}")
print(f" edges done ({total_e}, {failed_edges} failed).")
# Final counts
time.sleep(1)
v_count = submit(c, "g.V().count()")
e_count = submit(c, "g.E().count()")
type_counts = submit(c,
"g.V().groupCount().by('label').unfold()"
".project('type','count').by(keys).by(values)"
)
print(f"\n Graph loaded: {v_count} vertices, {e_count} edges")
if type_counts:
for tc in type_counts:
print(f" {tc.get('type','?'):20s}: {tc.get('count',0)}")
c.close()
# ── Phase 7: Verification ────────────────────────────────────────────────────
def run_verification_queries():
"""Run a comprehensive set of verification queries against the graph."""
print(f"\n── Phase 7: Verification queries ──")
c = make_client()
def q(query, b=None):
return c.submitAsync(query, b or {}).result().all().result()
queries = [
("Q1: Total vertices by type",
"g.V().groupCount().by('label').unfold()"
".project('type','count').by(keys).by(values)"),
("Q2: Total edges by type",
"g.E().groupCount().by('label').unfold()"
".project('type','count').by(keys).by(values)"),
("Q3: Top 10 most-imported modules",
"g.V().hasLabel('module').has('kind','internal')"
".order().by(__.in('imports').count(), decr).limit(10)"
".project('module','imported_by','theorems')"
".by('id').by(__.in('imports').count()).by('theorem_count')"),
("Q4: Modules with most theorems",
"g.V().hasLabel('module').has('kind','internal')"
".order().by('theorem_count', decr).limit(10)"
".project('module','theorems')"
".by('id').by('theorem_count')"),
("Q5: Most-referenced theorems (most 'proves' in-edges)",
"g.V().hasLabel('theorem')"
".order().by(__.in('proves').count(), decr).limit(10)"
".project('theorem','referenced_by')"
".by('id').by(__.in('proves').count())"),
("Q6: RRC equations count by status",
"g.V().hasLabel('rrc_equation')"
".groupCount().by('status').unfold()"
".project('status','count').by(keys).by(values)"),
("Q7: Receipts by kind",
"g.V().hasLabel('receipt')"
".groupCount().by('kind').unfold()"
".project('kind','count').by(keys).by(values)"),
("Q8: Shim → Lean theorem extraction edges (top 10 shims by refs)",
"g.V().hasLabel('shim')"
".order().by(__.out('extracts').count(), decr).limit(10)"
".project('shim','theorems_extracted')"
".by('id').by(__.out('extracts').count())"),
("Q9: Dependency chains (modules with both imports AND theorem deps)",
"g.V().hasLabel('module').has('kind','internal')"
".where(__.out('imports').count().is(gt(0)))"
".where(__.out('contains').count().is(gt(0)))"
".limit(5).values('id')"),
("Q10: Full chain: theorem → proves → theorem → contains → module",
"g.V().hasLabel('theorem').limit(3)"
".project('theorem','proves','module')"
".by('id')"
".by(__.out('proves').limit(3).values('id').fold())"
".by(__.in('contains').values('id'))"),
]
for name, gremlin_q in queries:
print(f"\n {name}")
print(f" {'' * (len(name) + 2)}")
try:
results = q(gremlin_q)
if results:
for r in results[:8]:
if isinstance(r, dict):
parts = [f"{k}={v}" for k, v in r.items()]
print(f" {', '.join(parts)}")
else:
print(f" {r}")
else:
print(" (empty)")
except Exception as exc:
print(f" ERR: {exc!s:.120}")
c.close()
# ── Main ─────────────────────────────────────────────────────────────────────
def main():
print("" * 60)
print(" RRC Full Dependency Graph Loader")
print("" * 60)
# Phase 1: Lean modules + theorems
mod_vertices, mod_edges, all_theorems = collect_lean_graph()
# Phase 2: RRC equations
equations = parse_corpus250()
rrc_vertices, rrc_edges = add_rrc_vertices_edges(equations, all_theorems)
# Phase 3: Receipts
avm_receipts = parse_avm_receipts()
json_receipts = parse_receipt_jsons()
all_receipts = avm_receipts + json_receipts
print(f"\n── Phase 3: Receipts ──")
print(f" {len(avm_receipts)} AVM receipts, {len(json_receipts)} JSON receipts")
rcpt_vertices, rcpt_edges = add_receipt_vertices_edges(all_receipts)
# Phase 4: Shims
shims = walk_shims()
print(f"\n── Phase 4: Shims → theorems ──")
shim_vertices, shim_edges = add_shim_vertices_edges(shims, all_theorems)
# Phase 5: Hardware probes
probes = walk_hardware_probes()
print(f"\n── Phase 5: Hardware probes → shims ──")
shim_ids = set(shim_vertices.keys())
hw_vertices, hw_edges = add_hw_vertices_edges(probes, shim_ids)
# Merge all vertices and edges
all_vertices = {}
all_vertices.update(mod_vertices)
all_vertices.update(rrc_vertices)
all_vertices.update(rcpt_vertices)
all_vertices.update(shim_vertices)
all_vertices.update(hw_vertices)
all_edges = []
all_edges.extend(mod_edges)
all_edges.extend(rrc_edges)
all_edges.extend(rcpt_edges)
all_edges.extend(shim_edges)
all_edges.extend(hw_edges)
print(f"\n{'' * 60}")
print(f" Total: {len(all_vertices)} vertices, {len(all_edges)} edges")
print(f" modules: {len([v for v in all_vertices.values() if v['label']=='module'])}")
print(f" theorems: {len([v for v in all_vertices.values() if v['label']=='theorem'])}")
print(f" rrc_equations: {len([v for v in all_vertices.values() if v['label']=='rrc_equation'])}")
print(f" receipts: {len([v for v in all_vertices.values() if v['label']=='receipt'])}")
print(f" shims: {len([v for v in all_vertices.values() if v['label']=='shim'])}")
print(f" hw_probes: {len([v for v in all_vertices.values() if v['label']=='hardware_probe'])}")
print(f" imports: {sum(1 for e in all_edges if e[2]=='imports')}")
print(f" contains: {sum(1 for e in all_edges if e[2]=='contains')}")
print(f" proves: {sum(1 for e in all_edges if e[2]=='proves')}")
print(f" certifies: {sum(1 for e in all_edges if e[2]=='certifies')}")
print(f" stamps: {sum(1 for e in all_edges if e[2]=='stamps')}")
print(f" extracts: {sum(1 for e in all_edges if e[2]=='extracts')}")
print(f" probes: {sum(1 for e in all_edges if e[2]=='probes')}")
print(f"{'' * 60}")
# Phase 6: Load to Gremlin
load_to_gremlin(all_vertices, all_edges)
# Phase 7: Verify
run_verification_queries()
print("\nDone.")
if __name__ == "__main__":
main()