"""Evidence classifier: hypotheses and confirmed observations are distinct.""" import json, sqlite3, time from pathlib import Path def diagnose(obs): pods=obs.get("pods",{}).get("pods",[]) events=obs.get("events",{}).get("items",[]) text=" ".join(e.get("message","") for e in events) if any(p.get("phase")=="Pending" for p in pods) and any(e.get("reason")=="FailedScheduling" for e in events): if obs.get("deployment",{}).get("selector")=={"lab.invalid/pool":"absent"} and ("selector" in text or "affinity" in text): return "selector_mismatch",["pods","events","deployment"] if "Insufficient nvidia.com/gpu" in text:return "gpu_insufficient",["pods","events"] for pod in pods: for c in pod.get("containers",[]): last=c.get("lastState",{}).get("terminated",{}) if last.get("reason")=="OOMKilled" and last.get("exitCode")==137:return "oom_killed",["pods"] waiting=c.get("state",{}).get("waiting",{}).get("reason") if waiting in ("ErrImagePull","ImagePullBackOff"):return "image_pull_failure",["pods"] if waiting=="CrashLoopBackOff" and "logs" in obs:return "restart_backoff",["pods","logs"] if "no such host" in str(obs.get("logs",{})):return "dns_lookup_failed",["logs"] if obs.get("endpoints",{}).get("service_exists") and not any(e.get("conditions",{}).get("ready") for s in obs["endpoints"]["items"] for e in s.get("endpoints",[])): return "no_ready_endpoints",["endpoints"] return None,[] def compact(obs,limit=3500): # Keep diagnosis-relevant fields before enforcing a character budget. result={} for k,v in obs.items(): if k=="pods":v=[{"phase":p["phase"],"conditions":p.get("conditions",[])[:2],"states":[(c.get("state"),c.get("lastState")) for c in p.get("containers",[])[:2]]} for p in v["pods"][:2]] if k=="deployment":v={n:v.get(n) for n in ("uid","selector","generation")} result[k]=json.dumps(v,ensure_ascii=False)[:max(100,limit//max(1,len(obs)))] return result def memory(mode,record=None): Path("data").mkdir(exist_ok=True) with sqlite3.connect("data/cluster-memory.sqlite") as c: c.execute("CREATE TABLE IF NOT EXISTS cases(id TEXT PRIMARY KEY,category TEXT,source TEXT,verified REAL)") if mode=="save": c.execute("INSERT OR REPLACE INTO cases VALUES(?,?,?,?)",(record["id"],record["category"],record["source"],time.time())) else: return c.execute("SELECT category,source FROM cases WHERE verified>? ORDER BY verified DESC LIMIT 3",(time.time()-86400*30,)).fetchall()