#!/usr/bin/env python3
from __future__ import annotations
import argparse,json
from pathlib import Path
from datetime import datetime
REQUIRED={"event_id","run_id","experiment_id","world_id","turn_index","timestamp_utc","agent_id","model_family","model_version","M_raw","provenance","S_t"}
EXPERIMENTS={"UCF-36","UCF-37","UCF-38"}
FORBIDDEN={"global_opacity_score","intent_score","consciousness_score","collusion_score"}

def parse_time(x):
    return datetime.fromisoformat(str(x).replace("Z","+00:00"))

def validate_event(e):
    missing=sorted(REQUIRED-set(e))
    if missing: raise ValueError(f"missing required fields: {missing}")
    if e["experiment_id"] not in EXPERIMENTS: raise ValueError("unknown experiment_id")
    if not isinstance(e["turn_index"],int) or e["turn_index"]<0: raise ValueError("turn_index must be non-negative integer")
    parse_time(e["timestamp_utc"])
    bad=sorted(FORBIDDEN & set(e))
    if bad: raise ValueError(f"forbidden sovereign/inferential scores: {bad}")
    s=e["S_t"]
    if not isinstance(s,dict) or "meaning_version" not in s or "gloss_id" not in s or "status" not in s:
        raise ValueError("S_t incomplete")
    if s["status"] not in {"UNRESOLVED","CANDIDATE","PARTICIPANT_STABLE","AUDIT_RECONSTRUCTED","FORKED"}:
        raise ValueError("bad S_t.status")
    prov=e["provenance"]
    if not isinstance(prov,dict) or prov.get("source_type") not in {"NATIVE_AGENT","AUDIT_GLOSS","MEMORY_INJECTION","COLD_READ","HUMAN_ANNOTATION"}:
        raise ValueError("bad provenance.source_type")
    cr=e.get("cold_read")
    if cr is not None:
        if not cr.get("history_blinded",False): raise ValueError("cold reader must be history-blinded")
        if not cr.get("candidate_glosses_blinded",False): raise ValueError("cold reader must be candidate-gloss blinded")
    if e["experiment_id"]=="UCF-38":
        if e.get("intervention_condition") not in {"CONTROL","VERIFIED_GLOSS","PERTURBED_GLOSS"}: raise ValueError("UCF-38 intervention condition required")
        if e.get("provenance_visibility") not in {"VISIBLE","HIDDEN"}: raise ValueError("UCF-38 provenance visibility required")
    return True

def validate_rows(rows):
    seen=set(); last={}
    for e in rows:
        validate_event(e)
        if e["event_id"] in seen: raise ValueError(f"duplicate event_id {e['event_id']}")
        seen.add(e["event_id"])
        k=(e["run_id"],e["world_id"],e["agent_id"])
        if k in last and e["turn_index"]<last[k]: raise ValueError(f"non-monotonic turn for {k}")
        last[k]=e["turn_index"]
    return {"status":"PASS","events":len(rows),"runs":len({e["run_id"] for e in rows}),"worlds":len({(e["run_id"],e["world_id"]) for e in rows})}

def load_jsonl(path):
    rows=[]
    for i,line in enumerate(Path(path).read_text(encoding="utf-8").splitlines(),1):
        if line.strip():
            try: rows.append(json.loads(line))
            except Exception as ex: raise ValueError(f"line {i}: {ex}")
    return rows

def main():
    ap=argparse.ArgumentParser()
    ap.add_argument("trace",type=Path)
    a=ap.parse_args()
    print(json.dumps(validate_rows(load_jsonl(a.trace)),ensure_ascii=False,indent=2))

if __name__=="__main__": main()
