def _major(v):
    try:return int(str(v).split('.')[0])
    except:return None

def evaluate(c):
    breaking=c.get('change_kind','').startswith('BREAKING')
    compatibility='BREAKING' if breaking else 'BACKWARD_COMPATIBLE'
    required='MAJOR' if breaking else 'MINOR'
    consumers=c.get('consumers') or []
    ready=sum(1 for x in consumers if x.get('adoption_state')=='MIGRATED' and x.get('contract_test_state')=='PASS' and x.get('migration_evidence') and not x.get('old_payload_seen'))
    blocked=len(consumers)-ready
    support_old=bool(c.get('deprecation_state')=='ACTIVE' and c.get('support_window_end'))
    rollback=bool(c.get('rollback_ref'))
    def out(state,reason):
        return {'decision_state':state,'compatibility_class':compatibility,'required_version_class':required,'consumer_ready_count':ready,'consumer_blocked_count':blocked,'support_old_version':support_old,'rollback_ready':rollback,'primary_reason':reason}
    if c.get('policy_blocked'): return out('BLOCKED','POLICY_BLOCK')
    if c.get('authority_conflict'): return out('DISPUTED','AUTHORITY_CONFLICT')
    if c.get('evidence_age_days',999)>180: return out('STALE','DECISIVE_EVIDENCE_STALE')
    if not c.get('interface_id') or not c.get('current_version') or not c.get('proposed_version') or not c.get('new_surface_hash') or not c.get('producer_owner'): return out('UNKNOWN','DECISIVE_INTERFACE_EVIDENCE_MISSING')
    if c.get('material_change_not_recomputed'): return out('PARTIAL','MATERIAL_CHANGE_NOT_RECOMPUTED')
    if c.get('fork_detected') and not c.get('convergence_plan'): return out('REJECT','VENTURE_FORK_WITHOUT_CONVERGENCE')
    if breaking and (_major(c.get('proposed_version')) is None or _major(c.get('proposed_version'))<=_major(c.get('current_version'))): return out('REJECT','BREAKING_CHANGE_WITHOUT_MAJOR_VERSION')
    if c.get('deprecation_state')=='ACTIVE' and (not c.get('support_window_end') or not c.get('deprecation_owner')): return out('HOLD','DEPRECATION_OWNER_OR_WINDOW_MISSING')
    for x in consumers:
        if x.get('adoption_state')=='MIGRATED' and (x.get('contract_test_state')!='PASS' or not x.get('migration_evidence')):
            return out('HOLD','MIGRATION_UNPROVEN')
    if any(x.get('old_payload_seen') for x in consumers): return out('MIGRATION_REQUIRED','OLD_PAYLOAD_REAPPEARED_AFTER_MIGRATION')
    if blocked>0:
        if support_old and rollback: return out('MIGRATION_REQUIRED','PENDING_CONSUMER_WITH_BOUNDED_OLD_VERSION_SUPPORT')
        return out('HOLD','CONSUMER_NOT_READY_WITHOUT_SAFE_SUPPORT_PATH')
    return out('COMPATIBLE_ACTIVE','ALL_CONSUMERS_PROVEN_ON_TARGET')
