from pathlib import Path
import json,sys
ROOT=Path(__file__).resolve().parents[1]; checks=[]
def ck(n,c):checks.append((n,bool(c)))
def load(r):return json.loads((ROOT/r).read_text())
base=load('fixture/baseline-ledger.json'); cases=load('fixture/probe-cases.json')['cases']; gold=load('fixture/golden-policy.json'); req=load('requirements.json'); pol=load('toolchain-policy.json'); dec=load('submission/decision.template.json'); status=load('evidence/validation-status.json'); ev=load('evidence/Append_only_Ledger_Integrity_Record_v1.template.json'); run=(ROOT/'src/run_local_lab.py').read_text(); fix=(ROOT/'src/ledger_fixture.py').read_text()
ids=['baseline_append_correction','mutate_original_history','duplicate_posting_identity','missing_correction_link','evidence_field_removed']; cls={'baseline_append_correction':'CORRECTION_APPENDED_AND_REPLAYABLE','mutate_original_history':'HISTORY_MUTATION_DETECTED','duplicate_posting_identity':'DUPLICATE_POSTING_REJECTED','missing_correction_link':'CORRECTION_LINEAGE_MISSING','evidence_field_removed':'EVIDENCE_INCOMPLETE'}; forb=['append-only proves legal compliance','correct balance proves historical integrity','correction requires mutating original','append-only equals event sourcing or blockchain','unique key proves distributed exactly-once']; fields=['correction_rule','projection_order_rule','posting_identity_rule','bounded_decision','residual_domain_rule','transfer_decision']
e=base['entries'][0]; vals=[('one baseline',len(base['entries'])==1),('entry id',e['entry_id']=='E1'),('business key',e['business_key']=='debit-001'),('entry type',e['entry_type']=='DEBIT'),('amount',e['amount_delta']==-12000),('accepted',e['accepted_at']==1),('expected projection',base['expected_corrected_projection']==-10000),('ids exact',[c['id'] for c in cases]==ids),('classes exact',{c['id']:c['expected_class'] for c in cases}==cls),('dims exact',req['critical_dimensions']==['append_only_history','correction_entry','projection_rebuild','posting_identity','audit_boundary']),('evidence seven',len(req['required_evidence'])==7),('external forbidden',pol['external_network_forbidden'] is True and pol['external_service_forbidden'] is True),('postgres false',pol['postgresql_runtime_claimed'] is False),('fixture scope',pol['fixture_scope']=='DISPOSABLE_IN_MEMORY_ONLY'),('evidence scope',pol['evidence_scope']=='BOUNDED_LOCAL_FIXTURE_ONLY'),('runner v2',pol['runner_contract_version']=='DAT010-RUNNER-CONTRACT-v2'),('policy ids',pol['expected_case_ids']==ids),('prediction ids',pol['required_prediction_ids']==ids),('required fields',pol['required_decision_fields']==fields),('provenance eight',len(pol['runtime_input_files_required'])==8),('forbidden exact',gold['forbidden_conclusions']==forb),('probe semantics',gold['required_probe_semantics']==cls),('correction type policy',gold['required_correction_entry_type']=='CORRECTION'),('replay policy',gold['required_replay_order']=='accepted_at_then_entry_id'),('decision incomplete',dec['status']=='LEARNER_INCOMPLETE'),('preds exact blank',set(dec['predictions'])==set(ids) and all(v is None for v in dec['predictions'].values())),('status untouched',status['status']=='NOT_RUN_AUTHORING_BOUNDARY' and status['runtime_observations_claimed'] is False and status['final_integrity_decision_claimed'] is False),('evidence untouched',ev['status']=='LEARNER_INCOMPLETE' and ev['runtime_observations_claimed'] is False and ev['bounded_decision']=='LEARNER_TODO'),('decision authority',ev['decision_authority']=='LEARNER'),('runner confirm','if not args.confirm_local:' in run),('runner all cases','for c in cases:' in run and 'cases[:1]' not in run),('runner fields',"pol['required_decision_fields']" in run),('runner provenance',"pol['runtime_input_files_required']" in run),('correction constant',"'entry_type':'CORRECTION'" in fix),('correction guard',"e['entry_type']!='CORRECTION'" in fix),('projection delegates','self.projection_trace()' in fix),('canonical full','return json.dumps(self.replay_entries()' in fix),('no network',not any(x in fix for x in ['requests','urllib','socket.connect','http://','https://']))]
for n,v in vals: ck(n,v)
for n,v in checks: print(('PASS' if v else 'FAIL'),n)
print(f'{sum(v for _,v in checks)}/{len(checks)} PASS');sys.exit(0 if all(v for _,v in checks) else 1)
