def evaluate(c):
    decisive=['content_object_id','audience_segment','intent_class','canonical_url','parent_node','navigation_label','breadcrumb_path','primary_cta','conversion_destination','owner','approval_state','measurement_event']
    if any(not c.get(k) for k in decisive) or not c.get('evidence_ref'):
        return _out('HOLD_EVIDENCE_MISSING','UNKNOWN','UNKNOWN','UNKNOWN','UNKNOWN','DECISIVE_EVIDENCE_MISSING')
    if c.get('accessibility_navigation_check') != 'PASS':
        return _out('HOLD_ACCESSIBILITY','VALID','PARTIAL','READY','READY','ACCESSIBILITY_NAVIGATION_EVIDENCE_INCOMPLETE')
    if c.get('duplicate_content') and c.get('canonical_decision') not in {'SELF_CANONICAL','CANONICAL_TO_EXISTING'}:
        return _out('HOLD_CANONICAL_UNRESOLVED','UNRESOLVED','READY','READY','READY','DUPLICATE_WITHOUT_CANONICAL_DECISION')
    if not c.get('canonical_search_aligned'):
        return _out('HOLD_CANONICAL_UNRESOLVED','SIGNAL_CONFLICT','READY','READY','READY','CANONICAL_SIGNAL_CONFLICT')
    if not c.get('navigation_consistency'):
        return _out('REVISE_NAVIGATION_DRIFT','VALID','DRIFT','READY','PARTIAL','NAVIGATION_BREADCRUMB_IDENTITY_DRIFT')
    if not c.get('cta_preserves_intent'):
        return _out('REVISE_CTA_HANDOFF','VALID','READY','INTENT_LOST','PARTIAL','CONVERSION_DESTINATION_LOSES_ORIGINATING_INTENT')
    if not c.get('measurement_uses_stable_id'):
        return _out('REVISE_MEASUREMENT_IDENTITY','VALID','READY','READY','LABEL_ONLY','MEASUREMENT_IDENTITY_NOT_DURABLE')
    return _out('READY','VALID','READY','READY','STABLE','IA_CONTRACT_AUDITABLE')

def _out(decision,canonical,navigation,conversion,measurement,reason):
    return {'decision_state':decision,'canonical_state':canonical,'navigation_state':navigation,'conversion_state':conversion,'measurement_state':measurement,'reason_code':reason}
