from app.common.enums import ActionType, DecisionMode, DoseBucket from app.common.types import PolyGuardAction from app.env.anti_cheat import detect_repeated_action_loop, evaluate_anti_cheat from app.env.env_core import PolyGuardEnv def _action(candidate_id: str) -> PolyGuardAction: return PolyGuardAction( mode=DecisionMode.REGIMEN_OPT, action_type=ActionType.KEEP_REGIMEN, target_drug=None, replacement_drug=None, dose_bucket=DoseBucket.NA, taper_days=None, monitoring_plan=None, candidate_id=candidate_id, confidence=0.7, rationale_brief="x", ) def test_repeat_loop_detector() -> None: assert detect_repeated_action_loop([_action("cand_01"), _action("cand_01"), _action("cand_01")], threshold=3) def test_candidate_mismatch_detected() -> None: env = PolyGuardEnv() env.reset(seed=77, difficulty="easy") action = _action("cand_not_in_set") result = evaluate_anti_cheat(env.state, action, legal_candidate_ids={"cand_01", "cand_02"}) assert result.exploit_detected assert "candidate_not_in_legal_set" in result.reasons def test_first_keep_regimen_is_not_holdout_exploit() -> None: env = PolyGuardEnv() env.reset(seed=42, difficulty="medium", sub_environment="REGIMEN_RISK") action = _action("cand_01") result = evaluate_anti_cheat(env.state, action, legal_candidate_ids={"cand_01"}) assert "holdout_ddi_not_addressed" not in result.reasons def test_repeated_keep_regimen_triggers_holdout_guard() -> None: env = PolyGuardEnv() env.reset(seed=42, difficulty="medium", sub_environment="REGIMEN_RISK") action = _action("cand_01") env.state.action_history.append({"step": 0, "action": action.model_dump(mode="json"), "applied": True}) result = evaluate_anti_cheat(env.state, action, legal_candidate_ids={"cand_01"}) assert result.exploit_detected assert "holdout_ddi_not_addressed" in result.reasons