MISSING={None,"","MISSING","UNKNOWN","N/A"}
ROUTES={"FOUNDATION","REPAIR","EXPERIENCED","BRIDGE"}

def missing(v): return v in MISSING

def evaluate(x):
    for f in ["learner_profile_id","target_competency_id","prior_evidence_ref"]:
        if missing(x.get(f)): return "HOLD_CORE_IDENTITY_OR_EVIDENCE_MISSING"
    strength=x.get("prior_evidence_strength")
    if missing(strength): return "HOLD_PRIOR_EVIDENCE_STRENGTH_MISSING"
    route=x.get("route_state")
    if route not in ROUTES: return "HOLD_ROUTE_STATE_INVALID"
    if missing(x.get("diagnostic_signal")): return "HOLD_DIAGNOSTIC_EVIDENCE_MISSING"
    # Profile/seniority cannot override evidence.
    if route=="EXPERIENCED" and strength in {"CONTRADICTED","WEAK","STALE","INSUFFICIENT"}:
        return "HOLD_SENIORITY_NOT_EVIDENCE"
    if x.get("prerequisite_contradiction_open") is True and route=="EXPERIENCED":
        return "HOLD_PREREQUISITE_CONTRADICTION"
    if route=="EXPERIENCED" and strength!="STRONG":
        return "HOLD_EXPERIENCED_ROUTE_UNSUPPORTED"
    if route=="EXPERIENCED" and x.get("diagnostic_supports_compression") is not True:
        return "HOLD_ROUTE_COMPRESSION_UNJUSTIFIED"
    # Conceptual strength + tool gap should use a bridge, not a false foundation downgrade.
    if x.get("conceptual_evidence_strong") is True and x.get("tool_familiarity") in {"NONE","LOW"}:
        if route in {"FOUNDATION","REPAIR"} and x.get("conceptual_gap") is not True:
            return "HOLD_TOOL_GAP_FALSE_COMPETENCE_FAILURE"
        if route=="EXPERIENCED" and x.get("tool_bridge_required") is True:
            return "HOLD_TOOL_BRIDGE_SKIPPED"
    for f in ["scaffold_level","challenge_level","practice_opportunity","feedback_signal"]:
        if missing(x.get(f)): return "HOLD_INSTRUCTIONAL_TREATMENT_INCOMPLETE"
    if route=="EXPERIENCED" and x.get("scaffold_level") not in {"MINIMAL","NONE"}:
        return "HOLD_EXPERIENCED_SCAFFOLD_NOT_COMPRESSED"
    if route=="BRIDGE" and x.get("scaffold_level") not in {"TARGETED_TOOL_BRIDGE","TARGETED_CONTEXT_BRIDGE"}:
        return "HOLD_BRIDGE_NOT_BOUNDED"
    if missing(x.get("transfer_task")): return "HOLD_TRANSFER_TASK_MISSING"
    if missing(x.get("exit_evidence")) or x.get("exit_evidence") in {"WAIVED","WAIVED_BY_EXPERIENCE","HOLD"}:
        return "HOLD_COMMON_EXIT_EVIDENCE_MISSING"
    if x.get("exit_bar_equivalent") is False:
        return "HOLD_EXIT_EVIDENCE_BAR_LOWERED"
    if missing(x.get("repair_trigger")): return "HOLD_REPAIR_TRIGGER_MISSING"
    if missing(x.get("review_owner")): return "HOLD_REVIEW_OWNER_MISSING"
    if x.get("transfer_variant") not in {None,"BASELINE","NONE"}:
        if x.get("baseline_decision_reused") is True: return "HOLD_TRANSFER_BASELINE_ORACLE_REUSE"
        if x.get("transfer_recomputed") is not True: return "HOLD_TRANSFER_NOT_RECOMPUTED"
        if route=="BRIDGE": return "TRANSFER_REVIEW_READY"
    if route=="BRIDGE": return "BRIDGE_REVIEW_READY"
    return "INSTRUCTIONAL_ROUTE_REVIEW_READY"
