import pathlib,json,sys,copy
LAB=pathlib.Path(__file__).resolve().parents[1]; sys.path.insert(0,str(LAB/'src'))
from lifecycle_policy import *
policy=json.loads((LAB/'fixture/golden-policy.json').read_text()); records=json.loads((LAB/'fixture/baseline-data.json').read_text())['records']; checks=[]
def c(n,x): checks.append((n,bool(x)))
op=records[0]; audit=records[1]
c('class_op',classify_record(op,policy)['decision']=='ALLOW_CLASSIFIED_CONTEXT')
c('ret_op',retention_decision(op,policy)['condition']=='synthetic_30d_after_case_close')
c('ret_audit',retention_decision(audit,policy)['condition']=='synthetic_180d_after_event')
mut=copy.deepcopy(op); mut['data_class']='audit_event'; c('class_mutation_denied',classify_record(mut,policy)['decision']=='DENY_CLASS_PURPOSE_OWNER_MISMATCH')
exp=evaluate_export({'record_id':op['record_id'],'requester_role':'role:support-exporter','processing_purpose':op['processing_purpose'],'requested_fields':['record_id','status']},records,policy); c('export_allow',exp['decision']=='ALLOW_EXPORT_MINIMIZED')
c('export_fields',exp['exported_fields']==['record_id','status'])
c('export_overbroad',evaluate_export({'record_id':op['record_id'],'requester_role':'role:support-exporter','processing_purpose':op['processing_purpose'],'requested_fields':['record_id','internal_trace']},records,policy)['decision']=='DENY_EXPORT_FIELD_SCOPE')
c('export_wrong_role',evaluate_export({'record_id':op['record_id'],'requester_role':'role:analytics-reader','processing_purpose':op['processing_purpose'],'requested_fields':['record_id']},records,policy)['decision']=='DENY_EXPORT_AUTHORITY')
hold={'active':True,'reason':'synthetic_review_hold','owner':'governance-owner'}; c('hold_active',evaluate_hold(hold,policy)['decision']=='HOLD_ACTIVE')
c('hold_blocks_delete',evaluate_deletion(op,{'primary_disposed':True,'derived_disposed':True,'backup_boundary':'DOCUMENTED_EXPIRY_BOUNDARY'},hold,policy)['decision']=='DELETE_SUSPENDED_HOLD')
c('hold_bad_meta',evaluate_hold({'active':True,'reason':'','owner':''},policy)['decision']=='DENY_HOLD_METADATA_INCOMPLETE')
c('ui_not_delete',evaluate_deletion(op,{'ui_hidden_only':True,'primary_disposed':True,'derived_disposed':True,'backup_boundary':'DOCUMENTED_EXPIRY_BOUNDARY'},None,policy)['decision']=='DENY_UI_INVISIBILITY_NOT_DISPOSITION')
c('incomplete_derived',evaluate_deletion(op,{'primary_disposed':True,'derived_disposed':False,'backup_boundary':'DOCUMENTED_EXPIRY_BOUNDARY'},None,policy)['decision']=='DENY_DELETION_EVIDENCE_INCOMPLETE')
delok=evaluate_deletion(op,{'primary_disposed':True,'derived_disposed':True,'backup_boundary':'DOCUMENTED_EXPIRY_BOUNDARY'},None,policy); c('delete_bounded',delok['decision']=='DELETE_BOUNDED_DISPOSITION_RECORDED')
row=build_evidence_row(op,retention_decision(op,policy),exp,delok); c('row_complete',evidence_row_complete(row)); bad=dict(row); bad['residual_boundary']=''; c('row_missing_detected',not evidence_row_complete(bad))
c('transfer_rebuild',classify_transfer('analytics_dataset')['status']=='REBUILD_LIFECYCLE'); c('transfer_no_copy',classify_transfer('analytics_dataset')['copy_baseline_retention'] is False)
c('production_false',policy['production_proof'] is False); c('not_law',policy['jurisdiction_specific_law'] is False); c('universal_false',policy['universal_retention_period'] is False)
for n,ok in checks: print(('PASS' if ok else 'FAIL'),n)
print(f'SUMMARY {sum(ok for _,ok in checks)}/{len(checks)} PASS'); raise SystemExit(0 if all(ok for _,ok in checks) else 1)
