#!/usr/bin/env python3
import hashlib,json,sys
REQUIRED=('referent','contract_version','captured_at','source_ref','population','unit','inherited_not_fact','coverage')
def canon(x): return json.dumps(x,sort_keys=True,separators=(',',':'),ensure_ascii=False).encode()
def digest(x): return hashlib.sha256(canon(x)).hexdigest()
def make_envelope(payload,prev_hash=None):
 e=dict(payload);e['prev_hash']=prev_hash;e['self_hash']=digest({k:v for k,v in e.items() if k!='self_hash'});return e
def validate(e,expected_referent=None,expected_contract=None,prev_hash=None):
 errors=[]
 if not isinstance(e,dict):return {'status':'REFUSE','errors':['not_object']}
 errors += ['missing:'+k for k in REQUIRED if k not in e]
 if e.get('inherited_not_fact') is not True:errors.append('inherited_not_fact_must_be_true')
 p=e.get('population')
 if not ((isinstance(p,int) and p>=0) or (isinstance(p,dict) and p and all(isinstance(v,int) and v>=0 for v in p.values()))):errors.append('population_invalid')
 if not isinstance(e.get('coverage'),dict):errors.append('coverage_invalid')
 if expected_referent is not None and e.get('referent')!=expected_referent:errors.append('referent_drift')
 if expected_contract is not None and e.get('contract_version')!=expected_contract:errors.append('contract_drift')
 if prev_hash is not None and e.get('prev_hash')!=prev_hash:errors.append('chain_drift')
 if 'self_hash' not in e:errors.append('self_hash_missing')
 elif e['self_hash']!=digest({k:v for k,v in e.items() if k!='self_hash'}):errors.append('self_hash_mismatch')
 return {'status':'PASS' if not errors else 'REFUSE','errors':errors}
def main():
 obj=json.load(sys.stdin)
 if isinstance(obj,list):
  prev=None;out=[]
  for e in obj:
   r=validate(e,prev_hash=prev);out.append(r)
   if r['status']=='REFUSE':break
   prev=e['self_hash']
  print(json.dumps({'status':'PASS' if len(out)==len(obj) and all(r['status']=='PASS' for r in out) else 'REFUSE','results':out},sort_keys=True))
 else:print(json.dumps(validate(obj),sort_keys=True))
if __name__=='__main__':main()
