CRITICAL=['segment_id','buyer_role','problem_intensity','decision_authority','budget_path','procurement_constraint','current_alternative','evidence_type','confidence_state','review_trigger','evidence_ref']
ALLOWED={'HYPOTHESIS','SUPPORTED','EXCLUDED','HOLD','PARTIAL','DISPUTED','STALE','BLOCKED'}
def evaluate(case):
    missing=[k for k in CRITICAL if case.get(k) in (None,'',[],'UNKNOWN')]
    authority_pass=case.get('decision_authority') in {'YES','CONFIRMED'}
    budget_pass=case.get('budget_path') in {'CLEAR','CONFIRMED'}
    constraint_pass=case.get('procurement_constraint') in {'NONE','PASS','CLEARED'} and case.get('security_constraint','PASS') not in {'BLOCKING','FAIL'}
    evidence_quality_pass=case.get('evidence_type') in {'MULTI_SOURCE','PRIMARY_INTERVIEW_PLUS_RECORDS'} and case.get('sample_bias') not in {'HIGH','SEVERE'} and case.get('confidence_state') in {'MEDIUM','HIGH'}
    stale=case.get('evidence_age_days',0)>case.get('max_evidence_age_days',90)
    state='HOLD';reason='INSUFFICIENT_EVIDENCE'
    if case.get('blocked_by_policy'):
        state='BLOCKED';reason='POLICY_BLOCK'
    elif missing:
        state='HOLD';reason='CRITICAL_EVIDENCE_MISSING'
    elif stale:
        state='STALE';reason='DECISIVE_EVIDENCE_STALE'
    elif case.get('evidence_conflict'):
        state='DISPUTED';reason='EVIDENCE_CONFLICT'
    elif case.get('material_change_not_recomputed'):
        state='PARTIAL';reason='MATERIAL_CHANGE_RECOMPUTE_REQUIRED'
    elif not constraint_pass:
        state='EXCLUDED';reason='CURRENT_CONSTRAINT_BLOCKS_SEGMENT'
    elif authority_pass and budget_pass and evidence_quality_pass and case.get('problem_intensity') in {'HIGH','SEVERE'} and case.get('recurring_need',True) and float(case.get('economic_impact',0))>0:
        state='SUPPORTED';reason='BUYER_MARKET_EVIDENCE_SUPPORTED'
    else:
        state='HYPOTHESIS';reason='EVIDENCE_NOT_YET_SUFFICIENT'
    return {'decision_state':state,'reason_code':reason,'authority_pass':authority_pass,'budget_path_pass':budget_pass,'constraint_pass':constraint_pass,'evidence_quality_pass':evidence_quality_pass,'missing_critical_count':len(missing),'recompute_required':bool(stale or case.get('evidence_conflict') or case.get('material_change_not_recomputed'))}
