#!/usr/bin/env python3
import hashlib, json, copy
from pathlib import Path

REQUIRED = {"PROVENANCE_REQUIRED", "INHERITED_NOT_FACT"}

def digest(obj):
    return hashlib.sha256(json.dumps(obj, sort_keys=True, separators=(",", ":")).encode()).hexdigest()

def seal(rec):
    body = {k:v for k,v in rec.items() if k not in ("hash_self", "hash_chain")}
    rec["hash_self"] = digest(body)
    return rec

def make_fixture():
    a = seal({"id":"a","kind":"decision","value":"keep","source_ref":"src:demo","flags":[]})
    b = seal({"id":"b","kind":"memory","value":"inherited context","source_ref":"src:demo","flags":["INHERITED_NOT_FACT"]})
    b["hash_chain"] = digest({"prev": a["hash_self"], "hash_self": b["hash_self"]})
    a["hash_chain"] = digest({"prev": None, "hash_self": a["hash_self"]})
    return [a,b]

def validate(rows):
    out=[]
    prev=None
    for i,r in enumerate(rows):
        gates=[]
        body={k:v for k,v in r.items() if k not in ("hash_self", "hash_chain")}
        if r.get("hash_self") == digest(body): gates.append("HASH_SELF")
        else: gates.append("HASH_SELF_FAIL")
        expected_chain=digest({"prev":prev,"hash_self":r.get("hash_self")})
        if r.get("hash_chain") == expected_chain: gates.append("HASH_CHAIN")
        else: gates.append("HASH_CHAIN_FAIL")
        if isinstance(r.get("source_ref"),str) and r["source_ref"]: gates.append("PROVENANCE_REQUIRED")
        else: gates.append("PROVENANCE_REQUIRED_FAIL")
        if "INHERITED_NOT_FACT" in r.get("flags",[]): gates.append("INHERITED_NOT_FACT")
        status="PASS" if not any(x.endswith("_FAIL") for x in gates) else "REFUSE"
        out.append({"index":i,"id":r.get("id"),"status":status,"gates":gates})
        prev=r.get("hash_self")
    return out

def main():
    positive=make_fixture()
    cases={"positive":positive}
    tamper_self=copy.deepcopy(positive); tamper_self[0]["value"]="altered"; cases["tampered_self"]=tamper_self
    tamper_chain=copy.deepcopy(positive); tamper_chain[1]["hash_chain"]="0"*64; cases["tampered_chain"]=tamper_chain
    missing_prov=copy.deepcopy(positive); missing_prov[0].pop("source_ref"); seal(missing_prov[0]); missing_prov[0]["hash_chain"]=digest({"prev":None,"hash_self":missing_prov[0]["hash_self"]}); cases["missing_provenance"]=missing_prov
    results={name:{"rows":rows,"validation":validate(rows)} for name,rows in cases.items()}
    print(json.dumps({"contract":"continuity-validator-v1","required_gates":sorted(REQUIRED|{"HASH_SELF","HASH_CHAIN"}),"cases":results},sort_keys=True,indent=2))

if __name__ == "__main__": main()
