"""Tests Planungs-KI Phase E3 — Lücken-Angebote und Off-Topic.""" from planning_exercise_path_ai_fill import collect_gap_fill_specs from planning_exercise_path_qa import parse_llm_suggested_new_exercises from planning_exercise_semantics import build_semantic_brief def test_parse_llm_suggested_new_exercises(): brief = build_semantic_brief("Mae Geri Perfektion") llm_qa = { "suggested_new_exercises": [ { "title_hint": "Mae Geri Kraft am Sandsack", "sketch": "Kraft und Schnelligkeit", "phase": "vertiefung", "insert_after_step_index": 1, "rationale": "Zwischenschritt", } ] } specs = parse_llm_suggested_new_exercises(llm_qa, brief=brief, step_count=5) assert len(specs) == 1 assert specs[0]["insert_after_index"] == 1 assert "Mae Geri" in specs[0]["title_hint"] def test_collect_gap_fill_specs_off_topic_and_unfilled(): brief = build_semantic_brief("Mae Geri Perfektion") steps = [ {"exercise_id": 1, "title": "Mae Geri Kihon"}, {"exercise_id": 2, "title": "Präzision"}, {"exercise_id": 3, "title": "One Leg Squat"}, {"exercise_id": 4, "title": "Gleichgewichtstritt"}, ] unfilled = [ { "from_exercise_id": 2, "to_exercise_id": 3, "expected_phase": "vertiefung", "from_title": "Präzision", "to_title": "One Leg Squat", } ] off_topic = [ { "step_index": 2, "exercise_id": 3, "title": "One Leg Squat", "expected_phase": "vertiefung", } ] specs = collect_gap_fill_specs( steps=steps, unfilled_gaps=unfilled, off_topic_steps=off_topic, llm_specs=[], brief=brief, goal_query="Mae Geri Perfektion", ) sources = {s["source"] for s in specs} assert "unfilled_gap" in sources assert "off_topic" in sources off = next(s for s in specs if s["source"] == "off_topic") assert off["replace_step_index"] == 2 assert off["insert_after_index"] == 1