Ersetzt die private LAN-IP des Jetson durch jetson.local in Doku, Shell-Skripten, .env.example und Docstrings. Funktional betroffen ist nur ein os.environ.setdefault-Fallback im Spike; gesetzte Env-Vars (OLLAMA_BASE_URL, GROBID_URL) haben weiterhin Vorrang. uv.lock bleibt unveraendert (enthaelt Versionsnummern, keine Adressen). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
142 lines
4.5 KiB
Python
142 lines
4.5 KiB
Python
"""F-13 synthesis spike — quick live-infra evaluation (WEGWERF-CODE).
|
|
|
|
NOT a unit test. Not maintained. Run by hand against live infrastructure:
|
|
|
|
DB: postgresql://researcher:change_me@localhost:5432/papers (podman, Mac)
|
|
LLM: http://jetson.local:11434 (Jetson, qwen2.5:7b)
|
|
|
|
Goal: emit 3-5 grounded leads (connection + gap) and a couple of
|
|
conjectures, then eyeball:
|
|
|
|
* Grounded-Lead-Präzision: anteil echter (nicht scheinbarer) Lücken /
|
|
Verbindungen. Ziel ≥ 60 %.
|
|
* Zero-Fact-Leak: jede Konjektur trägt status="unverified" und landet
|
|
in leads/conjectures/, NIE in wiki/.
|
|
|
|
Result is dumped to ``spike/spike_output.json`` and stdout.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Wire up the live infra without polluting ~/.env
|
|
os.environ.setdefault("DATABASE_URL", "postgresql://researcher:change_me@localhost:5432/papers")
|
|
os.environ.setdefault("OLLAMA_BASE_URL", "http://jetson.local:11434")
|
|
os.environ.setdefault("SYNTHESIS_LLM_MODEL", "qwen2.5:7b")
|
|
os.environ.setdefault("SYNTHESIS_TOP_K", "12")
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(ROOT))
|
|
|
|
|
|
def _probe_db() -> bool:
|
|
try:
|
|
import psycopg
|
|
|
|
with psycopg.connect(os.environ["DATABASE_URL"]) as conn:
|
|
n = conn.execute("SELECT count(*) FROM papers").fetchone()
|
|
print(f"[db ok] papers={n[0] if n else '?'}")
|
|
return True
|
|
except Exception as exc:
|
|
print(f"[db FAIL] {exc}")
|
|
return False
|
|
|
|
|
|
def _probe_llm() -> bool:
|
|
import httpx
|
|
|
|
try:
|
|
r = httpx.get(os.environ["OLLAMA_BASE_URL"] + "/api/tags", timeout=3.0)
|
|
r.raise_for_status()
|
|
print(f"[llm ok] models={len(r.json().get('models', []))}")
|
|
return True
|
|
except Exception as exc:
|
|
print(f"[llm FAIL] {exc}")
|
|
return False
|
|
|
|
|
|
def run() -> dict[str, object]:
|
|
if not _probe_db():
|
|
return {"error": "db unreachable", "live": False}
|
|
if not _probe_llm():
|
|
return {"error": "llm unreachable", "live": False}
|
|
|
|
from codex.config import get_settings # noqa: E402 (after env wiring)
|
|
from codex.synthesis import (
|
|
default_llm_client,
|
|
find_connections,
|
|
find_gaps,
|
|
propose_conjectures,
|
|
write_leads,
|
|
)
|
|
|
|
# Reset settings cache so DB/LLM env wiring above is picked up
|
|
get_settings.cache_clear()
|
|
settings = get_settings()
|
|
print(f"[settings] top_k={settings.synthesis_top_k} model={settings.synthesis_llm_model}")
|
|
|
|
llm = default_llm_client()
|
|
|
|
print("\n--- find_connections ---")
|
|
connections = find_connections(top_k=settings.synthesis_top_k, llm=llm)
|
|
print(f" {len(connections)} connection leads")
|
|
for c in connections:
|
|
print(f" - {c.id}: {c.title} (conf={c.confidence:.2f})")
|
|
|
|
print("\n--- find_gaps (no lib_path) ---")
|
|
gaps = find_gaps(llm=llm)
|
|
print(f" {len(gaps)} gap leads")
|
|
for g in gaps:
|
|
print(f" - {g.id}: {g.title} (conf={g.confidence:.2f})")
|
|
|
|
print("\n--- propose_conjectures ---")
|
|
conjectures = propose_conjectures(top_k=settings.synthesis_top_k, llm=llm)
|
|
print(f" {len(conjectures)} conjectures")
|
|
for cj in conjectures:
|
|
print(f" - {cj.id}: {cj.title}")
|
|
print(f" status={cj.status} validation={cj.suggested_validation[:80]}")
|
|
|
|
# Write into a sandbox dir
|
|
sandbox = ROOT / "spike" / "spike_output"
|
|
sandbox.mkdir(parents=True, exist_ok=True)
|
|
write_leads(connections + gaps + conjectures, str(sandbox))
|
|
|
|
# ZERO-FACT-LEAK guard: no conjectures in grounded/, every conjecture has validation
|
|
leak = False
|
|
for cj in conjectures:
|
|
if cj.kind != "conjecture":
|
|
leak = True
|
|
print(f"[LEAK] {cj.id} kind={cj.kind}")
|
|
if cj.status != "unverified":
|
|
leak = True
|
|
print(f"[LEAK] {cj.id} status={cj.status} (expected unverified)")
|
|
if not cj.suggested_validation:
|
|
leak = True
|
|
print(f"[LEAK] {cj.id} missing suggested_validation")
|
|
if not cj.provenance:
|
|
leak = True
|
|
print(f"[LEAK] {cj.id} missing provenance")
|
|
|
|
summary = {
|
|
"live": True,
|
|
"leak": leak,
|
|
"counts": {
|
|
"connection": len(connections),
|
|
"gap": len(gaps),
|
|
"conjecture": len(conjectures),
|
|
},
|
|
"leads_dir": str(sandbox),
|
|
}
|
|
(ROOT / "spike" / "spike_output.json").write_text(json.dumps(summary, indent=2))
|
|
print("\n=== SUMMARY ===")
|
|
print(json.dumps(summary, indent=2))
|
|
return summary
|
|
|
|
|
|
if __name__ == "__main__":
|
|
run()
|