#!/usr/bin/env python3
import argparse, hashlib, json, sys

KNOWN_SCHEMA = "terry.continuity.v1"

def canon(obj):
    return json.dumps(obj, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode()

def digest(obj):
    return hashlib.sha256(canon(obj)).hexdigest()

def validate(path):
    rows=[]; errors=[]; prev=None
    try:
        with open(path, encoding='utf-8') as f:
            for n,line in enumerate(f,1):
                try: row=json.loads(line)
                except Exception as e: errors.append(f"line {n}: INVALID_JSON"); continue
                if row.get('schema') != KNOWN_SCHEMA: errors.append(f"line {n}: UNKNOWN_SCHEMA")
                if not row.get('provenance_ref'): errors.append(f"line {n}: PROVENANCE_REQUIRED")
                if row.get('truth_scope') == 'fact' and row.get('inherited') is True: errors.append(f"line {n}: INHERITED_NOT_FACT")
                supplied=row.get('self_hash')
                body={k:v for k,v in row.items() if k!='self_hash'}
                if supplied != digest(body): errors.append(f"line {n}: HASH_SELF")
                if row.get('prev_hash') != prev: errors.append(f"line {n}: HASH_CHAIN")
                prev=supplied
                rows.append(row)
    except OSError as e: return {'status':'REFUSE','errors':[str(e)],'rows':0}
    return {'status':'PASS' if not errors else 'REFUSE','errors':errors,'rows':len(rows)}

def main():
    ap=argparse.ArgumentParser(); ap.add_argument('files',nargs='+'); a=ap.parse_args()
    out={p:validate(p) for p in a.files}; print(json.dumps(out,sort_keys=True,indent=2)); return 0 if all(x['status']=='PASS' for x in out.values()) else 1
if __name__=='__main__': sys.exit(main())
