"""Tests Planungs-Retrieval Phase A (Voll-Library-Ranking).""" from planning_exercise_profiles import ExerciseMatchProfile, PlanningTargetProfile from planning_exercise_retrieval import ( fetch_all_visible_exercise_rows, rank_visible_library_hits, ) def test_fetch_all_visible_has_no_profile_or_pool_filter(): captured = {} class _Cur: def execute(self, sql, params): captured["sql"] = sql captured["params"] = list(params) def fetchall(self): return [] fetch_all_visible_exercise_rows( _Cur(), vis_sql="(e.visibility = 'official' OR (e.visibility = 'private' AND e.created_by = %s))", vis_params=[42], query="Kime Partner", exercise_kind_any=["simple"], ) sql = captured["sql"].lower() assert "exercise_skills" not in sql assert "@@ plainto_tsquery" not in sql assert " exists " not in sql.replace("primary_focus_name", "") params = captured["params"] assert params[0] == "Kime Partner" assert params[1] == 42 assert params[2] == "archived" assert params[3] == "simple" assert params[-1] == 8000 def test_rank_visible_library_prefers_profile_over_untagged_pool_miss(): """Übung ohne Pool-Tags, aber hoher Profil-Match, muss vor schwachem Treffer ranken.""" target = PlanningTargetProfile( focus_area_ids={10: 1.0}, skill_weights={5: 1.0}, sources=["framework_catalog"], ) rows = [ {"id": 1, "title": "Schwach", "summary": "", "primary_focus_name": "X", "ft_rank": 0.9}, {"id": 2, "title": "Stark", "summary": "", "primary_focus_name": "Karate", "ft_rank": 0.0}, ] profiles = { 1: ExerciseMatchProfile(exercise_id=1, focus_area_ids={99: 1.0}), 2: ExerciseMatchProfile(exercise_id=2, focus_area_ids={10: 1.0}, skill_weights={5: 1.0}), } class _Cur: def execute(self, sql, params=None): return None def fetchall(self): return [] def _fake_load(cur, exercise_ids, *, batch=400): _ = (cur, batch) return {eid: profiles[eid] for eid in exercise_ids if eid in profiles} def _fake_skills(cur, exercise_ids, *, batch=400): _ = (cur, batch) return {1: {99}, 2: {5, 10}} import planning_exercise_retrieval as mod orig_profiles = mod._load_match_profiles_chunked orig_skills = mod._load_skill_sets_chunked try: mod._load_match_profiles_chunked = _fake_load mod._load_skill_sets_chunked = _fake_skills hits, _ = rank_visible_library_hits( _Cur(), rows, query="", intent="suggest_next", intent_weights={ "fulltext": 0.08, "progression": 0.28, "skill": 0.12, "plan": 0.10, "profile": 0.25, "repeat_unit": -0.30, "repeat_group": -0.15, }, target=target, pack={ "planned_exercise_ids": [], "group_recent_exercise_ids": [], "progression_successor_ids": [], "anchor_skill_ids": [], "anchor_exercise_id": None, "progression_edge_notes": {}, }, ) finally: mod._load_match_profiles_chunked = orig_profiles mod._load_skill_sets_chunked = orig_skills assert hits[0]["id"] == 2 assert hits[0]["score"] > hits[1]["score"]