# Planungs-KI: Übungssuche & Kontext für Neu-Anlage **Version:** 0.2 **Datum:** 2026-05-23 **Status:** P0–P2 ✅ · Phase A/B/B2 ✅ · **Phase C1–C3 ✅** · **Phase E ✅** (Semantik + Pfad-QA) **Bezüge:** `AI_PLANNING_KI_MULTISTAGE_FORECAST.md` · `AI_PROMPT_TARGET_ARCHITECTURE.md` · `SKILL_SCORING_SPEC.md` · `TRAINING_FRAMEWORK_SPEC.md` §3 (Progressionsgraph) --- ## 1. Ziel Trainer in der **Trainingsplanung** sollen Übungen finden oder anlegen können mit natürlichen Anfragen wie: - „Vertiefung zu Übung XY“ - „Nächste sinnvolle Übung im Progressionsgraph Z“ - „Baut auf der bisherigen Planung auf — Reaktionsschnelligkeit mit Partnern“ - **Preset:** „Schlage mir die nächste Übung vor“ **Suche** (Bibliothek) und **Neu mit KI-Assistent** (Anlage) nutzen dasselbe **`PlanningExerciseContextPack`** — unterschiedliches Ergebnis (Treffer vs. Entwurf). --- ## 2. Architektur (Mehrstufig) | Stufe | Name | Technik | P0 | |-------|------|---------|-----| | **S0** | Kontext-Pack | SQL/API, deterministisch | ✅ | | **S1a** | Intent strukturieren | LLM `planning_exercise_search_intent` (Szenario-Pipeline) | ✅ P1 | | **S1b** | Hybrid-Retrieval | Score: Volltext + Graph + Skills + Plan + **Profil** | ✅ | | **S1b+** | Profil-Vorselektion | `ExerciseMatchProfile` × `PlanningTargetProfile` | ✅ `profile_v1` | | **S1c** | Rerank + Begründung | Optional LLM `planning_exercise_search_rank` | Regelbasierte `reasons[]` | | **S2** | Neu-Anlage | Bestehende `suggestExerciseAi` + Pack als Zusatzkontext | Später | Zwischen jeder Stufe: **nur erlaubte `exercise_id`s** (Governance / Sichtbarkeit). --- ## 3. Intent-Typen | `intent_hint` | Bedeutung | Retrieval-Gewichtung (P0) | |---------------|-----------|---------------------------| | `suggest_next` | Nächste Übung (Default bei leerer/kurzer Query) | Progression + Skill-Overlap + Plan-Kontinuität | | `progression_next` | Explizit Graph-Folge | Progression hoch | | `deepen_exercise` | Vertiefung zu Anker-Übung | Skill-Overlap hoch, ähnlicher Fokus | | `continue_plan_goal` | Auf bisherigen Plan aufbauen | Plan-Kontinuität, Wiederholungsstrafe | | `free_search` | Freitext / Stichwort | Volltext hoch | **S1a (später):** Freitext → JSON `{ intent, skill_hints[], requires_partner, level_hint, … }` validiert per Pydantic. **P0:** `intent_hint` vom Client oder Keyword-Heuristik auf `query`. --- ## 4. PlanningExerciseContextPack (S0) Serverseitig aus Request + DB (tokenbewusst für spätere LLM-Stufen): | Feld | Quelle | UI-Chip | |------|--------|---------| | `unit_id`, Titel, `group_id`, Gruppenname | `training_units` + `training_groups` | Gruppe · Einheit | | `section_order_index`, Abschnittstitel | `training_unit_sections` | Abschnitt | | `planned_exercise_ids[]` | Items der Einheit (Reihenfolge) | „N Übungen im Plan“ | | `anchor_exercise_id`, Titel | Request oder letzte Übung vor Einfügepunkt | Anker | | `anchor_skill_ids[]` | `exercise_skills` | (intern) | | `progression_graph_id` | Request oder **Auto-Match** vom Anker (sichtbarer Graph mit passenden Ausgangskanten) | Graph | | `progression_graph_name`, `progression_graph_auto_resolved` | Response `context_summary` | Graph (auto) | | `anchor_exercise_variant_id` | Request / Abschnitt-Item / DB | (intern) | | `progression_successor_ids[]` | `exercise_progression_edges` ab Anker (variantenbewusst, Migration **034**) | (intern) | | `progression_successor_variants` | `to_exercise_variant_id` pro Nachfolger | (intern) | | `group_recent_exercise_ids[]` | Letzte Einheiten derselben Gruppe | Wiederholungsstrafe | | `framework_slot_notes` | Rahmen-Slot falls `framework_slot_id` | (später) | **Berechtigung:** `get_tenant_context` + `_assert_training_unit_permission` wie `GET /training-units/{id}`. --- ## 5. Hybrid-Retrieval (S1b, P0) Kandidaten: sichtbare Übungen (`library_content_visibility_sql`), ohne `archived`, max. ~400 (recent). **Score** (0–1, gewichtet nach Intent): ``` score = w_ft * fulltext_rank + w_prog * progression_hit + w_skill * skill_jaccard(anchor, candidate) + w_plan * plan_affinity + w_profile * profile_match(exercise, target) + w_repeat * (candidate in unit_plan ? -1 : 0) + w_group_repeat * (candidate in group_recent ? -0.5 : 0) ``` **`profile_match`** (0–1): siehe §12–§13 — Katalog-Dimensionen + Skill-Gewichte + Skill-Gap. **`reasons[]`** (regelbasiert, Deutsch): z. B. „Nachfolger im Progressionsgraph“, „Fähigkeiten passen zur Anker-Übung“, „Fokusbereich passend zum Planungsziel“, „Deckt Skill-Lücke im bisherigen Plan“, „Volltext-Treffer“. --- ## 6. API ### `POST /api/planning/exercise-suggest` **Body:** ```json { "unit_id": 123, "section_order_index": 0, "phase_order_index": null, "parallel_stream_order_index": null, "anchor_exercise_id": 456, "anchor_exercise_variant_id": 12, "progression_graph_id": 7, "query": "Schlage mir die nächste Übung vor", "intent_hint": "suggest_next", "limit": 20, "exercise_kind_any": ["simple"] } ``` **Response:** ```json { "context_summary": { "unit_title": "…", "group_name": "…", "section_title": "Hauptteil", "planned_count": 4, "anchor_title": "Partner-Fangspiel" }, "target_profile_summary": { "sources": ["framework_catalog", "current_unit_plan", "anchor_exercise"], "focus_areas": ["Reaktion & Abwehr"], "top_skills": [{ "skill_id": 12, "name": "Reaktionsgeschwindigkeit", "weight": 1.0 }], "has_skill_gap": true }, "retrieval_phase": "profile_v1", "intent_resolved": "suggest_next", "hits": [ { "id": 99, "title": "…", "summary": "…", "score": 0.78, "reasons": ["Nachfolger im Progressionsgraph", "Fokusbereich passend zum Planungsziel"], "focus_area": "…" } ] } ``` **Modul:** `backend/planning_exercise_suggest.py` · `backend/planning_exercise_profiles.py` · Router `backend/routers/planning_exercise_suggest.py` --- ## 7. Frontend | Ort | Verhalten | |-----|-----------| | `ExercisePickerModal` | Prop `planningContext` → Planungs-API statt reiner `listExercises`; Kontext-Chips; `reasons` unter Treffer | | `TrainingUnitEditPage` | `planningContext` aus Einheit + Picker-Ziel (Anker = letzte Übung im Abschnitt) | | **`ExercisesListPageRoot`** | Schalter **„Neu mit KI-Assistent“**: Planungs-KI-Suche (frei, ohne `unit_id`) + Neuanlage im Modal; **„+ Neu“** ausgeblendet | | Rahmen / Kombi-Formular | analog, sobald `unit_id` / Slot-Blueprint bekannt | | Übungsliste (ohne KI-Schalter) | weiter Volltext | **Zweites Suchfeld** im Picker: Query = Volltext + ergänzender Begriff (ODER in P0 als Konkatenation an Backend). --- ## 8. Neu-Anlage (Anbindung, Phase P1) Wenn `hits` leer oder Trainer wählt „Mit KI anlegen“: - `planning_context` im Request-Body → `planning_context_json` in Übungs-Prompts (Migration **085**); Pfad-Builder + Picker ✅ **0.8.208** - Kurzbeschreibung optional leer (freier Vorschlag) oder aus Intent/Skizze --- ## 9. Phasen-Roadmap | Phase | Inhalt | Status | |-------|--------|--------| | **P0** | Context-Pack, Hybrid-Score, API, Picker in Planung | ✅ | | **P0.1** | `ExerciseMatchProfile` / `PlanningTargetProfile`, `profile_v1` | ✅ | | **P1** | Szenario-Pipeline + LLM Query-Intent → Erwartungsprofil | ✅ | | **P2 / B2** | LLM-Rerank bei engem Top-Feld (max. 2 Calls) | ✅ | | **P3** | Skill-Discovery / Framework-Ziele im Pack | 🔲 | | **A** | Voll-Library Hybrid-Ranking | ✅ **0.8.177** | | **B** | Text-Signale guidance/Rahmen-Ziele | ✅ **0.8.181** | | **C1** | Graph auto-match + variantenbewusste Nachfolger | ✅ **0.8.183** | | **C2** | Varianten in Trefferliste / Picker | ✅ **0.8.184** | | **C3** | Graph-Builder (Ziel → Pfad → speichern) | ✅ **0.8.185** | | **E** | Semantik-Schicht + Pfad-QA (Lücken/Brücken/LLM-QS) | ✅ **0.8.186** | | **E2** | Pfad-Neuordnung + KI-Lückenfüller | ✅ **0.8.187** | | **D** | Neu-Anlage: `planning_context` an `suggestExerciseAi` (Migration **085**) | ✅ **0.8.208** | --- ## 10. Changelog - **2026-05-23:** Phase C1 — Graph auto-match, variantenbewusste Nachfolger (`planning_exercise_progression.py`). - **2026-05-23:** Phase B2 — Rerank bei engem Top-Feld; Phase B — Text-Signale; Phase A — Voll-Library (siehe §17–§19). - **2026-05-22:** Erstfassung; P0 API + Planungs-Picker. - **2026-05-22:** P0 implementiert (`planning_exercise_suggest.py`, Router, Picker); unsaved Formular-Plan noch nicht an API (nur persistierte Einheit). - **2026-05-22:** P0.1 — `planning_exercise_profiles.py`, Profil-Score in Hybrid-Retrieval, `retrieval_phase: profile_v1`, `target_profile_summary`. - **2026-05-22:** P2 — LLM-Rerank optional (`include_llm_rank`); Client `planned_exercise_ids[]`; Prompt Migration 072. --- ## 11. Bekannte Lücken & Backlog - **Ungespeicherte Plan-Änderungen:** ✅ Client übergibt `planned_exercise_ids[]` aus Formular (TrainingUnitEditPage). - **Progressionsgraph-ID:** ✅ Auto-Match vom Anker (**C1**); manuelle Auswahl in UI noch offen. - **Anker-Variante:** ✅ Client + DB (**C1**); Picker wählt Variante bei Treffer (**C2** — Dropdown + Graph-Vorschlag). - **Graph-Builder (C3):** Ziel → Pfad vorschlagen → in Graph speichern — ✅ **0.8.185** - **Varianten-Suche:** Library-Picker nutzt `include_variants`; Planungs-KI rankt primär **Übungsebene** — Varianten-Expansion nur gezielt (**C2**). - **Enrichment:** Superadmin-Tool für Skills; Datenqualität der Bibliothek entscheidend für Profil-Score. - **LLM-Intent:** ✅ P1 Szenario-Pipeline + `planning_exercise_search_intent` (Migration 073). - **Preset + LLM:** ✅ Erwartungs-LLM (074) bei Planungsbezug; Preset ohne Plan = kein Erwartungs-LLM. --- ## 16. Szenario-Pipeline & Query-Erwartungsprofil (P1) Komplexe Planungsanfragen brauchen **Schritte vor** dem Profil-Match — nicht jede Query ist gleich. ### 16.1 Szenario-Klassen | `scenario_kind` | Typische Anfrage | LLM Intent? | |-----------------|------------------|-------------| | `preset_next` | „Nächste Übung vorschlagen“ (Preset) | Erwartungs-LLM (074) wenn Planungsbezug | | `progression` | Progressionsgraph / Pfad | Ja (wenn Freitext) | | `deepen` | Vertiefung Anker | Ja | | `continue_plan` | Auf bisherigen Plan aufbauen | Ja | | `additive_constraint` | Plan **+** Zusatz (z. B. Schnellkraft) | Ja | | `free_search` | Offene Stichwortsuche | Ja | **Routing:** `planning_exercise_target_pipeline.classify_planning_scenario()` → `should_run_llm_intent_pipeline()`. ### 16.2 Pipeline (Reihenfolge) ``` S0 Kontext-Pack → Heuristik-Intent + Szenario → [optional] LLM planning_exercise_search_intent → Basis PlanningTargetProfile (Rahmen, Plan, Anker, Gap) → Merge Query-Overlay (Katalog-IDs aus Hints) → Hybrid-Retrieval + Profil-Score → [optional] LLM-Rerank ``` Module: `planning_exercise_target_pipeline.py` · `planning_exercise_intent.py` ### 16.3 API (Erweiterung) | Request | Default | Bedeutung | |---------|---------|-----------| | `include_llm_intent` | `true` | LLM nur wenn Szenario ≠ preset_next und Query nicht leer | | Response | Bedeutung | |----------|-----------| | `scenario_kind` | Szenario-Klasse | | `query_intent_summary` | intent, llm_applied, rationale, skill_hints_resolved | | `intent_heuristic` | Heuristik vor LLM | | `retrieval_phase` | z. B. `profile_v1+query_intent+llm_rank` | **Prompt 073:** `planning_exercise_search_intent` — Ausgabe JSON mit `skill_hints`, `focus_hints`, `emphasis` (`additive`|`replace`). --- ## 15. LLM-Rerank (P2) **Request:** | Feld | Typ | Default | Bedeutung | |------|-----|---------|-----------| | `planned_exercise_ids` | `int[]` | — | Optional: Reihenfolge aus Formular (überschreibt DB-Plan) | | `include_llm_rank` | `bool` | `true` (Client) | Backend gated (B2): Rerank nur bei engem Top-Feld, max. 2 LLM-Calls | **Response:** | Feld | Wert | |------|------| | `retrieval_phase` | `profile_v1` oder `profile_v1+llm_rank` | | `llm_rank_applied` | `true` wenn LLM erfolgreich sortiert hat | | `hits[].llm_rank` | optional: Position nach LLM (1…n) | **Fallback:** Kein API-Key, inaktiver Prompt oder Parse-Fehler → Hybrid-Reihenfolge unverändert, `llm_rank_applied: false`. **Prompt:** Migration **072**, Slug `planning_exercise_search_rank` — Kandidaten als JSON mit Titel, summary, goal (Plaintext), skills; Ausgabe `{ ranked_ids, reasons }`. --- ## 12. ExerciseMatchProfile & PlanningTargetProfile (Phase 1) Ziel: deterministische Vorselektion über **Profil-Dimensionen** statt nur Titel/Jaccard. ### 12.1 ExerciseMatchProfile (pro Übung) | Feld | Quelle | |------|--------| | `focus_area_ids` | `exercise_focus_areas` (Primary = 1.0, sonst 0.85) | | `style_direction_ids` | `exercise_style_directions` | | `training_type_ids` | `exercise_training_types` | | `target_group_ids` | `exercise_target_groups` | | `skill_weights` | `exercise_skills` × Intensitäts-Multiplikator (`skill_scoring._skill_link_multiplier`) | Bulk-Lader: `load_exercise_match_profiles_bulk(cur, exercise_ids)`. ### 12.2 PlanningTargetProfile (Planungsziel) Zusammensetzung aus mehreren Quellen (`sources[]`): | Quelle | Inhalt | |--------|--------| | `framework_catalog` | Fokus/Stil/Trainingsstil/Zielgruppe aus `training_framework_program_*` | | `framework_slot_skill_profile` | Skill-Profil des Slot-Blueprints (`profile_for_occurrences`) | | `framework_overall_skill_profile` | Fallback: alle Blueprint-Einheiten des Rahmens | | `current_unit_plan` | Skill-Profil der bereits eingeplanten Übungen dieser Einheit | | `anchor_exercise` | Katalog + Skills der Anker-Übung (Intent-abhängig) | | `skill_gap_vs_plan` | `target_skills − plan_skills` (normalisiert, Schwelle > 0.08) | Builder: `build_planning_target_profile(cur, unit=…, planned_exercise_ids=…, anchor_exercise_id=…, intent=…)`. Rahmen-Anbindung über `unit.framework_slot_id` oder `origin_framework_slot_id`. --- ## 13. Profil-Score (Formeln) **Gewichtete Überlappung** (Katalog + Skills): ``` overlap(a, b) = Σ min(a[k], b[k]) / Σ max(a[k], b[k]) ``` **Skill-Gap-Abdeckung:** ``` gap_coverage(gap, candidate) = Σ min(gap[k], candidate[k]) / Σ gap[k] ``` **Profil-Score** (intent-gewichtet, Summe Dimensionen = 1.0): ``` profile_score = w_focus * overlap(focus) + w_style * overlap(style) + w_tt * overlap(training_type) + w_tg * overlap(target_group) + w_skill * overlap(skill_weights) + w_gap * gap_coverage(skill_gap) ``` Intent-Gewichte (Auszug): `deepen_exercise` → Skill hoch; `continue_plan_goal` → Gap hoch; `free_search` → Gap + Skill moderat. Scorer: `score_exercise_against_target(exercise_profile, target_profile, intent=…) → (score, reasons[])`. --- ## 14. Hybrid + Profil (P0.1) Im Hybrid-Score kommt **`w_profile * profile_score`** hinzu (Intent-abhängig ~0.15–0.35). Jaccard auf Anker-Skills bleibt parallel (schneller Anker-Fokus). **Response-Felder:** | Feld | Bedeutung | |------|-----------| | `retrieval_phase` | `"profile_v1"` — Phase-1 aktiv, kein LLM-Rerank | | `target_profile_summary` | Lesbare Kurzinfo für UI-Chips (Fokus, Top-Skills, Quellen) | **Phase 2 (P2 / B2):** siehe §15 und §18 — `include_llm_rank: true` vom Client, Backend entscheidet. --- ## 17. Phase A — Voll-Library-Ranking (0.8.177) - Kein OR-Profil-Pool (~500 Übungen) mehr. - Alle sichtbaren Übungen (bis 8000) werden hybrid gescored (`fetch_all_visible_exercise_rows` + `rank_visible_library_hits`). - API: `full_library_ranked: true`, `retrieval_phase` enthält `+full_library+`. --- ## 18. Phase B / B2 — Text-Signale & Rerank-Gates (0.8.181–0.8.182) **B — Text-Signale (`planning_exercise_text_signals.py`):** - `section_guidance_notes`, Rahmen-Ziele/Notizen → Skill-/Katalog-Gewichte ohne LLM. - `requires_partner` aus Intent filtert Kandidaten. - `retrieval_phase +text_signals`. **B2 — Rerank bei unklarem Ranking:** - `hybrid_ranking_ambiguous(hits)` (Top-4-/Top-10-Gap). - Rerank auch nach Erwartungs-/Intent-LLM, wenn Scores eng beieinander. - Budget: max. **2** LLM-Calls (Profil + optional Rerank). --- ## 19. Phase C1 — Progressionsgraph im Planungskontext (0.8.183) **Modul:** `planning_exercise_progression.py` ### Auto-Match Graph Wenn `progression_graph_id` fehlt und Anker-Übung gesetzt: sichtbarer Graph mit passender `next_exercise`-Kante vom Anker (variantenbewusst). Bevorzugung: variantenspezifische Kanten > Anzahl Kanten. ### Variantenbewusste Nachfolger (Migration 034) Generische Kante (`from_exercise_variant_id IS NULL`) gilt für jeden Anker; variantenspezifische Kante nur bei passender Anker-Variante. Treffer: optional `hits[].suggested_variant_id`. ### Request / Response | Feld | Bedeutung | |------|-----------| | `anchor_exercise_variant_id` | Request — Variante der Anker-Übung | | `progression_graph_name` | Response — Name des (auto-)Graphs | | `progression_graph_auto_resolved` | Response — Auto-Match aktiv | --- ## 20. Phase C2 — Varianten in Treffern (0.8.184) ✅ - API: `variants[]`, `suggested_variant_name` pro Treffer (Batch aus `exercise_variants`). - **`ExercisePickerModal`:** Dropdown pro Treffer; Graph-`suggested_variant_id` vorausgewählt; Übernahme setzt `exercise_variant_id`. - **`hydrateExercisePlanningRow`:** übernimmt `exercise_variant_id` / `suggested_variant_id` in die Planungszeile. --- ## 21. Phase C3 — Graph-Builder (0.8.185) ✅ **API:** `POST /api/planning/progression-path-suggest` | Feld | Bedeutung | |------|-----------| | `query` | Ziel / Entwicklungsrichtung (Freitext, min. 3 Zeichen) | | `max_steps` | 2–10, Default 5 | | `progression_graph_id` | optional — Graph-Kontext für Nachfolger ab Schritt 2 | | `include_llm_intent` | LLM nur Schritt 1 (Budget) | **Response:** `steps[]` mit `exercise_id`, `variant_id`, `title`, `reasons`, `variants`; `retrieval_phase: …+path_builder`. **Algorithmus:** Iterativ Hybrid-Ranking — Schritt 1 aus Zielprofil, Folgeschritte mit Anker = letzte Übung, ohne Duplikate. **UI:** `ExerciseProgressionPathBuilder` im Progressionsgraph-Panel — Review, Varianten, `POST …/edges/sequence`. --- ## 22. Phase E — Semantik-Schicht + Pfad-QA (0.8.186) ✅ ### Semantic Brief (`planning_exercise_semantics.py`) Parallel zum Katalog-Overlay — **nicht ersetzend**: | Feld | Bedeutung | |------|-----------| | `primary_topic` | z. B. `mae geri` | | `must_phrases` / `exclude_phrases` | Phrasen-Match in Titel/Ziel/Varianten | | `development_arc` | einstieg → … → perfektion | | `semantic_strength` | 0–1 — steuert dynamisches Blend im Hybrid-Score | | `retrieval_query` | fokussierte Volltext-Query (nicht ganzer Satz) | Optional LLM: Prompt `planning_exercise_query_semantics` (Migration **075**). **Hybrid-Score:** neuer Term `w_semantic * semantic_score` — Profil/Volltext werden bei hoher `semantic_strength` relativ abgeschwächt. ### Pfad-QA (`planning_exercise_path_qa.py`) Nach Pfad-Bildung: 1. **Lücken-Messung** zwischen benachbarten Schritten (Skill-Jaccard + Semantik zum erwarteten Phasen-Segment) 2. **Brücken-Übungen** bei großen Lücken (zusätzliche Schritte, markiert `is_bridge`) 3. **LLM-QS** (Prompt `planning_exercise_path_qa`): Reihenfolge, Themen-Abdeckung, Empfehlungen **API-Erweiterung** `progression-path-suggest`: `include_path_qa`, `include_llm_path_qa` · Response: `semantic_brief_summary`, `path_qa`. **Pfad-Schritte:** Semantic Brief + Entwicklungsphase in **allen** Schritten (nicht nur Schritt 1). ### Phase E2 (0.8.187) - **LLM-QS → Neuordnung:** `ordered_step_indices` im Prompt `planning_exercise_path_qa` (Migration **076**) - **KI-Lückenfüller:** `planning_exercise_path_ai_fill.py` — `is_ai_proposal` wenn Bibliothek keine Brücke liefert - Request: `include_path_reorder`, `include_ai_gap_fill` --- ## 23. Phase E3 (0.8.203) ✅ - Off-Topic aus Pfad entfernen; `gap_fill_offers` mit `goal_for_ai`; voller KI-Call im UI (kein Pre-Vorschlag) - Migration **077** `suggested_new_exercises` im Pfad-QS-Prompt --- ## 24. Phase F — Roadmap-first Progressionsgraph (0.8.204–217) ✅ **Entscheidung:** Progressionsgraph plant **vom Ziel rückwärts** (Roadmap → Stufenspezifikation → Bibliothek/KI). **Keine Gruppenanalyse** — die gehört zur Trainingsplanung. **Ist-Stand (vollständig):** `docs/architecture/PLANNING_PROGRESSION_GRAPH_KI.md` **Spec:** `working/PLANNING_PROGRESSION_ROADMAP_SPEC.md` · **Roadmap:** `docs/architecture/PLANNING_KI_ROADMAP.md` | Teil | Modul / API | |------|-------------| | Pipeline | `planning_progression_roadmap.py` (Workflow-lite) | | Match | `planning_exercise_path_builder.py` — `roadmap_first`, `roadmap_override` | | Skills | `planning_skill_expectations.py` — pro Stufe + Pfad | | Gap-KI | `planning_exercise_form_context.py`, `planning_exercise_path_ai_fill.py` | | Persistenz | `planning_roadmap` JSONB (Migration **088**) | | API | `progression-path-suggest`, `PUT` Graph, `POST …/edges/sequence` | | Prompts | **078/079/087** — Slugs nur in `ai_prompts` | | UI | `ExerciseProgressionPathBuilder`, `ExerciseGapFillPrepModal` | **Graph-Bias:** `progression_graph_id` bevorzugt **bestehende Nachfolger** ab Schritt 2 (Gewicht ~4–10 %), baut aber **keinen** Pfad aus vorhandenen Knoten — siehe Ist-Doku §5. **Mitai Workflow-Engine:** bewusst **nicht** jetzt — Pipeline workflow-ready für spätere Anbindung. --- ## 25. Backlog (offen) Siehe priorisierte Liste in **`docs/architecture/PLANNING_PROGRESSION_GRAPH_KI.md`** §10: 1. UI-Wizard (Progressionsgraph) — separater Chat 2. Graph-Erweiterungsmodus (Start ab Knoten) 3. Trainingsplanung Phase G (Gruppenkontext, `planning_skill_expectations`) 4. Kontext auf allen Pfad-Schritten in der UI 5. Enrichment / Prompt-Feintuning 6. Mitai Workflow-Engine (langfristig)