Research-Stack/5-Applications/scripts/text_container_to_jsonl.py
Devin AI 0c9efac330 chore(consolidation): integrate E8Sidon stack (PRs #79 #80 #81 #89) into one PR
Squash the four overlapping feature branches into a single change set against
main, eliminating cross-PR merge conflicts and the duplicated CI-fix scripts.

What this brings in (merge order #79 -> #80 -> #81 -> #89):
- #79 refactor(infra): shared utilities (4-Infrastructure/lib/*: q16, hashing,
  jsonl, fraction_utils) + the scripts/math-first/* validators that the
  math-check CI requires.
- #80 feat(lean): Semantics.E8Sidon (1025 lines) -- Eisenstein coefficient
  identity E4^2 = E8 and the Sidon framework. E4_sq_eq_E8_coeff is fully proved
  (all Fourier-coefficient extraction machine-checked); the single residual gap
  is pinned to E4_sq_eq_E8_qExpansion (Mathlib lacks the valence formula /
  dim M8 = 1). 4 sorries + 1 axiom (e8_additive_completeness), all TODO(lean-port).
- #81 refactor(lean): Float-free FixedPoint core (integer-only sqrt/log2/expNeg).
  E8Sidon.lean kept at #80's final 1025-line version (the #81 intermediate
  438-line copy was overridden by merge order).
- #89 feat(lean): Semantics.RRC.PolyFactorIdentity -- short-sleeve polynomial
  detection at the zerocopy limb boundary; now imports Semantics.E8Sidon for
  sigma3/sigma7/convolutionLHS (single source of truth) instead of inlining them.

Conflict resolution:
- flake.nix -> canonical rs-surface removal (Garnix shutdown).
- scripts/math-first/* -> byte-identical across branches, clean.
- .cursorrules / AGENTS.md -> unified; baselines + sorry inventory refreshed.

Verification:
- lake build (default aggregator): 3573 jobs, 0 errors.
- lake build Semantics.RRC.PolyFactorIdentity (E8Sidon + FixedPoint + PolyFactor):
  3655 jobs, 0 errors. Witnesses verified (sigma7 4 = 16513, convolutionLHS 6 = 2350).
- Python tests: 68/68 pass.

Note: the "Workers Builds: researchstack" check is a preexisting external
Cloudflare build unrelated to this change (no branch touches 4-Infrastructure/cloudflare/).

Build: 3573 jobs (default), 3655 jobs (narrow), 0 errors
Co-Authored-By: Allaun Silverfox <bigdataiscoming+9i37y6j2@protonmail.com>
2026-06-16 02:01:31 +00:00

369 lines
10 KiB
Python

#!/usr/bin/env python3
"""Comprehensive Text Container → JSON-L Converter (legacy shim).
Hardcoded node/provenance assumptions were removed:
- node id is configurable via --node-id or ENE_NODE_ID
- tailscale ip via ENE_TAILSCALE_IP
- workspace root via ENE_WORKSPACE_ROOT
This script is an ingest shim. Treat outputs as non-authoritative.
"""
import argparse
import json
import csv
import sys
from pathlib import Path
from datetime import datetime, timezone
from typing import Dict, Any, List, Optional, Tuple
from dataclasses import dataclass
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "4-Infrastructure"))
from lib.hashing import sha256_file as _sha256_file
def compute_sha256(filepath: Path) -> str:
return f"sha256:{_sha256_file(filepath)}"
def env_default(name: str, default: str) -> str:
try:
import os
v = os.environ.get(name)
except Exception:
v = None
return v if v is not None and v != "" else default
WORKSPACE_ROOT = Path(env_default("ENE_WORKSPACE_ROOT", "/home/allaun/Documents/Research Stack"))
MANIFEST_PATH = WORKSPACE_ROOT / "data" / "manifest.jsonl"
EXCLUDE_PATTERNS = [
".git",
"node_modules",
".lake",
"tools/search",
".vscode",
".devcontainer",
"__pycache__",
".pytest_cache",
"venv",
"hutter_venv",
"venv_",
]
PROCESS_EXTENSIONS = {".md", ".json", ".jsonl", ".csv", ".tsv", ".txt"}
ARCHETYPE_MAP = {
".md": "markdown_document",
".json": "json_structure",
".jsonl": "jsonl_dataset",
".csv": "csv_table",
".tsv": "tsv_table",
".txt": "text_document",
}
@dataclass
class FileContainer:
filepath: Path
ext: str
size: int
mtime: float
hash: str
def should_skip(filepath: Path) -> Tuple[bool, str]:
path_str = str(filepath)
config_files = {
"package.json",
"package-lock.json",
"tsconfig.json",
"devcontainer.json",
"settings.json",
"launch.json",
"tasks.json",
".stylelintrc.json",
"biome.json",
"lake-manifest.json",
"pyrightconfig.json",
"manifest.json",
"requirements.txt",
"app.json",
"acme.json",
".vscode",
".devcontainer",
}
if filepath.name in config_files:
return True, "config"
for pattern in EXCLUDE_PATTERNS:
if pattern in path_str:
return True, f"excluded:{pattern}"
if filepath.stat().st_size > 100_000_000:
return True, "too_large"
return False, ""
def infer_domain(filepath: Path, content: str = "") -> str:
name = filepath.stem.upper()
path = str(filepath).upper()
domain_hints = {
"LEAN|SEMANTIC|FORMALIZATION": "formalization",
"MATH|EQUATION|MODEL": "mathematics",
"ENE|SUBSTRATE": "ene",
"HUTTER|COMPRESS|KOLMOGOROV": "compression",
"PHYSICS|FIELD|QUANTUM": "physics",
"GENOME|RGFLOW|SWARM|TOPOLOGY": "orchestration",
"NOTION|LINEAR|ISSUE|TASK": "project_management",
"BRAIN|MANIFOLD": "topology",
"SPEC|SPECIFICATION|SCHEMA": "specification",
"DATA|DATASET|CSV|TSV": "data_science",
"CONFIG|SETTING": "infrastructure",
}
for patterns, domain in domain_hints.items():
if any(p in name or p in path for p in patterns.split("|")):
return domain
if filepath.suffix in {".csv", ".tsv"}:
return "data_science"
if filepath.suffix == ".json":
return "specification"
return "unknown"
def infer_tier(filepath: Path) -> str:
path = str(filepath).lower()
if "6-Documentation/docs/semantics" in path or "docs" in path:
return "CORE"
if "shared-data/data/germane" in path:
return "AUX"
if "out" in path:
return "DERIVED"
return "AUX"
def read_text_safely(filepath: Path, max_size: int = 1_000_000) -> str:
encodings = ["utf-8", "utf-8-sig", "latin-1", "ascii", "cp1252"]
size = filepath.stat().st_size
if size > max_size:
with open(filepath, "rb") as f:
start = f.read(500)
f.seek(max(0, size - 500))
end = f.read(500)
content_bytes = start + b"\n...\n" + end
else:
with open(filepath, "rb") as f:
content_bytes = f.read()
for encoding in encodings:
try:
return content_bytes.decode(encoding, errors="replace")
except Exception:
continue
return "<unable to decode>"
def extract_summary(content: str, max_chars: int = 250) -> str:
lines = content.split("\n")
summary_lines = []
for line in lines:
stripped = line.strip()
if stripped and not stripped.startswith("#") and not stripped.startswith("{"):
summary_lines.append(stripped)
if len(" ".join(summary_lines)) >= max_chars:
break
summary = " ".join(summary_lines)[:max_chars]
return summary or "<empty or binary file>"
def compute_genome(filepath: Path, content: str = "") -> Dict[str, int]:
try:
size = filepath.stat().st_size
lines = len(content.split("\n")) if content else 10
mu = (lines % 256) // 32
rho = min(7, (size // 1024) % 8)
c = 4
m = 4
ne = min(7, len(filepath.stem) // 10)
sig = 0 if filepath.suffix != ".json" else 3
return {"mu": mu, "rho": rho, "c": c, "m": m, "ne": ne, "sig": sig}
except Exception:
return {"mu": 0, "rho": 0, "c": 4, "m": 4, "ne": 0, "sig": 0}
def text_to_jsonl_entry(filepath: Path, node_id: str) -> Optional[Dict[str, Any]]:
should_skip_file, _reason = should_skip(filepath)
if should_skip_file:
return None
content = read_text_safely(filepath)
file_hash = compute_sha256(filepath)
file_stat = filepath.stat()
mtime_unix = file_stat.st_mtime
file_size = file_stat.st_size
domain = infer_domain(filepath, content)
tier = infer_tier(filepath)
genome = compute_genome(filepath, content)
rel_path = filepath.relative_to(WORKSPACE_ROOT)
pkg = f"ene/text/{filepath.suffix[1:]}/{rel_path.stem}".replace("\\", "/")
version = datetime.fromtimestamp(mtime_unix, tz=timezone.utc).isoformat()
concept_anchor = {
"domain": domain,
"concept": filepath.stem.lower().replace(" ", "_").replace("-", "_").replace(".", "_"),
"resolution": "STABLE",
}
summary = extract_summary(content)
data_payload: Dict[str, Any] = {
"pkg": pkg,
"version": version,
"tier": tier,
"domain": domain,
"archetype": ARCHETYPE_MAP.get(filepath.suffix, "text_document"),
"concept_anchor": concept_anchor,
"file_path": str(rel_path).replace("\\", "/"),
"file_ext": filepath.suffix,
"file_hash": file_hash,
"byte_count": file_size,
"line_count": len(content.split("\n")),
"summary": summary,
}
if filepath.suffix == ".json":
try:
obj = json.loads(content)
data_payload["json_keys"] = list(obj.keys() if isinstance(obj, dict) else [])
except Exception:
data_payload["json_keys"] = []
if filepath.suffix in {".csv", ".tsv"}:
try:
with open(filepath, "r", encoding="utf-8", errors="replace") as f:
reader = csv.DictReader(f)
first_row = next(reader, None)
if first_row:
data_payload["columns"] = list(first_row.keys())
except Exception:
pass
provenance = {
"node": node_id,
"lake_seed": env_default("ENE_LAKE_SEED", "text_converter"),
"tailscale_ip": env_default("ENE_TAILSCALE_IP", "127.0.0.1"),
"attestation_hash": file_hash,
"prev_id": None,
}
bind = {
"lawful": True,
"cost": 0x00010000,
"invariant": "documentConsistency",
"class": "informational_bind",
}
return {
"t": mtime_unix,
"src": "ene",
"id": f"ene:{pkg}:{version}",
"op": "upsert",
"data": data_payload,
"genome": genome,
"bind": bind,
"provenance": provenance,
}
def find_all_text_containers() -> List[Path]:
containers = []
for ext in PROCESS_EXTENSIONS:
for file_path in WORKSPACE_ROOT.rglob(f"*{ext}"):
if file_path.is_file():
containers.append(file_path)
return sorted(list(set(containers)))
def load_existing_manifest() -> set:
existing_ids = set()
if MANIFEST_PATH.exists():
with open(MANIFEST_PATH, "r") as f:
for line in f:
line = line.strip()
if not line:
continue
try:
entry = json.loads(line)
existing_ids.add(entry.get("id", ""))
except json.JSONDecodeError:
continue
return existing_ids
def convert_all_text_containers(node_id: str, output_file: Optional[str] = None) -> Tuple[int, int, int, int]:
output_path = Path(output_file) if output_file else MANIFEST_PATH
containers = find_all_text_containers()
existing_ids = load_existing_manifest()
converted = 0
skipped = 0
already_exists = 0
with open(output_path, "a") as manifest_f:
for container in containers:
entry = text_to_jsonl_entry(container, node_id=node_id)
if entry is None:
skipped += 1
continue
entry_id = entry.get("id", "")
if entry_id in existing_ids:
already_exists += 1
else:
manifest_f.write(json.dumps(entry) + "\n")
manifest_f.flush()
converted += 1
return len(containers), converted, already_exists, skipped
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--output-file", default=None)
parser.add_argument("--node-id", default=env_default("ENE_NODE_ID", "qfox"))
args = parser.parse_args()
total, converted, already_exists, skipped = convert_all_text_containers(
node_id=args.node_id, output_file=args.output_file
)
print(
json.dumps(
{
"total": total,
"converted": converted,
"already_exists": already_exists,
"skipped": skipped,
"node_id": args.node_id,
},
indent=2,
)
)
return 0
if __name__ == "__main__":
raise SystemExit(main())