MISSING={None,"","MISSING","UNKNOWN","N/A"}
OPTIONS={"DEFER_SHARED_MULTI_TENANCY","POOL","SILO","HYBRID_STAMP"}
MODELS={"POOL","SILO","HYBRID_STAMP"}
STATES={"DEFERRED","PROMOTE_POOL","PROMOTE_SILO","PROMOTE_HYBRID_STAMP"}

def missing(v): return v in MISSING

def money(v):
    try: return float(v)>=0
    except Exception: return False

def evaluate(x):
    # identity and demand evidence
    for f in ["architecture_decision_id","demand_snapshot_id"]:
        if missing(x.get(f)): return "HOLD_DECISION_IDENTITY_MISSING"
    for f in ["tenant_count_current","tenant_count_forecast"]:
        if not isinstance(x.get(f),int) or x.get(f)<0: return "HOLD_TENANT_COUNT_INVALID"
    if x["tenant_count_forecast"] < x["tenant_count_current"]: return "HOLD_FORECAST_BELOW_CURRENT"
    if missing(x.get("growth_trigger")): return "HOLD_GROWTH_TRIGGER_MISSING"
    if missing(x.get("cost_pressure_signal")): return "HOLD_COST_PRESSURE_MISSING"
    if missing(x.get("operational_capacity_signal")): return "HOLD_OPERATIONAL_CAPACITY_MISSING"
    if missing(x.get("compliance_isolation_requirement")): return "HOLD_COMPLIANCE_ISOLATION_MISSING"
    if missing(x.get("tenant_context_propagation_ref")): return "HOLD_TENANT_CONTEXT_MISSING"
    if missing(x.get("isolation_requirement_ref")): return "HOLD_ISOLATION_REQUIREMENT_MISSING"
    if x.get("isolation_model") not in MODELS: return "HOLD_ISOLATION_MODEL_INVALID"
    if missing(x.get("resource_sharing_model")): return "HOLD_RESOURCE_SHARING_MODEL_MISSING"
    if missing(x.get("deployment_model")): return "HOLD_DEPLOYMENT_MODEL_MISSING"
    if missing(x.get("tenant_to_deployment_map_ref")): return "HOLD_TENANT_DEPLOYMENT_MAP_MISSING"
    if missing(x.get("noisy_neighbor_risk")): return "HOLD_NOISY_NEIGHBOR_RISK_MISSING"
    if missing(x.get("blast_radius")): return "HOLD_BLAST_RADIUS_MISSING"
    if missing(x.get("per_tenant_quota_ref")): return "HOLD_PER_TENANT_QUOTA_EVIDENCE_MISSING"
    if missing(x.get("onboarding_automation_state")): return "HOLD_ONBOARDING_STATE_MISSING"
    if missing(x.get("tenant_aware_observability_ref")): return "HOLD_TENANT_OBSERVABILITY_MISSING"
    if not money(x.get("unit_cost_estimate")): return "HOLD_UNIT_COST_INVALID"
    if not money(x.get("migration_cost_estimate")): return "HOLD_MIGRATION_COST_INVALID"
    if x.get("decision_option") not in OPTIONS: return "HOLD_DECISION_OPTION_INVALID"
    if x.get("decision_state") not in STATES: return "HOLD_DECISION_STATE_INVALID"
    if missing(x.get("revisit_trigger")): return "HOLD_REVISIT_TRIGGER_MISSING"
    if missing(x.get("owner_approval_ref")): return "HOLD_OWNER_APPROVAL_MISSING"
    if missing(x.get("audit_ref")): return "HOLD_AUDIT_REFERENCE_MISSING"

    option=x["decision_option"]; state=x["decision_state"]
    expected={"DEFER_SHARED_MULTI_TENANCY":"DEFERRED","POOL":"PROMOTE_POOL","SILO":"PROMOTE_SILO","HYBRID_STAMP":"PROMOTE_HYBRID_STAMP"}[option]
    if state!=expected: return "HOLD_DECISION_OPTION_STATE_MISMATCH"

    # model consistency
    if option in {"POOL","SILO","HYBRID_STAMP"} and x["isolation_model"]!=option:
        return "HOLD_OPTION_ISOLATION_MODEL_MISMATCH"
    if option=="HYBRID_STAMP" and x.get("deployment_model")!="DEPLOYMENT_STAMPS":
        return "HOLD_HYBRID_STAMP_DEPLOYMENT_MISSING"
    if x.get("compliance_isolation_requirement") in {"REGULATED_TIER_DEDICATED","DEDICATED_REQUIRED"} and option=="POOL":
        return "HOLD_COMPLIANCE_ISOLATION_CONFLICT"
    if x.get("regulated_tier_requires_dedicated") is True and option=="POOL":
        return "HOLD_REGULATED_TIER_REQUIRES_DEDICATED"
    if x.get("noisy_neighbor_risk") in {"HIGH","UNMANAGED"} and x.get("per_tenant_quota_ref") in {"NONE","NOT_IMPLEMENTED"}:
        return "HOLD_NOISY_NEIGHBOR_CONTROL_MISSING"
    if x.get("blast_radius") in {"UNBOUNDED","GLOBAL_UNKNOWN"}:
        return "HOLD_BLAST_RADIUS_UNBOUNDED"

    # Promotion requires operations evidence; defer can be valid before demand is cleared.
    promotion=option!="DEFER_SHARED_MULTI_TENANCY"
    if promotion and x.get("growth_trigger")!="CLEARED": return "HOLD_DEMAND_GATE_NOT_CLEARED"
    if promotion and x.get("operational_capacity_signal") not in {"READY","STRONG"}: return "HOLD_OPERATIONAL_CAPACITY_NOT_READY"
    if promotion and x.get("onboarding_automation_state") not in {"AUTOMATED","READY"}: return "HOLD_ONBOARDING_AUTOMATION_NOT_READY"
    if promotion and x.get("tenant_aware_observability_ref") in {"NONE","NOT_IMPLEMENTED"}: return "HOLD_TENANT_OBSERVABILITY_NOT_READY"

    # Transfer is always recomputed.
    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 x.get("regulated_tier_requires_dedicated") is True and option not in {"HYBRID_STAMP","SILO"}:
            return "HOLD_REGULATED_TIER_REQUIRES_DEDICATED"
        if option=="HYBRID_STAMP": return "TRANSFER_HYBRID_REVIEW_READY"

    if option=="DEFER_SHARED_MULTI_TENANCY": return "DEFER_REVIEW_READY"
    if option=="POOL": return "POOL_PROMOTION_REVIEW_READY"
    if option=="SILO": return "SILO_PROMOTION_REVIEW_READY"
    return "HYBRID_PROMOTION_REVIEW_READY"
