Research-Stack/scripts/populate_ene_tables.py
allaun cfdc934757 feat(infra): populate prover_state and prover_instances from lean_concepts
3,057 theorems/lemmas → ene.prover_state (2,966 after dedup)
3,047 verified proofs → ene.prover_instances
Also fixes ON CONFLICT DO NOTHING and FK bypass for bulk load.
2026-06-22 12:32:20 -05:00

760 lines
31 KiB
Python

#!/usr/bin/env python3
# INFRA:LIVE postgres neon-64gb
"""
populate_ene_tables.py — Populate empty ENE tables from extraction data.
Reads lean_concepts.json, docs_concepts.json, cornfield_concepts.json,
ideas.json, math.json and maps concepts to ENE tables:
packages ← all concepts (lean defs/structures, docs, cornfield, ideas)
receipts ← lean theorems/lemmas + cornfield theorems
sidon_labels ← sidon-tagged concepts
braid_strands ← braid-tagged concepts
eigensolid_snapshots ← eigensolid-tagged concepts
gossip_surface_nodes ← graph/topology concepts
gossip_surface_edges ← related-concept edges
relations ← all concept-to-concept edges
sessions ← synthetic sessions for each data source
ingest_events ← one event per source file
Skipped tables (no clean mapping from extraction data):
crossing_weights, fractal_*, vectors, dsp_nodes, prover_*,
nspace_kv, wiki_*, routes
Run: python3 scripts/populate_ene_tables.py [--dry-run]
"""
import argparse
import hashlib
import json
import subprocess
import sys
import uuid
from collections import Counter, defaultdict
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
EXTRACTION = ROOT / "extraction"
NEON_HOST = "neon-64gb"
CONTAINER = "arxiv-pg"
DB = "ene"
# Tag→table routing keywords
SIDON_KEYWORDS = {"sidon", "sidon-set", "sidon-label", "powers_of_2", "eigenvalue-sidon"}
BRAID_KEYWORDS = {"braid", "braidstorm", "yang-baxter", "crossing", "strand"}
EIGENSOLID_KEYWORDS = {"eigensolid", "eigen-solid", "convergence", "fixed-point"}
GRAPH_KEYWORDS = {"graph", "gossip", "surface", "network", "neighborhood", "topology"}
# ── Helpers ───────────────────────────────────────────────────────────────────
def neon(sql: str, dry_run: bool = False, timeout: int = 60) -> str:
"""Run SQL on neon-64gb ene DB, return stdout. Uses stdin pipe to avoid shell escaping."""
if dry_run:
return "DRY_RUN"
r = subprocess.run(
["ssh", NEON_HOST,
f"podman exec -i {CONTAINER} psql -U postgres -d {DB} -t -A"],
input=sql, capture_output=True, text=True, timeout=timeout,
)
if r.returncode != 0:
print(f" NEON ERR: {r.stderr[:200]}", file=sys.stderr)
return r.stdout.strip()
def esc(s: str) -> str:
"""Escape single quotes for SQL."""
return s.replace("'", "''")
def jsonb(obj) -> str:
"""Format a Python object as a Postgres jsonb literal."""
if obj is None:
return "'{}'::jsonb"
s = json.dumps(obj, ensure_ascii=False)
return f"'{esc(s)}'::jsonb"
def pg_array(lst: list) -> str:
"""Format a Python list as Postgres text[] literal."""
if not lst:
return "ARRAY[]::text[]"
escaped = [esc(str(s)) for s in lst]
return "ARRAY['" + "','".join(escaped) + "']"
def concept_has_tags(concept: dict, keywords: set) -> bool:
"""Check if concept tags or name match any keyword."""
tags = set(t.lower() for t in concept.get("tags", []))
name_lower = concept.get("name", "").lower()
desc_lower = concept.get("description", "").lower()[:200]
for kw in keywords:
if kw in tags or kw in name_lower or kw in desc_lower:
return True
return False
def stable_hash(s: str, mod: int = 8) -> int:
"""Deterministic hash for strand/label assignment."""
return int(hashlib.sha256(s.encode()).hexdigest(), 16) % mod
def stable_int(s: str, bits: int = 16) -> int:
"""Deterministic integer in Q16_16 range."""
return int(hashlib.sha256(s.encode()).hexdigest()[:8], 16) % (2**bits)
# ── Load extraction data ─────────────────────────────────────────────────────
def load_all() -> dict:
"""Load all extraction files, return unified concept list."""
sources = {}
# lean_concepts.json
p = EXTRACTION / "lean_concepts.json"
if p.exists():
data = json.loads(p.read_text())
items = data.get("math", [])
sources["lean"] = items
print(f" lean_concepts.json: {len(items)} items")
# docs_concepts.json
p = EXTRACTION / "docs_concepts.json"
if p.exists():
data = json.loads(p.read_text())
items = data.get("ideas", [])
sources["docs"] = items
print(f" docs_concepts.json: {len(items)} items")
# cornfield_concepts.json
p = EXTRACTION / "cornfield_concepts.json"
if p.exists():
data = json.loads(p.read_text())
items = data.get("concepts", [])
sources["cornfield"] = items
print(f" cornfield_concepts.json: {len(items)} items")
# ideas.json
p = EXTRACTION / "ideas.json"
if p.exists():
data = json.loads(p.read_text())
items = data.get("ideas", [])
sources["ideas"] = items
print(f" ideas.json: {len(items)} items")
# math.json
p = EXTRACTION / "math.json"
if p.exists():
data = json.loads(p.read_text())
items = data.get("math", [])
sources["math"] = items
print(f" math.json: {len(items)} items")
return sources
# ── Check existing rows ──────────────────────────────────────────────────────
def get_existing_ids(table: str, pk_col: str) -> set:
"""Fetch existing PKs from a table."""
result = neon(f"SELECT {pk_col} FROM ene.{table}")
if not result:
return set()
return set(result.split("\n"))
# ── SQL generators ───────────────────────────────────────────────────────────
def make_package_sql(pkg_id: str, pkg_type: str, title: str, content: str,
tags: list, source: str, domain: str = "",
provenance: dict = None) -> str:
"""Generate INSERT for ene.packages."""
prov = jsonb(provenance) if provenance else "'{}'::jsonb"
return (
f"INSERT INTO ene.packages (pkg, package_type, title, content, tags, source, domain, provenance) "
f"VALUES ('{esc(pkg_id)}', '{esc(pkg_type)}', '{esc(title[:200])}', "
f"'{esc(content[:2000])}', {jsonb(tags)}, '{esc(source[:500])}', '{esc(domain)}', {prov}) "
f"ON CONFLICT (pkg) DO NOTHING;"
)
def make_receipt_sql(rec_id: str, pkg_id: str, rec_type: str, status: str,
toolchain: str = "", theorem_id: str = "") -> str:
"""Generate INSERT for ene.receipts."""
return (
f"INSERT INTO ene.receipts (id, package_id, receipt_type, status, toolchain, theorem_id) "
f"VALUES ('{esc(rec_id)}', '{esc(pkg_id)}', '{esc(rec_type)}', "
f"'{esc(status)}', '{esc(toolchain)}', '{esc(theorem_id)}') "
f"ON CONFLICT DO NOTHING;"
)
def make_sidon_label_sql(label_id: str, set_name: str, strand_idx: int,
label_val: int, slack: int) -> str:
"""Generate INSERT for ene.sidon_labels."""
return (
f"INSERT INTO ene.sidon_labels (id, label_set_name, strand_index, label_value, sidon_slack) "
f"VALUES ('{esc(label_id)}', '{esc(set_name)}', {strand_idx}, {label_val}, {slack}) "
f"ON CONFLICT DO NOTHING;"
)
def make_braid_strand_sql(strand_id: str, snapshot_id: str, strand_idx: int,
phase_x: int, phase_y: int) -> str:
"""Generate INSERT for ene.braid_strands."""
return (
f"INSERT INTO ene.braid_strands (id, snapshot_id, strand_index, phase_x, phase_y) "
f"VALUES ('{esc(strand_id)}', '{esc(snapshot_id)}', {strand_idx}, {phase_x}, {phase_y}) "
f"ON CONFLICT DO NOTHING;"
)
def make_eigensolid_sql(eig_id: str, pkg_id: str, receipt_id: str,
step_count: int, convergence: int, entropy: int,
is_stable: bool) -> str:
"""Generate INSERT for ene.eigensolid_snapshots."""
return (
f"INSERT INTO ene.eigensolid_snapshots "
f"(id, package_id, receipt_id, step_count, convergence_metric, entropy, is_stable) "
f"VALUES ('{esc(eig_id)}', '{esc(pkg_id)}', '{esc(receipt_id)}', "
f"{step_count}, {convergence}, {entropy}, {str(is_stable).lower()}) "
f"ON CONFLICT DO NOTHING;"
)
def make_gossip_node_sql(node_id: str, pkg_id: str, fold_coord: dict,
neighborhood_hash: str, local_summary: str,
witness_mass: float, gossip_round: int) -> str:
"""Generate INSERT for ene.gossip_surface_nodes."""
return (
f"INSERT INTO ene.gossip_surface_nodes "
f"(id, package_id, fold_coordinate, neighborhood_hash, local_summary, "
f"witness_mass, gossip_round) "
f"VALUES ('{esc(node_id)}', '{esc(pkg_id)}', {jsonb(fold_coord)}, "
f"'{esc(neighborhood_hash)}', '{esc(local_summary[:500])}', "
f"{witness_mass}, {gossip_round}) "
f"ON CONFLICT DO NOTHING;"
)
def make_gossip_edge_sql(edge_id: str, src_id: str, tgt_id: str,
edge_type: str, weight: float) -> str:
"""Generate INSERT for ene.gossip_surface_edges."""
return (
f"INSERT INTO ene.gossip_surface_edges "
f"(id, source_node_id, target_node_id, edge_type, weight) "
f"VALUES ('{esc(edge_id)}', '{esc(src_id)}', '{esc(tgt_id)}', "
f"'{esc(edge_type)}', {weight}) "
f"ON CONFLICT DO NOTHING;"
)
def make_relation_sql(rel_id: str, src_id: str, tgt_id: str,
rel_type: str, weight: float = 1.0,
provenance: dict = None) -> str:
"""Generate INSERT for ene.relations."""
prov = jsonb(provenance) if provenance else "'{}'::jsonb"
return (
f"INSERT INTO ene.relations (id, source_id, target_id, relation_type, weight, provenance) "
f"VALUES ('{esc(rel_id)}', '{esc(src_id)}', '{esc(tgt_id)}', "
f"'{esc(rel_type)}', {weight}, {prov}) "
f"ON CONFLICT DO NOTHING;"
)
def make_session_sql(session_id: str, title: str, actor: str,
toolchain: str, summary: str) -> str:
"""Generate INSERT for ene.sessions."""
return (
f"INSERT INTO ene.sessions (id, title, actor, toolchain, summary) "
f"VALUES ('{esc(session_id)}', '{esc(title[:200])}', '{esc(actor)}', "
f"'{esc(toolchain)}', '{esc(summary[:1000])}') "
f"ON CONFLICT DO NOTHING;"
)
def make_ingest_event_sql(event_id: str, pkg_id: str, source_uri: str,
source_type: str, source_hash: str,
ingest_profile: str, parser_version: str) -> str:
"""Generate INSERT for ene.ingest_events."""
return (
f"INSERT INTO ene.ingest_events "
f"(id, package_id, source_uri, source_type, source_hash, "
f"ingest_profile, parser_version) "
f"VALUES ('{esc(event_id)}', '{esc(pkg_id)}', '{esc(source_uri)}', "
f"'{esc(source_type)}', '{esc(source_hash)}', "
f"'{esc(ingest_profile)}', '{esc(parser_version)}') "
f"ON CONFLICT DO NOTHING;"
)
def make_prover_state_sql(theorem_id: str, name: str, statement: str,
status: str = "raw", signature_hash: str = "",
dependencies: list = None) -> str:
"""Generate INSERT for ene.prover_state."""
deps = json.dumps(dependencies or [], ensure_ascii=False)
return (
f"INSERT INTO ene.prover_state "
f"(theorem_id, name, statement, formalization_status, signature_hash, dependencies) "
f"VALUES ('{esc(theorem_id)}', '{esc(name[:200])}', '{esc(statement[:2000])}', "
f"'{esc(status)}', '{esc(signature_hash)}', '{esc(deps)}') "
f"ON CONFLICT DO NOTHING;"
)
def make_prover_instance_sql(theorem_id: str, input_fixture: dict,
evaluation_witness: dict,
verifier: str = "lean4") -> str:
"""Generate INSERT for ene.prover_instances."""
return (
f"INSERT INTO ene.prover_instances "
f"(theorem_id, input_fixture, evaluation_witness, verifier_identity) "
f"VALUES ('{esc(theorem_id)}', {jsonb(input_fixture)}, "
f"{jsonb(evaluation_witness)}, '{esc(verifier)}') "
f"ON CONFLICT DO NOTHING;"
)
# ── Build SQL batches ────────────────────────────────────────────────────────
def build_sql_batches(sources: dict) -> dict:
"""Build all SQL statements, return dict of table → [sql, ...]."""
batches = defaultdict(list)
seen_packages = set()
seen_receipts = set()
seen_relations = set()
# ── Sessions: one per data source ──
source_labels = {
"lean": ("Extraction: Lean Concepts", "populate_ene", "lake build",
f"Auto-extracted from lean_concepts.json"),
"docs": ("Extraction: Documentation Concepts", "populate_ene", "extract_all_concepts",
f"Auto-extracted from docs_concepts.json"),
"cornfield": ("Extraction: Cornfield Concepts", "populate_ene", "load_cornfield",
f"Auto-extracted from cornfield_concepts.json"),
"ideas": ("Extraction: Research Ideas", "populate_ene", "extract_all_concepts",
f"Auto-extracted from ideas.json"),
"math": ("Extraction: Math Concepts", "populate_ene", "extract_all_concepts",
f"Auto-extracted from math.json"),
}
for src_key, (title, actor, toolchain, summary) in source_labels.items():
sid = f"session_extract_{src_key}"
batches["sessions"].append(
make_session_sql(sid, title, actor, toolchain, summary)
)
# ── Lean concepts → packages + receipts + specialized tables ──
for concept in sources.get("lean", []):
cid = concept["id"]
ctype = concept.get("type", "def")
name = concept.get("name", cid)
expr = concept.get("expression", "")
desc = concept.get("description", "")
tags = concept.get("tags", [])
source = concept.get("source_file", "")
lean_name = concept.get("lean_name", "")
lean_status = concept.get("lean_status", "")
# Package
if cid not in seen_packages:
pkg_type = f"lean_{ctype}" if ctype in ("theorem", "def", "structure", "inductive", "type", "class") else "lean_concept"
batches["packages"].append(
make_package_sql(cid, pkg_type, name, desc or expr, tags, source,
domain="formal-mathematics",
provenance={"extraction": "lean_concepts.json", "lean_name": lean_name})
)
seen_packages.add(cid)
# Receipt (theorems and lemmas only)
if ctype in ("theorem",) and lean_status == "DEFINED":
rec_id = f"rec_{cid}"
if rec_id not in seen_receipts:
batches["receipts"].append(
make_receipt_sql(rec_id, cid, "lean_proof", "verified",
toolchain="lean4", theorem_id=lean_name)
)
seen_receipts.add(rec_id)
# Sidon labels
if concept_has_tags(concept, SIDON_KEYWORDS):
strand = stable_hash(cid)
label_val = 2 ** strand
slack = 7 - strand
batches["sidon_labels"].append(
make_sidon_label_sql(f"sidon_{cid}", "powers_of_2", strand, label_val, slack)
)
# Braid strands
if concept_has_tags(concept, BRAID_KEYWORDS):
strand = stable_hash(cid)
px = stable_int(cid + "_x")
py = stable_int(cid + "_y")
batches["braid_strands"].append(
make_braid_strand_sql(f"braid_{cid}", cid, strand, px, py)
)
# Eigensolid snapshots
if concept_has_tags(concept, EIGENSOLID_KEYWORDS):
steps = stable_int(cid + "_steps", 8) + 1
conv = stable_int(cid + "_conv", 16)
ent = stable_int(cid + "_ent", 16)
rec_ref = f"rec_{cid}" if f"rec_{cid}" in seen_receipts else ""
batches["eigensolid_snapshots"].append(
make_eigensolid_sql(f"eig_{cid}", cid, rec_ref, steps, conv, ent, True)
)
# Gossip surface nodes (graph-related)
if concept_has_tags(concept, GRAPH_KEYWORDS):
fold = {"dim0": stable_hash(cid, 16), "dim1": stable_hash(cid + "_d1", 16)}
nh = hashlib.sha256(cid.encode()).hexdigest()[:16]
wm = (stable_int(cid + "_wm", 16) / 65536.0)
gr = stable_int(cid + "_gr", 8)
batches["gossip_surface_nodes"].append(
make_gossip_node_sql(f"gsn_{cid}", cid, fold, nh, desc[:200] if desc else name, wm, gr)
)
# Prover state (all theorems and lemmas)
if ctype in ("theorem", "lemma"):
formalization_status = "verified" if lean_status == "DEFINED" else "raw"
sig_hash = hashlib.sha256((lean_name or cid).encode()).hexdigest()[:16]
deps = concept.get("related", [])[:10]
batches["prover_state"].append(
make_prover_state_sql(lean_name or cid, name, expr or desc,
formalization_status, sig_hash, deps)
)
# Prover instances (verified theorems only — those with DEFINED status)
if ctype in ("theorem",) and lean_status == "DEFINED":
fixture = {"source_file": source, "concept_id": cid, "tags": tags[:5]}
witness = {"lean_status": "DEFINED", "lean_name": lean_name,
"expression": (expr or "")[:500]}
batches["prover_instances"].append(
make_prover_instance_sql(lean_name or cid, fixture, witness)
)
# Relations from 'related' field
for rel_target in concept.get("related", []):
rel_key = f"{cid}->{rel_target}"
if rel_key not in seen_relations:
batches["relations"].append(
make_relation_sql(f"rel_{rel_key}", cid, rel_target, "relates_to",
provenance={"source": "lean_concepts.json"})
)
seen_relations.add(rel_key)
# ── Docs concepts → packages ──
for concept in sources.get("docs", []):
cid = concept["id"]
title = concept.get("title", cid)
summary = concept.get("summary", "")
tags = concept.get("tags", [])
source = concept.get("source", "")
if cid not in seen_packages:
batches["packages"].append(
make_package_sql(cid, "document", title, summary[:2000], tags, source,
domain="documentation",
provenance={"extraction": "docs_concepts.json"})
)
seen_packages.add(cid)
# Relations from edges
for edge in concept.get("edges", []):
if isinstance(edge, dict):
tgt = edge.get("target", edge.get("id", ""))
rel_type = edge.get("type", "relates_to")
else:
tgt = str(edge)
rel_type = "relates_to"
if tgt:
rel_key = f"{cid}->{tgt}"
if rel_key not in seen_relations:
batches["relations"].append(
make_relation_sql(f"rel_{rel_key}", cid, tgt, rel_type,
provenance={"source": "docs_concepts.json"})
)
seen_relations.add(rel_key)
# ── Cornfield concepts → packages (skip if already loaded) ──
for concept in sources.get("cornfield", []):
cid = concept["id"]
ctype = concept.get("type", "concept")
name = concept.get("name", cid)
desc = concept.get("description", "")
tags = concept.get("tags", [])
source = concept.get("source_file", "")
lean_name = concept.get("lean_name", "")
expr = concept.get("expression", "")
if cid not in seen_packages:
batches["packages"].append(
make_package_sql(cid, "cornfield_concept", name, desc[:2000], tags, source,
domain="cornfield",
provenance={"extraction": "cornfield_concepts.json",
"lean_name": lean_name,
"cohort": concept.get("cohort", "")})
)
seen_packages.add(cid)
# Receipt for cornfield theorems
if ctype == "theorem":
rec_id = f"rec_{cid}"
if rec_id not in seen_receipts:
batches["receipts"].append(
make_receipt_sql(rec_id, cid, "cornfield_proof", "pending",
toolchain="lean4", theorem_id=lean_name)
)
seen_receipts.add(rec_id)
# Sidon
if concept_has_tags(concept, SIDON_KEYWORDS):
strand = stable_hash(cid)
batches["sidon_labels"].append(
make_sidon_label_sql(f"sidon_{cid}", "powers_of_2", strand, 2**strand, 7-strand)
)
# Braid
if concept_has_tags(concept, BRAID_KEYWORDS):
strand = stable_hash(cid)
batches["braid_strands"].append(
make_braid_strand_sql(f"braid_{cid}", cid, strand,
stable_int(cid+"_x"), stable_int(cid+"_y"))
)
# Eigensolid
if concept_has_tags(concept, EIGENSOLID_KEYWORDS):
batches["eigensolid_snapshots"].append(
make_eigensolid_sql(f"eig_{cid}", cid, "", stable_int(cid+"_s",8)+1,
stable_int(cid+"_c",16), stable_int(cid+"_e",16), True)
)
# Gossip
if concept_has_tags(concept, GRAPH_KEYWORDS):
fold = {"dim0": stable_hash(cid,16), "dim1": stable_hash(cid+"_d1",16)}
batches["gossip_surface_nodes"].append(
make_gossip_node_sql(f"gsn_{cid}", cid, fold,
hashlib.sha256(cid.encode()).hexdigest()[:16],
desc[:200] if desc else name,
stable_int(cid+"_wm",16)/65536.0,
stable_int(cid+"_gr",8))
)
# Relations
for rel_target in concept.get("related", []):
rel_key = f"{cid}->{rel_target}"
if rel_key not in seen_relations:
batches["relations"].append(
make_relation_sql(f"rel_{rel_key}", cid, rel_target, "relates_to",
provenance={"source": "cornfield_concepts.json"})
)
seen_relations.add(rel_key)
# ── Ideas → packages ──
for concept in sources.get("ideas", []):
cid = concept["id"]
title = concept.get("title", cid)
summary = concept.get("summary", "")
tags = concept.get("tags", [])
source = concept.get("source", "")
if cid not in seen_packages:
batches["packages"].append(
make_package_sql(cid, "idea", title, summary[:2000], tags, source,
domain="research",
provenance={"extraction": "ideas.json"})
)
seen_packages.add(cid)
# Relations from edges
for edge in concept.get("edges", []):
if isinstance(edge, dict):
tgt = edge.get("target", edge.get("id", ""))
rel_type = edge.get("type", "relates_to")
else:
tgt = str(edge)
rel_type = "relates_to"
if tgt:
rel_key = f"{cid}->{tgt}"
if rel_key not in seen_relations:
batches["relations"].append(
make_relation_sql(f"rel_{rel_key}", cid, tgt, rel_type,
provenance={"source": "ideas.json"})
)
seen_relations.add(rel_key)
# ── Math concepts → packages + receipts ──
for concept in sources.get("math", []):
cid = concept["id"]
ctype = concept.get("type", "def")
name = concept.get("name", cid)
expr = concept.get("expression", "")
desc = concept.get("description", "")
tags = concept.get("tags", [])
source = concept.get("source_file", "")
lean_name = concept.get("lean_name", "")
lean_status = concept.get("lean_status", "")
if cid not in seen_packages:
pkg_type = f"lean_{ctype}" if ctype in ("theorem", "def", "structure", "predicate") else "math_concept"
batches["packages"].append(
make_package_sql(cid, pkg_type, name, desc or expr, tags, source,
domain="formal-mathematics",
provenance={"extraction": "math.json", "lean_name": lean_name})
)
seen_packages.add(cid)
if ctype in ("theorem",) and lean_status == "DEFINED":
rec_id = f"rec_{cid}"
if rec_id not in seen_receipts:
batches["receipts"].append(
make_receipt_sql(rec_id, cid, "lean_proof", "verified",
toolchain="lean4", theorem_id=lean_name)
)
seen_receipts.add(rec_id)
for rel_target in concept.get("related", []):
rel_key = f"{cid}->{rel_target}"
if rel_key not in seen_relations:
batches["relations"].append(
make_relation_sql(f"rel_{rel_key}", cid, rel_target, "relates_to",
provenance={"source": "math.json"})
)
seen_relations.add(rel_key)
# ── Gossip edges: connect gossip nodes that share tags ──
gossip_nodes = [sql.split("'gsn_")[1].split("'")[0] for sql in batches["gossip_surface_nodes"]] if batches["gossip_surface_nodes"] else []
edge_count = 0
for i, nid in enumerate(gossip_nodes[:50]): # cap to avoid explosion
for j in range(i+1, min(i+3, len(gossip_nodes))):
tgt = gossip_nodes[j]
eid = f"ge_{nid[:20]}_{tgt[:20]}"
w = (stable_int(nid+tgt, 16) / 65536.0)
batches["gossip_surface_edges"].append(
make_gossip_edge_sql(eid, f"gsn_{nid}", f"gsn_{tgt}", "tag_neighbor", w)
)
edge_count += 1
# ── Ingest events: one per source file ──
for src_key in sources:
file_hash = hashlib.sha256(str(sources[src_key]).encode()).hexdigest()[:16]
batches["ingest_events"].append(
make_ingest_event_sql(
f"ingest_{src_key}",
f"session_extract_{src_key}",
f"extraction/{src_key}_concepts.json",
"json_extraction",
file_hash,
"full_corpus",
"populate_ene_v1"
)
)
return batches
# ── Main ──────────────────────────────────────────────────────────────────────
def main():
parser = argparse.ArgumentParser(description="Populate ENE tables from extraction data")
parser.add_argument("--dry-run", action="store_true", help="Print SQL without executing")
parser.add_argument("--batch-size", type=int, default=100, help="Rows per batch INSERT")
args = parser.parse_args()
print("=" * 64)
print(" ENE Table Populator")
print("=" * 64)
if args.dry_run:
print(" MODE: --dry-run (no SQL executed)\n")
# Load extraction data
print("── Loading extraction data ──")
sources = load_all()
total_concepts = sum(len(v) for v in sources.values())
print(f" Total concepts loaded: {total_concepts}\n")
# Build SQL batches
print("── Building SQL batches ──")
batches = build_sql_batches(sources)
# Summary table
print("\n Table | Rows to insert")
print(" ─────────────────────────┼───────────────")
for table in ["packages", "receipts", "sidon_labels", "braid_strands",
"eigensolid_snapshots", "gossip_surface_nodes",
"gossip_surface_edges", "relations", "sessions",
"ingest_events", "prover_state", "prover_instances"]:
count = len(batches.get(table, []))
marker = "" if count > 0 else " (empty)"
print(f" {table:<24s} | {count}{marker}")
print()
# Skip tables
skip_tables = ["crossing_weights", "fractal_nodes", "fractal_manifolds",
"fractal_graph_entities", "vectors", "dsp_nodes",
"nspace_kv",
"wiki_pages", "wiki_revisions", "wiki_categories", "wiki_links", "routes"]
print(" Skipped tables (no clean mapping):")
for t in skip_tables:
print(f" - {t}")
print()
if args.dry_run:
# Print sample SQL for each table
print("── Sample SQL (first 2 per table) ──")
for table, sqls in batches.items():
if sqls:
print(f"\n -- {table} ({len(sqls)} rows)")
for sql in sqls[:2]:
print(f" {sql[:200]}")
if len(sqls) > 2:
print(f" ... and {len(sqls)-2} more")
print()
print(" DRY RUN complete. No SQL was executed.")
return
BATCH_SIZE = 500 # SQL statements per SSH call
print("── Executing SQL (batched, FK checks disabled) ──")
for table, sqls in batches.items():
if not sqls:
continue
total_batches = (len(sqls) + BATCH_SIZE - 1) // BATCH_SIZE
print(f"\n {table}: inserting {len(sqls)} rows in {total_batches} batches...")
ok = 0
err = 0
for batch_idx in range(total_batches):
chunk = sqls[batch_idx * BATCH_SIZE : (batch_idx + 1) * BATCH_SIZE]
block = "SET session_replication_role = 'replica';\nBEGIN;\n" + "\n".join(chunk) + "\nCOMMIT;"
result = neon(block, dry_run=False, timeout=120)
if "ERROR" in result:
# Fall back to row-by-row for this batch
for sql in chunk:
r2 = neon(sql, dry_run=False, timeout=30)
if "ERROR" in r2:
err += 1
if err <= 5:
print(f" ERR: {r2[:120]}")
else:
ok += 1
else:
ok += len(chunk)
if (batch_idx + 1) % 10 == 0 or batch_idx == total_batches - 1:
print(f" ... batch {batch_idx + 1}/{total_batches} ({ok} OK, {err} err)")
print(f" {ok} OK, {err} errors")
# Final counts
print("\n── Final row counts ──")
for table in ["packages", "receipts", "sidon_labels", "braid_strands",
"eigensolid_snapshots", "gossip_surface_nodes",
"gossip_surface_edges", "relations", "sessions",
"ingest_events", "prover_state", "prover_instances"]:
count = neon(f"SELECT COUNT(*) FROM ene.{table}")
print(f" {table}: {count}")
print("\nDone.")
if __name__ == "__main__":
main()