Research-Stack/5-Applications/scripts/text_container_to_jsonl.py
Devin AI 38b48e30d2 fix: preserve semantic differences in refactored shared utilities
- q16_lut_generator.py: revert to local unsigned-wrapping Q16 functions
  (hardware LUT uses 32-bit wrapping + 0xFFFFFFFF div-by-zero sentinel)
- dataset_ingest_rds.py: import load_json (not load_jsonl) — files are
  standard JSON arrays, not JSONL
- tiddlywiki_ene_bridge.py: use canonical_json (ensure_ascii=False) to
  preserve non-ASCII hash stability
- ollama_deepseek_review_emitter.py: restore "sha256:" prefix wrapper
- md_to_jsonl_converter.py: restore "sha256:" prefix via compute_sha256
- text_container_to_jsonl.py: restore "sha256:" prefix via compute_sha256
- kotc_sim.py: restore "sha256:" prefix on sha256_text
- gccl_waveprobe.py: restore Q16_MIN/Q16_MAX clamping on q16_add/sub/mul
- vcn_famm_transport.py: restore Q16_MIN/Q16_MAX clamping on q16_add/sub/mul
- lib/jsonl.py: add canonical_json() with ensure_ascii=False

Build: py_compile verified on all 71 modified files
Co-Authored-By: Allaun Silverfox <bigdataiscoming+9i37y6j2@protonmail.com>
2026-06-15 02:26:45 +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())