from pathlib import Path
import json, ast
P=Path(__file__).resolve().parent
cases=json.loads((P/'fixtures/cases.json').read_text(encoding='utf-8'))['cases']
assert len(cases)==8 and len({c['id'] for c in cases})==8
ast.parse((P/'starter.py').read_text(encoding='utf-8'))
required=['handoff_id','sender_agent','handoff_timestamp','declared_work_scope','returned_artifact_id','returned_digest','returned_manifest_id','bag_complete','checksums_verified','derivation_linked','external_source_present','external_source_disclosed','external_source_traceable','acceptance_reviewer','reviewer_acceptance']
for c in cases:
    for k in required: assert k in c,(c['id'],k)
assert any(c['returned_digest']==c.get('outbound_digest') for c in cases if c.get('outbound_digest'))
assert any(c.get('change_note') is None for c in cases)
assert any(not c.get('checksums_verified') for c in cases)
assert any(not c.get('outbound_artifact_id') for c in cases)
assert any(not c.get('transfer_receipt_id') for c in cases)
assert any(c.get('external_source_present') and c.get('external_source_disclosed') and not c.get('external_source_traceable') for c in cases)
assert any(c.get('reviewer_acceptance')=='REJECTED' for c in cases)
assert any(c.get('transfer') for c in cases)
print('PASS learner structural checks: 8 synthetic round-trip cases covering byte-identical receipt, missing change note, checksum failure, ambiguous outbound, missing receipt, external-source gap, reviewer rejection and transfer')
