CRITICAL = ['anchor_id', 'anchor_version', 'anchor_owner', 'anchor_approval', 'variant_id', 'parent_artifact_id', 'generation_activity_id', 'provider', 'model_id', 'transformation_intent', 'allowed_change_dimensions', 'protected_claim_ids', 'source_registry_ref', 'semantic_diff', 'claim_diff', 'qa_run_ref', 'human_review_state', 'promotion_decision', 'rollback_ref', 'evidence_ref']

def evaluate(c):
    missing=[k for k in CRITICAL if c.get(k) in (None,"",[],{})]
    evidence_complete=not missing
    lineage_valid=bool(c.get("anchor_id")) and c.get("parent_artifact_id")==c.get("anchor_id") and bool(c.get("generation_activity_id"))
    allowed=set(c.get("allowed_change_dimensions",[])); observed=set(c.get("observed_change_dimensions",[])); scope_valid=observed.issubset(allowed)
    protected=set(c.get("protected_claim_ids",[])); changed=set(c.get("materially_changed_claim_ids",[])); protected_claims_valid=not bool(protected & changed)
    qa_valid=(c.get("qa_result")=="PASS")
    human_review_valid=(c.get("human_review_state")=="APPROVED")
    anchor_version_valid=(c.get("variant_anchor_version")==c.get("anchor_version")) and bool(c.get("anchor_version_current",True))
    if not evidence_complete:
        state="HOLD_MISSING_EVIDENCE"
    elif not lineage_valid:
        state="BLOCKED_LINEAGE"
    elif not protected_claims_valid:
        state="RE_REVIEW_PROTECTED_CLAIM"
    elif not scope_valid:
        state="REWORK_SCOPE_VIOLATION"
    elif not anchor_version_valid:
        state="REVALIDATE_ANCHOR_VERSION"
    elif not qa_valid:
        state="REJECT_VARIANT"
    elif not human_review_valid:
        state="BLOCKED_HUMAN_REVIEW"
    else:
        state="VARIANT_PROMOTED"
    return {"state":state,"evidence_complete":evidence_complete,"lineage_valid":lineage_valid,"protected_claims_valid":protected_claims_valid,"human_review_valid":human_review_valid,"anchor_version_valid":anchor_version_valid}
