diff --git a/.claude/docs/PROJECT_STATUS.md b/.claude/docs/PROJECT_STATUS.md
index 3ab8915..209c8fd 100644
--- a/.claude/docs/PROJECT_STATUS.md
+++ b/.claude/docs/PROJECT_STATUS.md
@@ -15,7 +15,7 @@
**Plattform-Rechtstexte (P-01, 0.8.95–0.8.96):** Admin-Editor mit **Abschnitts- und Vollvorschau** (Markdown); fortlaufende Abschnittsnummerierung in der Anzeige/PDF (Darstellung, nicht DB-persistent).
-**Parallel weiter relevant:** **Trainingsplan Phasen & Streams** (Migration **063**, Coach + Planung **0.8.137–0.8.140**; Handover **`docs/HANDOVER.md`** §3); **Trainingsrahmenprogramm** (036–037), **Progressionsgraph** (032–034) — siehe **`TRAINING_FRAMEWORK_SPEC.md`**.
+**Parallel weiter relevant:** **Trainingsplan Phasen & Streams** (Migration **063**, Coach + Planung **0.8.137–0.8.140**; Handover **`docs/HANDOVER.md`** §3); **Trainingsrahmenprogramm** (036–037), **Progressionsgraph** (032–034) — siehe **`TRAINING_FRAMEWORK_SPEC.md`**. **Planungs-KI Progressionsgraph** (Roadmap-first, Auto-Optimierung, Katalog-Kontext **0.8.233**): Ist-Doku **`docs/architecture/PLANNING_PROGRESSION_GRAPH_KI.md`**, Handover **`docs/HANDOVER.md`** §2.8.
**Referenz:** [`library/FEATURES_DELIVERED_2026-Q2.md`](library/FEATURES_DELIVERED_2026-Q2.md) Abschnitt 12 · Medien-Norm: [`technical/MEDIA_ASSETS_AND_ARCHIVE_SPEC.md`](technical/MEDIA_ASSETS_AND_ARCHIVE_SPEC.md) (inkl. **Abschnitt 11 Inline-Medien**, umgesetzt) · **Fachlicher Nutzerüberblick:** [`../../docs/FACHLICHE_NUTZERFUNKTIONEN.md`](../../docs/FACHLICHE_NUTZERFUNKTIONEN.md)
diff --git a/.claude/docs/functional/DOMAIN_MODEL.md b/.claude/docs/functional/DOMAIN_MODEL.md
index 158d784..b240724 100644
--- a/.claude/docs/functional/DOMAIN_MODEL.md
+++ b/.claude/docs/functional/DOMAIN_MODEL.md
@@ -465,6 +465,8 @@ skill_level_definitions (
**Fachliche Grenze aktuell:** Mehrere gleichwertige „Pakete“ paralleler Alternativen sind **modellierbar** (mehrere ausgehende Kanten), aber noch **nicht** über eine dedizierte „Alternativgruppe“ in der UI trivial pflegbar; siehe `technical/TRAINING_FRAMEWORK_SPEC.md` §4.
+**KI-Planung (Workbench, Stand 0.8.233):** Am Graph können Trainer neben Kanten ein **`planning_roadmap`**-Artefakt (Curriculum-Stufen) und **`planning_catalog_context`** (Primärfokus, Stilrichtung, Trainingsstil, Zielgruppe aus den Katalog-Dimensionen §1) pflegen. Die Roadmap-first-Pipeline matcht Übungen pro Stufe; Didaktik und Reihenfolge kommen aus Roadmap + QS, nicht aus Technik-Hardcoding. Technische Details: **`docs/architecture/PLANNING_PROGRESSION_GRAPH_KI.md`**. Für **Trainingsplanung** (Einheit, Abschnitt, Rahmen-Slot) gelten dieselben Katalog- und Retrieval-Bausteine mit anderen Scopes — Phase G, siehe Roadmap **`PLANNING_KI_ROADMAP.md`**.
+
### Trainingsrahmen‑Vorlage (Rahmenprogramm, CURR‑002 Stufe 2 / CURR‑009)
**Abgrenzung:** Eine **einzeilige** Trainingsplan‑Mikrovorlage (`training_plan_template`) strukturiert **eine** Einheit; das **Rahmenprogramm** ist eine **eigene Bibliotheksentität** mit **sortierten Session‑Slots**, **mindestens einem** formulierten **Entwicklungsziel** (Zielliste, **CURR‑011**) und einem **vollständigen Ablauf** pro Slot (**`training_unit_sections` + `training_unit_section_items`** wie bei geplanten Einheiten — **CURR‑010** inhaltlich, technisch seit **037** identisch zur Planungsstruktur). Der persistierte **Progressionsgraph** zwischen Übungen bleibt **optional** (**CURR‑013**).
diff --git a/backend/tests/test_planning_catalog_context.py b/backend/tests/test_planning_catalog_context.py
index f525be6..21d6330 100644
--- a/backend/tests/test_planning_catalog_context.py
+++ b/backend/tests/test_planning_catalog_context.py
@@ -45,3 +45,34 @@ def test_normalize_planning_roadmap_with_catalog_context():
}
)
assert out["planning_catalog_context"]["focus_areas"][0]["id"] == 4
+
+
+def test_multistage_qa_splits_llm_highlights_from_fix_hints():
+ from planning_path_qa_pipeline import run_multistage_path_qa
+
+ result = run_multistage_path_qa(
+ off_topic_steps=[],
+ stripped_off_topic=[
+ {
+ "issue": "roadmap_unfilled",
+ "step_index": 1,
+ "reasons": ["Keine passende Übung"],
+ }
+ ],
+ gaps=[],
+ llm_qa={
+ "overall_ok": True,
+ "quality_score": 0.88,
+ "recommendations": [
+ "Gute didaktische Progression",
+ "Optional: Vertiefung Koordination",
+ ],
+ },
+ llm_applied=True,
+ )
+ hints = result["optimization_hints"]
+ llm_hints = [h for h in hints if h.get("issue") == "llm_recommendation"]
+ fix_hints = [h for h in hints if h.get("issue") != "llm_recommendation"]
+ assert len(llm_hints) >= 2
+ assert any(h.get("issue") == "roadmap_unfilled" for h in fix_hints)
+ assert result["qa_tiers"][2]["recommendations"][0].startswith("Gute didaktische")
diff --git a/docs/HANDOVER.md b/docs/HANDOVER.md
index 06e5daf..b672d48 100644
--- a/docs/HANDOVER.md
+++ b/docs/HANDOVER.md
@@ -1,7 +1,7 @@
# Shinkan Jinkendo – Entwicklungsstand & Handover
-**Stand:** 2026-06-07
-**App-Version / DB-Schema:** App **`0.8.208`** (Planungs-KI Phase D); DB **`20260606086`** — maßgeblich **`backend/version.py`**.
+**Stand:** 2026-05-22
+**App-Version / DB-Schema:** App **`0.8.233`** (Planungs-KI F11–F14, Katalog-Kontext); DB siehe **`backend/version.py`** (`DB_SCHEMA_VERSION`, Migration **088**).
Diese Datei ist die **Einstiegs-Doku für neue Chat-Sessions**: Anforderungen im Detail stehen in `.claude/docs/` (siehe unten); hier der **implementierte Stand**, **Medien-Meilenstein** und **sinnvolle nächste Schritte**.
@@ -89,7 +89,7 @@ Das Schema ist gegenüber dem Code zurück: Migration **`022_skills_schema_compl
- **Varianten:** Speichern in der **Aktionsleiste** persistiert zuerst geänderte Varianten (`persistPendingVariantChanges`), dann Übungs-Stammdaten; „Variante anlegen“ als `type="button"` ohne verschachteltes Formular (`createVariantFromDraft`)
- **Governance (Übungen):** Owner = `created_by`; Bearbeiten = Ersteller, Plattform-Admin oder `can_plan_in_club` bei `visibility=club`; Löschen `club` = nur `club_admin`; Details **`FEATURES_DELIVERED_2026-Q2.md`** §16, **`EXERCISES_API_SPEC.md`** Permissions
-### 2.8 KI Assistenz Übungen & Planungs-KI (Stand **0.8.217**)
+### 2.8 KI Assistenz Übungen & Planungs-KI (Stand **0.8.233**)
**Zentrale Ist-Doku (Progressionsgraph-KI):** **`docs/architecture/PLANNING_PROGRESSION_GRAPH_KI.md`** — bei Drift zuerst dort pflegen.
@@ -108,20 +108,31 @@ Das Schema ist gegenüber dem Code zurück: Migration **`022_skills_schema_compl
| **F7** | `planning_skill_expectations` — Retrieval + UI + Gap | ✅ **0.8.215–216** |
| **F8** | Editierbare `stage_specs` (Belastung, Erfolgskriterien) | ✅ **0.8.216** |
| **F9** | `planning_roadmap` JSONB am Graph (Migration **088**) | ✅ **0.8.217** |
+| **F10** | Stufen-Lernziel-Gate, kein blindes Rank-Fallback | ✅ **0.8.218** |
+| **F11** | Auto-Rematch + Stufen-Spec-Refine + mehrstufige QS | ✅ **0.8.225–0.8.230** |
+| **F12** | Post-Match-Gate, LLM-QA nach Rematch, Gap-Timing, `roadmap_unfilled`-Sync | ✅ **0.8.231–0.8.232** |
+| **F13** | **`planning_catalog_context`** (Fokus/Stil/TT/ZG) im Match + Graph-Artefakt | ✅ **0.8.233** |
+| **F14** | **`ProgressionGraphEditor`** — Slot-UI + Planungskontext-Dropdowns | ✅ **0.8.233** |
-**Architektur (verbindlich):** Progressionsgraph = **Roadmap-first**, **keine Gruppenanalyse**. Bestehender Graph = **leichter Nachfolger-Bias** ab Schritt 2, **kein** automatisches Erweitern ab letztem Knoten (siehe Ist-Doku §5). Trainingsplanung = **eigene Pipeline** (Phase G), wiederverwendet `planning_skill_expectations`.
+**Architektur (verbindlich):** Drei Schichten — (1) **Katalog-Dimensionen** (DB, jetzt im Match verdrahtet), (2) **Technik-Disambiguierung** (Code, nur bei `topic_type=technique`), (3) **Didaktik** (Roadmap + LLM-QS, nicht im Vokabular). Progressionsgraph = **Roadmap-first**, **keine Gruppenanalyse**. Bestehender Graph = **leichter Nachfolger-Bias** ab Schritt 2. Trainingsplanung = **eigene Pipeline** (Phase G) — Wiederverwendung der Bausteine, siehe Ist-Doku §16.
-**Backend-Kern:** `planning_progression_roadmap.py`, `planning_exercise_path_builder.py`, `planning_skill_expectations.py`, `planning_exercise_form_context.py`, `planning_exercise_path_ai_fill.py`, `progression_graph_planning_artifact.py`
+**Validierung (Mae Geri, Härtetest):** Pfad-QS vor Optimierung ~65 % → nach Trainer-Roadmap + KI-Gap-Fill **~88 % OK**. Workbench ist **universell** gedacht; Mae Geri war Referenzfall, kein Sonder-Patch.
-**API:** `POST /api/planning/progression-path-suggest` · `PUT /api/exercise-progression-graphs/:id` (`planning_roadmap`) · `POST …/edges/sequence`
+**Backend-Kern:** `planning_progression_roadmap.py`, `planning_exercise_path_builder.py`, `planning_catalog_context.py`, `planning_path_rematch.py`, `planning_path_refine_stage.py`, `planning_path_qa_pipeline.py`, `planning_skill_expectations.py`, `planning_exercise_form_context.py`, `planning_exercise_path_ai_fill.py`, `progression_graph_planning_artifact.py`
-**Frontend:** `ExerciseProgressionPathBuilder`, `ExerciseGapFillPrepModal`, `planningContextForExerciseAi.js`
+**API:** `POST /api/planning/progression-path-suggest` · `PUT /api/exercise-progression-graphs/:id` (`planning_roadmap`, `planning_catalog_context`) · `POST …/edges/sequence`
+
+**Frontend:** **`ProgressionGraphEditor`** (primäre Workbench), `ExerciseProgressionPathBuilder`, `ExerciseGapFillPrepModal`, `progressionGraphDraft.js`, `planningContextForExerciseAi.js`
**Offen (priorisiert):**
-1. UI-Wizard (Scroll-Monolith → 4 Schritte) — **separater UI-Chat**
-2. Graph-Erweiterungsmodus (Start ab Knoten)
-3. Trainingsplanung Phase G (Gruppenkontext)
-4. Kontext-Anzeige auf allen Pfad-Schritten
+1. Dev-Regression: Gewaltschutz / Breitensport / Kinder (nicht nur Mae Geri)
+2. **PathBuilder-Parität** — gleiche Katalog-Dropdowns wie GraphEditor
+3. QS-UI — positive LLM-Hinweise als Highlights
+4. UI-Wizard (4 Schritte: Ziel → Roadmap → Match → Lücken)
+5. Graph-Erweiterungsmodus (Start ab Knoten)
+6. Phase D′ — Auto KI-Gap-Fill bei persistent leeren Slots
+7. **Trainingsplanung Phase G** — Gruppenkontext-Pack, Scopes `training_section` / `framework_slot` (Ist-Doku §16)
+8. Technik-Katalog konfigurierbar (Backlog)
#### Übungs-KI Formular / Schnellanlage (Stand **0.8.171**)
@@ -256,11 +267,14 @@ Das Schema ist gegenüber dem Code zurück: Migration **`022_skills_schema_compl
### Planungs-KI (priorisiert)
-1. **Phase F2:** LLM für Roadmap (Prompts **078**) + `roadmap_first` Retrieval aus `stage_specs`.
-2. **Phase F4:** Roadmap-Review UI (Major Steps editierbar vor Übungs-Match).
-3. **Enrichment:** Skills/Tags pro Technik (Feinauflösung statt nur Geri Waza).
-4. **D — Neu-Anlage:** `planning_context_json` an `POST /api/exercises/ai/suggest`.
-5. **Trainingsplanung G:** Kontext-Pack Gruppe/Historie — eigene Pipeline (`AI_PLANNING_KI_MULTISTAGE_FORECAST`); Mitai Workflow-Engine erst danach.
+1. **Dev-Regression:** Katalog-Match für Gewaltschutz, Breitensport, Kinder — nicht nur Mae-Geri-Härtetest.
+2. **PathBuilder-Parität:** `planning_catalog_context`-Dropdowns auch in `ExerciseProgressionPathBuilder`.
+3. **QS-UI:** positive LLM-Empfehlungen als Highlights statt nur Optimierungspotenziale.
+4. **UI-Wizard:** 4 Schritte (Ziel & Katalog → Roadmap → Match → Lücken); Backend-Pipeline unverändert.
+5. **Phase D′:** automatisches KI-Gap-Fill bei persistent `roadmap_unfilled`.
+6. **Trainingsplanung G0–G4:** Katalog in Einheits-Editor, Scopes `training_section`/`framework_slot`, Abschnitts-QS, Gruppenkontext-Pack — Details **`PLANNING_PROGRESSION_GRAPH_KI.md`** §16, **`PLANNING_KI_ROADMAP.md`**.
+7. **Technik-Katalog externalisieren** (Backlog): `concept_groups` konfigurierbar statt Code-Tuples.
+8. **Mitai Workflow-Engine** erst nach stabiler Phase G.
### Allgemein
diff --git a/docs/architecture/PLANNING_KI_ROADMAP.md b/docs/architecture/PLANNING_KI_ROADMAP.md
index ee16d23..de73bbf 100644
--- a/docs/architecture/PLANNING_KI_ROADMAP.md
+++ b/docs/architecture/PLANNING_KI_ROADMAP.md
@@ -1,7 +1,7 @@
# Planungs-KI — Produkt-Roadmap
**Stand:** 2026-05-22
-**App-Version:** **0.8.217** — maßgeblich `backend/version.py`
+**App-Version:** **0.8.233** — maßgeblich `backend/version.py`
Diese Roadmap ergänzt die **Architektur-Refaktor-Roadmap** (`UMSETZUNGSPLAN_ROADMAP.md`) und gilt **nur für KI-gestützte Trainingsplanungsunterstützung**.
@@ -13,9 +13,10 @@ Diese Roadmap ergänzt die **Architektur-Refaktor-Roadmap** (`UMSETZUNGSPLAN_ROA
## Strategische Entscheidung (verbindlich)
1. **Progressionsgraph:** Planung **vom Ziel rückwärts** (Roadmap-first), nicht Bibliothek-first.
-2. **Keine Gruppenanalyse** im Graphen — Kontext = Zieltext, Thema, Schrittanzahl, optional Graph-Kanten.
-3. **Trainingsplanung** (Einheit, Rahmen, Abschnitt): eigene Pipeline später, **mit** Gruppenkontext — siehe `AI_PLANNING_KI_MULTISTAGE_FORECAST.md` S0–S4.
-4. **Orchestrierung:** Workflow-**lite** jetzt (`planning_progression_roadmap.py`); Mitai Workflow-Engine **später**, wenn 2–3 Pipelines stabil sind.
+2. **Keine Gruppenanalyse** im Graphen — Kontext = Zieltext, Katalog-Dimensionen, Start/Ziel, Roadmap, optional Graph-Kanten.
+3. **Drei Schichten statt monolithischem Vokabular:** Katalog (DB) · Technik-Disambiguierung (Code, nur bei Technik-Themen) · Didaktik (Roadmap + LLM-QS).
+4. **Trainingsplanung** (Einheit, Rahmen, Abschnitt): eigene Pipeline (Phase G), **mit** Gruppenkontext — siehe `AI_PLANNING_KI_MULTISTAGE_FORECAST.md` S0–S4 und Ist-Doku §16.
+5. **Orchestrierung:** Workflow-**lite** jetzt (`planning_progression_roadmap.py`, `planning_exercise_path_builder.py`); Mitai Workflow-Engine **später**, wenn Phase G stabil ist.
---
@@ -27,84 +28,138 @@ Diese Roadmap ergänzt die **Architektur-Refaktor-Roadmap** (`UMSETZUNGSPLAN_ROA
| A–C2 | Übungssuche | Voll-Library, Graph, Varianten | ✅ |
| C3 | Progressionsgraph | Pfad-Builder (retrieval-first) | ✅ |
| E–E3 | Progressionsgraph | Semantik, QA, Lücken-Angebote | ✅ |
-| **F0–F4** | Progressionsgraph | Roadmap-Pipeline, LLM, roadmap-first, UI Review | ✅ **0.8.204–209** |
+| **F0–F4** | Progressionsgraph | Roadmap-Pipeline, LLM, roadmap_first, UI Review | ✅ **0.8.204–209** |
| **F5–F9** | Progressionsgraph | Start/Ziel, Gap-Prep, Skill-Expectations, Persistenz | ✅ **0.8.210–217** |
+| **F10** | Progressionsgraph | Stufen-Lernziel-Gate, kein blindes Rank-Fallback | ✅ **0.8.218** |
+| **F11–F12** | Progressionsgraph | Auto-Rematch, Spec-Refine, QS-Pipeline-Timing | ✅ **0.8.225–0.8.232** |
+| **F13–F14** | Progressionsgraph | Katalog-Kontext + GraphEditor-Workbench | ✅ **0.8.233** |
| D | Übungs-Neuanlage | `planning_context` an `suggestExerciseAi` | ✅ **0.8.208** |
-| **UX** | Progressionsgraph | Wizard/Stepper statt Scroll-UI | 🔲 |
-| G | Trainingsplanung | Kontext-Pack Gruppe/Historie, S0–S4 | 🔲 |
-| H | Plattform | Mitai-Workflow-Engine (optional) | 🔲 Backlog |
+| **UX** | Progressionsgraph | Wizard/Stepper; PathBuilder-Parität Katalog | 🔲 |
+| **D′** | Progressionsgraph | Auto KI-Gap-Fill bei persistent leeren Slots | 🔲 Backlog |
+| **G** | Trainingsplanung | Kontext-Pack Gruppe/Historie, G0–G4 | 🔲 |
+| **H** | Plattform | Technik-Katalog konfigurierbar; Mitai-Workflow | 🔲 Backlog |
---
-## Phase F — Progressions-Roadmap (aktiver Fokus)
+## Phase F — Progressions-Roadmap (abgeschlossen bis F14)
-### F0 — Foundation (0.8.204)
+Details und Module: **`PLANNING_PROGRESSION_GRAPH_KI.md`**.
-- [x] Spec `PLANNING_PROGRESSION_ROADMAP_SPEC.md`
-- [x] Modul `planning_progression_roadmap.py` (Pydantic, Pipeline-Skeleton)
-- [x] Migration **078** Prompt-Slugs (Zielanalyse, Roadmap)
-- [x] API: `include_roadmap_preview` auf `progression-path-suggest`
-- [x] Doku: HANDOVER, PLANNING_EXERCISE_SUGGEST_CONTEXT, MULTISTAGE_FORECAST
+### F0–F9 — (Kurz, siehe Ist-Doku)
-### F1 — Deterministische Roadmap
+- [x] F0 Foundation (0.8.204) — Spec, Pipeline-Skeleton, Prompts 078
+- [x] F1 Deterministische Roadmap — Phase A/B/C heuristisch
+- [x] F2 LLM Roadmap (0.8.205) — Prompts 078/079
+- [x] F3 roadmap-first (0.8.206) — Match pro `stage_spec`, `roadmap_unfilled`
+- [x] F4 UI Review (0.8.207) — `roadmap_override`, Major Steps editierbar
+- [x] F5 Start/Ziel (0.8.210–214) — Prompt **087**, Zwei-Schritt-UI
+- [x] F6 Gap-KI-Kontext (0.8.212–214) — `ExerciseGapFillPrepModal`
+- [x] F7 Fähigkeiten-Scoring (0.8.215–216) — `planning_skill_expectations`
+- [x] F8 Stufen-Details UI (0.8.216) — editierbare `stage_specs`
+- [x] F9 Persistenz (0.8.217) — Migration **088** `planning_roadmap` JSONB
-- [x] Phase A aus Semantic Brief
-- [x] Phase B: `micro_objectives` aus `development_arc` + Konsolidierung auf N
-- [x] Phase C: heuristische `stage_specs`
-- [ ] pytest für Konsolidierung
+### F10 — Stufen-Qualität (0.8.218)
-### F2 — LLM Roadmap (0.8.205)
+- [x] Stufen-Lernziel-Gate — kein Rank-Fallback ohne Pass
+- [x] Anti-Pattern-Sanitizer, `stage_mismatch` → leerer Slot + Gap
-- [x] Prompts **078/079** in `ai_prompts` — Code nur Slugs (`PROMPT_SLUG_*`)
-- [x] `include_llm_roadmap` + `load_and_render_ai_prompt` + JSON-Validierung
-- [x] Deterministischer Fallback wenn Prompt/OpenRouter fehlt
-- [ ] Response/UI: genutzte `prompt_slugs` sichtbar machen (Admin-Hinweis)
+### F11 — Auto-Optimierung (0.8.225–0.8.230)
-### F3 — roadmap-first (0.8.206)
+- [x] `planning_path_rematch.py` — Rematch-Schleife für `rematch_slot` / `roadmap_unfilled`
+- [x] `planning_path_refine_stage.py` — Spec-Schärfung aus QS
+- [x] `planning_path_qa_pipeline.py` — mehrstufige QS
-- [x] Retrieval pro `major_step` + `stage_spec` statt iterativem Pfad-Bau
-- [x] Gap-Angebote für unbesetzte Roadmap-Stufen (`roadmap_unfilled`)
-- [x] QA/Lücken an Roadmap gekoppelt (`roadmap_first_lite`: keine Brücken/Reorder zwischen Major Steps)
+### F12 — Pipeline-Timing & Sync (0.8.231–0.8.232)
-### F4 — UI (0.8.207)
+- [x] Post-Match-Gate vor Rematch-Akzeptanz
+- [x] LLM Pfad-QS **nach** Rematch
+- [x] Gap-Offers vor `path_qa`-Summary
+- [x] Frontend: `applyMatchStepsToSlots` sync per `majorStepIndex`
-- [x] Roadmap-Review im `ExerciseProgressionPathBuilder`
-- [x] Major Steps editierbar (Phase, Lernziel, Reihenfolge) vor Übungs-Match
-- [x] API `roadmap_only` + `roadmap_override`
+### F13 — Katalog-Kontext (0.8.233)
-### F5 — Start/Ziel (0.8.210–214)
+- [x] `planning_catalog_context.py` — Fokus, Stil, Trainingsstil, Zielgruppe
+- [x] Merge in `PlanningTargetProfile` + Text-Signale
+- [x] Persistenz im Graph-Artefakt
+- [x] Technik-Gates nur bei `topic_type == "technique"`
-- [x] Strukturierte Felder `start_situation`, `target_state`, `roadmap_notes`
-- [x] Prompt **087** `planning_progression_start_target`
-- [x] Priorität: Trainer > KI > Regex (`resolve_roadmap_structured_input`)
-- [x] Zwei-Schritt-UI: „Start/Ziel analysieren“ / „Roadmap vorschlagen“
+### F14 — GraphEditor Workbench (0.8.233)
-### F6 — Gap-KI-Kontext (0.8.212–214)
+- [x] `ProgressionGraphEditor` — primäre UI für Roadmap + Match + Lücken
+- [x] Vier Planungskontext-Dropdowns im Editor
+- [x] `progressionGraphDraft.js` — Artefakt + API-Payload
-- [x] `ExerciseGapFillPrepModal` vor KI-Call
-- [x] `planning_exercise_form_context.py` — Gap-Snapshot, `context_preview`
-- [x] Migration **085** — `planning_context` in Übungs-Prompts
+### Validierung (Referenz Mae Geri, 2026-05)
-### F7 — Fähigkeiten-Scoring (0.8.215–216)
+| Phase | Pfad-QS | Ergebnis |
+|-------|---------|----------|
+| Vor Roadmap/KI | ~65 % | Lücken, falsche Reihenfolge, Off-Topic |
+| Nach Trainer-Roadmap + KI-Gap-Fill | **~88 % OK** | Vollständige Abdeckung; positive LLM-Hinweise |
-- [x] `planning_skill_expectations.py` (Scopes: `progression_stage`, `progression_path`)
-- [x] Pro-Stufe-Retrieval + `path_skill_expectations` + UI-Tags
-- [x] `expected_skills` in Gap-Fill
+**Fazit:** Workbench + Katalog + Roadmap sind universell; Technik-Hardcoding allein reicht für Didaktik nicht.
-### F8 — Stufen-Details UI (0.8.216)
+---
-- [x] Editierbare `stage_specs` in `roadmap_override` (Belastung, Erfolgskriterien, Vermeiden)
+## UX — UI-Überarbeitung (offen)
-### F9 — Persistenz (0.8.217)
+- [ ] Wizard mit 4 Schritten (Ziel & Katalog → Roadmap → Match → Lücken)
+- [ ] Progressive disclosure — Details in Panels
+- [ ] PathBuilder-Parität: gleiche Katalog-Dropdowns wie GraphEditor
+- [ ] QS-UI: positive LLM-Hinweise als Highlights
+- Briefing: `PLANNING_PROGRESSION_GRAPH_KI.md` §12
-- [x] Migration **088** — `planning_roadmap` JSONB am Graph
-- [x] Laden/Speichern über `GET/PUT` Graph + Sequenz-Endpoint
+---
-### UX — UI-Überarbeitung (offen)
+## Phase D′ — Auto Gap-Fill (Backlog)
-- [ ] Wizard mit 4 Schritten (Ziel → Roadmap → Match → Lücken)
-- [ ] Progressive disclosure — Details in Panels, nicht alles gleichzeitig
-- [ ] Briefing: `PLANNING_PROGRESSION_GRAPH_KI.md` §10
+- [ ] Bei persistent `roadmap_unfilled` automatisch KI-Vorschlag vorbereiten (ohne manuelles Modal)
+- [ ] Governance: Trainer bestätigt vor Persistenz
+
+---
+
+## Phase G — Trainingsplanung (komplexere Domäne)
+
+**Ziel:** Einheiten, Rahmen-Slots, Abschnitte und parallele Streams KI-gestützt planen — **ohne** zweite Retrieval-Welt.
+
+### Wiederverwendung aus Progressionsgraph
+
+| Baustein | Progressionsgraph | Trainingsplanung |
+|----------|-------------------|------------------|
+| `PlanningTargetProfile` | Curriculum-Query + Katalog | Einheit + Abschnitt + Slot + Katalog + Historie |
+| `planning_catalog_context` | Am Graph gespeichert | Pro Einheit / Slot / Voreinstellung |
+| `planning_skill_expectations` | `progression_stage`, `progression_path` | **`training_section`**, **`framework_slot`** |
+| `planning_exercise_retrieval` | Roadmap-Stufen-Match | `suggest_planning_exercises` — **bereits produktiv** |
+| `planning_path_qa_pipeline` | Curriculum-QS | Abschnitts-QS (Kohärenz, Streams) |
+| `planning_exercise_form_context` | Pfad-Lücken | Abschnitts-/Slot-Lücken |
+| Roadmap-Pipeline | Major Steps über Wochen | **Nicht 1:1** — Phasen/Streams + Vorlagen |
+
+### Was Phase G neu braucht
+
+- Gruppen-/Historie-Kontext-Pack (`AI_PLANNING_KI_MULTISTAGE_FORECAST` S0–S4)
+- Abschnitts-Didaktik — Dauer, Parallel-Streams, Coaching
+- Rahmen-Blueprint-Anbindung (`training_framework_programs`, Slot-Blueprints)
+- Eigene Orchestrierung pro Einheit (kein Curriculum über N Wochen)
+
+### Integrations-Reihenfolge G0–G4
+
+| Schritt | Inhalt | Abhängigkeit |
+|---------|--------|--------------|
+| **G0** | Katalog in Einheits-Editor → bestehende Suggest-Pipeline | F13 ✅ |
+| **G1** | Scope `training_section` + Skill-Erwartungen aktiv | F7 ✅ |
+| **G2** | Abschnitts-QS (Hint-Struktur wie Graph) | F11–F12 ✅ |
+| **G3** | Framework-Slot + Gap-Fill | G0, G1 |
+| **G4** | Gruppenkontext-Pack | G0–G3 |
+
+**Nicht:** Roadmap-first-Loop 1:1 auf Trainingseinheit mappen.
+
+Details: **`PLANNING_PROGRESSION_GRAPH_KI.md`** §16 · Domäne **`DOMAIN_MODEL.md`** §1–2.
+
+---
+
+## Phase H — Plattform (Backlog)
+
+- [ ] Technik-Disambiguierung konfigurierbar (DB statt `_GERI_TECHNIQUES` in Code)
+- [ ] Mitai Workflow-Engine — erst wenn G0–G4 stabil
---
@@ -112,10 +167,10 @@ Diese Roadmap ergänzt die **Architektur-Refaktor-Roadmap** (`UMSETZUNGSPLAN_ROA
| Von | Nach | Hinweis |
|-----|------|---------|
-| F2 | Enrichment / Skills | Bessere Roadmap bei technikspezifischen Skills |
-| F3 | F2 | LLM-Roadmap oder stabile heuristische B |
-| G | F4 | Trainingsplanung kann Roadmap aus Graph referenzieren |
-| H | G + F4 | Workflow-Engine lohnt bei verzweigten Planungsflows |
+| F13 | G0 | Katalog-Kontext in Einheitsplanung |
+| F7, F11 | G1, G2 | Skill-Expectations + QS-Muster |
+| F4, F9 | G3 | Graph-Roadmap kann Rahmen referenzieren |
+| G | H | Workflow-Engine lohnt bei verzweigten Planungsflows |
---
diff --git a/docs/architecture/PLANNING_PROGRESSION_GRAPH_KI.md b/docs/architecture/PLANNING_PROGRESSION_GRAPH_KI.md
index 5b2df2d..55d2c9b 100644
--- a/docs/architecture/PLANNING_PROGRESSION_GRAPH_KI.md
+++ b/docs/architecture/PLANNING_PROGRESSION_GRAPH_KI.md
@@ -1,7 +1,7 @@
# Progressionsgraph — KI-Planung (Ist-Stand)
-**Stand:** 2026-05-22 (Dokumentation) · **App-Version:** **0.8.218** · **DB:** Migration **088**
-**Maßgeblich für Code:** `backend/version.py` (`APP_VERSION`, `DB_SCHEMA_VERSION`)
+**Stand:** 2026-05-22 (Dokumentation) · **App-Version:** **0.8.233** · **DB:** Migration **088**
+**Maßgeblich für Code:** `backend/version.py` (`APP_VERSION`, `DB_SCHEMA_VERSION`, `MODULE_VERSIONS.planning_exercise_suggest`)
> **Diese Datei ist die zentrale Referenz** für die KI-gestützte Planung im Progressionsgraph.
> Ältere Abschnitte in `HANDOVER.md` §2.8 und `PLANNING_KI_ROADMAP.md` verweisen hierher.
@@ -30,19 +30,20 @@
## 2. Trainer-Workflow (UI)
-Aktuell in `ExerciseProgressionPathBuilder.jsx` (eingebettet in `ExerciseProgressionGraphPanel.jsx`):
+**Primär:** `ProgressionGraphEditor.jsx` (integrierter Slot-Editor, Phase B).
+**Legacy/Parallel:** `ExerciseProgressionPathBuilder.jsx` (Scroll-Monolith — gleiche API, Katalog-Kontext-Dropdowns dort noch nachziehen).
```
-① Ziel eingeben (+ optional Start/Ziel-Felder manuell)
-② „Start/Ziel analysieren“ (optional, start_target_only)
-③ „Roadmap vorschlagen“ (roadmap_only, LLM-Roadmap)
+① Ziel eingeben (+ Planungskontext: Primärfokus, Stil, Trainingsstil, Zielgruppe)
+② Optional: Start/Ziel-Felder manuell oder „Start/Ziel analysieren“
+③ „Roadmap generieren“ (roadmap_only, LLM-Roadmap)
④ Roadmap bearbeiten (Major Steps + Stufen-Details)
-⑤ „Übungen matchen“ (roadmap_first + roadmap_override)
-⑥ Lücken mit KI schließen (gap_fill_offers + Vorbereitungs-Dialog)
-⑦ „Pfad in Graph speichern“ (Sequenz-Kanten)
+⑤ „Übungen matchen“ (roadmap_first + roadmap_override + Auto-QS/Rematch)
+⑥ Lücken: KI-Angebote → „KI anlegen“ (Gap-Prep-Modal) → in Slot
+⑦ „Graph speichern“ (planning_roadmap + optional Kanten-Sequenz)
```
-**Bekannte UX-Schuld:** Alle Schritte liegen auf **einer langen Scroll-Seite** — Überarbeitung als Wizard/Stepper ist geplant (separater UI-Chat). Briefing-Vorlage siehe unten §10.
+**Bekannte UX-Schuld:** PathBuilder = lange Scroll-Seite; GraphEditor = kompakter, aber noch kein Wizard. Stepper geplant (separater UI-Chat). Briefing §12.
---
@@ -51,6 +52,7 @@ Aktuell in `ExerciseProgressionPathBuilder.jsx` (eingebettet in `ExerciseProgres
```mermaid
flowchart TB
subgraph ui [Frontend]
+ PGE[ProgressionGraphEditor]
EPB[ExerciseProgressionPathBuilder]
GFM[ExerciseGapFillPrepModal]
PCtx[planningContextForExerciseAi.js]
@@ -71,6 +73,10 @@ flowchart TB
subgraph match [Match + QA]
PB[planning_exercise_path_builder.py]
+ PCC[planning_catalog_context.py]
+ REM[planning_path_rematch.py]
+ REF[planning_path_refine_stage.py]
+ QAP[planning_path_qa_pipeline.py]
RET[planning_exercise_retrieval.py]
PG[planning_exercise_progression.py]
SEM[planning_exercise_semantics.py]
@@ -88,11 +94,16 @@ flowchart TB
end
EPB --> PPS
- EPB --> SEQ
- EPB --> PUT
+ PGE --> PPS
+ PGE --> SEQ
+ PGE --> PUT
GFM --> EAI
PPS --> PR
PPS --> PB
+ PB --> PCC
+ PB --> REM
+ PB --> REF
+ PB --> QAP
PB --> RET
PB --> PG
PB --> PSE
@@ -108,12 +119,18 @@ flowchart TB
| Modul | Aufgabe |
|--------|---------|
| `planning_progression_roadmap.py` | Phasen A–C: Zielanalyse, Roadmap, `stage_specs`; Start/Ziel-Auflösung (Trainer > KI > Regex) |
-| `planning_exercise_path_builder.py` | `suggest_progression_path`: roadmap_first Match, QA, Gap-Offers |
+| `planning_exercise_path_builder.py` | `suggest_progression_path`: roadmap_first Match, Auto-QS, Rematch, Gap-Offers |
+| `planning_catalog_context.py` | **Expliziter Katalog-Kontext** (Fokus, Stil, Trainingsstil, Zielgruppe) → `PlanningTargetProfile` |
+| `planning_path_rematch.py` | Auto-Rematch betroffener Slots (`max_rematch_rounds`) |
+| `planning_path_refine_stage.py` | Stufen-Spec-Verfeinerung bei `stage_mismatch` (Phase C) |
+| `planning_path_qa_pipeline.py` | Mehrstufige QS → `optimization_hints` |
| `planning_exercise_progression.py` | Graph auflösen, Nachfolger-Kanten für Retrieval-Bias |
| `planning_skill_expectations.py` | Skill-Erwartungen pro Scope (`progression_stage`, `progression_path`, später `training_section`) |
| `planning_exercise_form_context.py` | `planning_context` / Gap-Snapshot für Übungs-KI |
| `planning_exercise_path_ai_fill.py` | Gap-Fill-Angebote, `goal_for_ai`, `context_preview` |
| `progression_graph_planning_artifact.py` | Validierung `planning_roadmap` JSON (Schema v1, max. 64 KB) |
+| `planning_exercise_profiles.py` | **Katalog-Scoring** (Fokus/Stil/TT/ZG/Skills) — gemeinsam mit Einheitsplanung |
+| `planning_exercise_target_pipeline.py` | Query-Intent-Pipeline — Progressionsgraph nutzt `query_only`-Modus + Katalog-Overlay |
---
@@ -131,10 +148,14 @@ flowchart TB
| `start_target_only` | bool | Nur Start/Ziel-Analyse |
| `roadmap_override` | object | Trainer-bearbeitete `major_steps` + `stage_specs` |
| `start_situation`, `target_state`, `roadmap_notes` | string? | Strukturierte Eingabe (Priorität vor KI) |
+| `planning_catalog_context` | object? | Primärfokus, Stilrichtung, Trainingsstil, Zielgruppe (IDs + `is_primary`) |
| `include_llm_start_target` | bool | LLM-Extraktion Start/Ziel (Prompt **087**) |
| `include_llm_roadmap` | bool | LLM Roadmap (Prompts **078/079**) |
-| `include_llm_intent` | bool | LLM Intent für Semantic Brief (Roadmap-Vorschlag: **true** seit 0.8.217) |
-| `include_path_qa`, `include_ai_gap_fill` | bool | QS, Lücken-Angebote |
+| `include_llm_intent` | bool | LLM Intent für Semantic Brief |
+| `auto_rematch_after_qa` | bool | Auto-Rematch nach QS (Default **true**) |
+| `auto_refine_stage_spec` | bool | Stufen-Spec bei `stage_mismatch` schärfen (Default **true**) |
+| `max_rematch_rounds` | int | Rematch-Runden 0–4 (Default **3**) |
+| `include_path_qa`, `include_llm_path_qa`, `include_ai_gap_fill` | bool | QS, LLM-Ganzpfad, Lücken-Angebote |
### 4.2 Wichtige Response-Felder
@@ -144,7 +165,27 @@ flowchart TB
| `steps[]` | Gematchte Übungen; pro Schritt u. a. `roadmap_*`, `skill_expectations` |
| `path_skill_expectations` | Pfadweite Skill-Erwartungen |
| `gap_fill_offers[]` | Lücken mit `context_preview`, `goal_for_ai` |
-| `path_qa` | QS inkl. `roadmap_qa_mode: roadmap_first_lite` |
+| `path_qa` | QS inkl. `qa_tiers`, `optimization_hints`, `rematch_log`, `refine_log` |
+| `target_profile_summary` | Erwartungsprofil inkl. Katalog-Dimensionen (nach Match) |
+| `match_summary` | `library_matches`, `gap_fill_offer_count`, `roadmap_unfilled_count` |
+
+---
+
+## 4.4 Planungskontext — Katalog vs. Technik-Vokabular
+
+Shinkan unterscheidet **drei Schichten** (kein monolithisches „Vokabular“):
+
+| Schicht | Was | Wo | Beispiel |
+|---------|-----|-----|----------|
+| **Katalog-Dimensionen** | Was für Training? | DB: `focus_areas`, `style_directions`, `training_types`, `target_groups`, `skills` | Gewaltschutz, Breitensport, Shotokan |
+| **Disambiguierung (Technik)** | Verwechslungs-Nachbarn | Code: `planning_exercise_semantics.py` (`_GERI_TECHNIQUES`, …) | Mae Geri ≠ Mawashi Geri |
+| **Didaktik / Kausalität** | Reihenfolge, Lernphasen | Roadmap + LLM Pfad-QS | Grundlagen vor Geschwindigkeit |
+
+**Seit 0.8.233:** `planning_catalog_context` im Request und im Graph-Artefakt (`planning_catalog_context` JSON). Fließt in `PlanningTargetProfile` → Hybrid-Retrieval (`score_exercise_against_target`: „Fokusbereich passend“, …). Zusätzlich additive Text-Signale aus Anfrage + Start/Ziel + Notizen (`planning_exercise_text_signals`).
+
+**Technik-Gates** (`technique_scope`, Geschwister-Ausschluss) nur bei `topic_type == "technique"` — Fokus-Pfade (Gewaltschutz, Fitness, …) werden nicht wie Mae-Geri-Pfade behandelt.
+
+Fallback: fehlt `planning_catalog_context` im Request, wird aus gespeichertem `planning_roadmap` am Graph geladen.
### 4.3 Prompt-Slugs (nur in `ai_prompts`, nie Hardcoding)
@@ -157,17 +198,32 @@ flowchart TB
---
-## 5. Roadmap-Match — Stufen-Qualität (0.8.218)
+## 5. Roadmap-Match — Stufen-Qualität (0.8.218–0.8.233)
Pro Major Step gilt:
-1. **Stufen-Brief** — `semantic_brief_for_stage()` ergänzt `must_phrases` um das Stufen-Lernziel.
-2. **Stufen-Gate** — `exercise_passes_stage_learning_goal_gate()` prüft Lernziel-Text in Titel/Summary/Ziel oder Mindest-`semantic_score`.
-3. **Kein Fallback** — Bei `roadmap_first` wird **nicht** auf die globale `goal_query` zurückgefallen; passt keine Übung → **Lücke** (`roadmap_unfilled`) statt themenfremder Übung.
-4. **Retrieval** — Bonus/Strafe im Hybrid-Score je nach Stufen-Passung.
-5. **QS** — `detect_off_topic_steps` erkennt `stage_mismatch` anhand `roadmap_learning_goal`.
+1. **Stufen-Brief** — `build_stage_match_brief()` aus Lernziel, `anti_patterns`, Erfolgskriterien, Pfad-Kontext.
+2. **Stufen-Gate** — `exercise_passes_stage_fit()` / `exercise_passes_stage_learning_goal_gate()` auf vollem Übungstext.
+3. **Kein blindes Rank-Fallback** — ohne Gate-Passung → `roadmap_unfilled`, nicht themenfremde Übung.
+4. **Post-Match-Gate** — `_roadmap_step_passes_post_match_gate()` = gleiche QS wie `detect_off_topic_steps` (kein Rematch-Treffer, der sofort wieder `stage_mismatch` wäre).
+5. **Retrieval** — Hybrid-Score: Volltext + Semantik + **Profil/Katalog** + Skill-Erwartungen + optional Graph-Bias.
+6. **Auto-Optimierung (ein Match-Lauf):**
+ - **Phase B:** Rematch-Schleife (`planning_path_rematch.py`) für `rematch_slot` / `roadmap_unfilled`
+ - **Phase C:** `planning_path_refine_stage.py` — `anti_patterns` / Erfolgskriterien aus QS
+ - Purge persistent `stage_mismatch` → Slot leeren + KI-Gap
+ - LLM Pfad-QS **nach** Rematch auf finalem Pfad
+ - Gap-Offers für alle leeren Slots **vor** `path_qa`-Summary
-Tests: `test_planning_roadmap_stage_match.py`
+Tests: `test_planning_roadmap_stage_match.py`, `test_planning_path_rematch.py`, `test_planning_path_refine_stage.py`, `test_planning_catalog_context.py`
+
+### Referenz-Validierung (Mae Geri, 2026-05)
+
+| Phase | Pfad-QS | Ergebnis |
+|-------|---------|----------|
+| Vor Roadmap/KI-Anpassung | ~65 % | Strukturelle Lücken (Grundlagen, Reihenfolge, Zielgenauigkeit) |
+| Nach Trainer-Roadmap + KI-Angebote in leeren Slots | **~88 % OK** | Vollständige Curriculum-Abdeckung; positive LLM-Empfehlungen |
+
+**Lesson:** Workbench + Katalog-Kontext + Roadmap sind der Hebel; Technik-Hardcoding allein reicht nicht für Didaktik.
---
@@ -209,7 +265,15 @@ Gespeichert am **Graph-Container** (`exercise_progression_graphs`), Schema v1:
"roadmap_notes": "…",
"max_steps": 5,
"progression_roadmap": { },
- "path_skill_expectations": { }
+ "path_skill_expectations": { },
+ "planning_catalog_context": {
+ "focus_areas": [{ "id": 1, "is_primary": true }],
+ "style_directions": [],
+ "training_types": [{ "id": 2, "is_primary": true }],
+ "target_groups": []
+ },
+ "slot_contents": [ ],
+ "last_findings": { }
}
```
@@ -307,26 +371,73 @@ Kontext-Helfer: `frontend/src/utils/planningContextForExerciseAi.js`
| F7 | `planning_skill_expectations` (Retrieval + UI + Gap) | ✅ | 0.8.215–216 |
| F8 | Editierbare `stage_specs` in UI | ✅ | 0.8.216 |
| F9 | `planning_roadmap` Persistenz (Migration **088**) | ✅ | 0.8.217 |
-| F10 | Stufen-Lernziel-Gate beim Match (kein goal_query-Fallback) | ✅ | 0.8.218 |
-| **G** | Trainingsplanung eigene Pipeline + Graph-Referenz | 🔲 | — |
-| **UX** | Wizard/Stepper statt Scroll-Monolith | 🔲 | separater Chat |
+| F10 | Stufen-Lernziel-Gate + kein goal_query-Fallback | ✅ | 0.8.218 |
+| **F11** | Auto-Rematch + Stufen-Spec-Refine + mehrstufige QS | ✅ | 0.8.225–0.8.230 |
+| **F12** | Post-Match-Gate, LLM-QA nach Rematch, Gap-Timing, `roadmap_unfilled`-Sync | ✅ | 0.8.231–0.8.232 |
+| **F13** | **Katalog-Kontext** (`planning_catalog_context`) im Match + Graph-Artefakt | ✅ | **0.8.233** |
+| **F14** | `ProgressionGraphEditor` Slot-UI + Planungskontext-Dropdowns | ✅ | 0.8.233 |
+| **G** | Trainingsplanung: eigene Pipeline + Wiederverwendung Bausteine (§16) | 🔲 | — |
+| **UX** | Wizard/Stepper; PathBuilder-Parität Katalog | 🔲 | — |
+| **H** | Technik-Disambiguierung konfigurierbar (DB statt Code-Tuples) | 🔲 | Backlog |
+| **D′** | Auto Gap-Fill (KI generiert bei persistent `roadmap_unfilled`) | 🔲 | Backlog |
---
## 12. Offenes Backlog (priorisiert)
-1. **UI-Überarbeitung** — Wizard mit 4 Schritten, progressive disclosure (Briefing unten)
-2. **Graph-Erweiterungsmodus** — Start ab gewähltem Knoten / letzter Sequenz
-3. **Kontext auf allen Pfad-Schritten** in UI (nicht nur Lücken)
-4. **Trainingsplanung Phase G** — Pipeline mit Gruppenkontext, Wiederverwendung `planning_skill_expectations`
-5. Enrichment / Prompt-Feintuning
-6. Mitai Workflow-Engine (langfristig)
+1. **Dev-Regression:** Gewaltschutz + Breitensport + Kinder (ohne Mae Geri) — Katalog-Match verifizieren
+2. **PathBuilder-Parität** — gleiche `planning_catalog_context`-Dropdowns in `ExerciseProgressionPathBuilder`
+3. **QS-UI** — positive LLM-Hinweise als „Highlights“, nicht als „Optimierungspotenziale“
+4. **UI-Wizard** — 4 Schritte (Ziel → Roadmap → Match → Lücken); Backend unverändert
+5. **Graph-Erweiterungsmodus** — Start ab gewähltem Knoten / letzter Sequenz
+6. **Phase D′** — automatisches KI-Gap-Fill bei persistent leeren Slots
+7. **Trainingsplanung Phase G** — siehe §16
+8. **Technik-Katalog externalisieren** — konfigurierbare `concept_groups` (Backlog)
+9. Graph-Metadaten: Primärfokus/Stil als Spalten (Reporting)
+10. Mitai Workflow-Engine (langfristig)
-### Briefing-Vorlage UI-Chat (Copy-Paste)
+### Briefing-Vorlage UI-Chat
-Siehe Nutzer-Chat 2026-05-22 oder `HANDOVER.md` §2.8 — Abschnitt „UI-Überarbeitung“.
+Kern: Wizard ① Ziel & Planungskontext → ② Roadmap → ③ Match → ④ Lücken & Speichern; Backend-Pipeline unverändert lassen.
-Kern: Wizard ① Ziel & Start/Ziel → ② Roadmap → ③ Match → ④ Lücken & Speichern; Backend-Pipeline unverändert lassen.
+---
+
+## 16. Wiederverwendung in der Trainingsplanung (Phase G)
+
+Die **komplexere Trainingsplanung** (Einheit, Rahmen-Slot, Abschnitt, parallele Streams) soll **keine zweite Retrieval-Welt** bauen, sondern bestehende Module mit **anderem Kontext-Pack** nutzen.
+
+### 16.1 Was Progressionsgraph liefert (Workbench-Muster)
+
+| Baustein | Progressionsgraph | Trainingsplanung (Ziel) |
+|----------|-------------------|-------------------------|
+| `PlanningTargetProfile` | Query + Katalog + Skills | Einheit + Abschnitt + Slot + Katalog + Historie |
+| `planning_catalog_context` | Am Graph gespeichert | Pro Einheit / Slot / Trainer-Voreinstellung |
+| `planning_skill_expectations` | `progression_stage` / `progression_path` | **`training_section`**, **`framework_slot`** |
+| `planning_exercise_retrieval` | Roadmap-Stufen-Match | Abschnitts-Suche (`suggest_planning_exercises`) — **produktiv** |
+| `planning_path_qa_pipeline` | Curriculum-QS | Abschnitts-QS (Kohärenz, Streams) |
+| `planning_intent_context` | Pfad-Ausschlüsse → Stufen | Abschnitts-Guidance → Brief |
+| `planning_exercise_form_context` | Pfad-Lücken | Abschnitts-/Slot-Lücken |
+| Roadmap-Pipeline | Curriculum Major Steps | **Nicht 1:1** — Phasen/Streams + Vorlagen |
+| Technik-Disambiguierung | bei `topic_type=technique` | nur bei explizitem Technik-Abschnitt |
+
+### 16.2 Was Phase G neu braucht
+
+- **Gruppen-/Historie-Kontext-Pack** (`AI_PLANNING_KI_MULTISTAGE_FORECAST` S0–S4)
+- **Abschnitts-Didaktik** — Dauer, Parallel-Streams, Coaching (`training_unit_phases`)
+- **Rahmen-Blueprint** — bereits `training_framework_programs` / Slot-Blueprints
+- **Eigene Orchestrierung** pro Einheit — kein Curriculum über N Wochen
+
+### 16.3 Integrations-Reihenfolge (Phase G)
+
+1. **G0** — Katalog in Einheits-Editor → bestehende Suggest-Pipeline
+2. **G1** — Scope `training_section` + Skill-Erwartungen aktiv
+3. **G2** — Abschnitts-QS (Hint-Struktur wie Graph)
+4. **G3** — Framework-Slot + Gap-Fill
+5. **G4** — Gruppenkontext-Pack
+
+**Nicht:** Roadmap-first-Loop 1:1 auf Trainingseinheit mappen.
+
+Domänenbezug: **`DOMAIN_MODEL.md`** §1–2 (Katalog-Dimensionen).
---
@@ -342,6 +453,10 @@ Kern: Wizard ① Ziel & Start/Ziel → ② Roadmap → ③ Match → ④ Lücken
| `test_planning_exercise_form_context.py` | `planning_context`, Gap-Snapshot |
| `test_progression_graph_planning_artifact.py` | JSONB-Artefakt-Validierung |
| `test_planning_exercise_progression.py` | Graph-Auflösung, Nachfolger |
+| `test_planning_path_rematch.py` | Auto-Rematch, unfilled-Platzhalter |
+| `test_planning_path_refine_stage.py` | Stufen-Spec-Refine |
+| `test_planning_stage_anti_patterns.py` | Anti-Pattern-Sanitizer, Stufen-Gate |
+| `test_planning_catalog_context.py` | Katalog-Kontext → Target-Profil |
---
@@ -366,3 +481,4 @@ Kern: Wizard ① Ziel & Start/Ziel → ② Roadmap → ③ Match → ④ Lücken
| Datum | Änderung |
|-------|----------|
| 2026-05-22 | Erstfassung Ist-Stand 0.8.217 — zentrale Referenz nach F5–F9 |
+| 2026-05-22 | F11–F14: Auto-Optimierung, Katalog-Kontext, GraphEditor, Mae-Geri-Validierung, Phase-G-Wiederverwendung §16 |
diff --git a/frontend/src/components/ExerciseProgressionPathBuilder.jsx b/frontend/src/components/ExerciseProgressionPathBuilder.jsx
index 9c83c04..f06c61d 100644
--- a/frontend/src/components/ExerciseProgressionPathBuilder.jsx
+++ b/frontend/src/components/ExerciseProgressionPathBuilder.jsx
@@ -7,6 +7,16 @@ import api from '../utils/api'
import ExerciseAiQuickCreateModal from './exercises/ExerciseAiQuickCreateModal'
import ExerciseGapFillPrepModal from './exercises/ExerciseGapFillPrepModal'
import ExerciseAiSuggestPreviewModal from './ExerciseAiSuggestPreviewModal'
+import PlanningCatalogContextFields from './PlanningCatalogContextFields'
+import {
+ EMPTY_PLANNING_CATALOG_CONTEXT,
+ parsePlanningCatalogContextFromArtifact,
+ planningCatalogContextToApi,
+ pathQaQualityPercent,
+ pathQaShowsStrongResult,
+ setCatalogSelectItems,
+ splitPathQaHints,
+} from '../utils/progressionGraphDraft'
import {
aiPreviewToQuickCreateDraft,
buildQuickCreateAiPreview,
@@ -449,9 +459,13 @@ function buildPlanningRoadmapArtifactSnapshot({
maxSteps,
progressionRoadmap,
pathSkillExpectations,
+ planningCatalogContext,
}) {
const q = (goalQuery || '').trim()
if (!q && !progressionRoadmap) return null
+ const catalogPayload = planningCatalogContextToApi(
+ planningCatalogContext || EMPTY_PLANNING_CATALOG_CONTEXT,
+ )
return {
schema_version: PLANNING_ARTIFACT_SCHEMA,
goal_query: q,
@@ -461,6 +475,9 @@ function buildPlanningRoadmapArtifactSnapshot({
max_steps: Number(maxSteps) || 5,
progression_roadmap: progressionRoadmap || null,
path_skill_expectations: pathSkillExpectations || null,
+ ...(catalogPayload.planning_catalog_context
+ ? { planning_catalog_context: catalogPayload.planning_catalog_context }
+ : {}),
}
}
@@ -544,6 +561,12 @@ export default function ExerciseProgressionPathBuilder({
const [startTargetAnalyzed, setStartTargetAnalyzed] = useState(false)
const loading = loadingRoadmap || loadingStartTarget || loadingMatch
const [focusAreas, setFocusAreas] = useState([])
+ const [styleDirections, setStyleDirections] = useState([])
+ const [trainingTypes, setTrainingTypes] = useState([])
+ const [targetGroups, setTargetGroups] = useState([])
+ const [planningCatalogContext, setPlanningCatalogContext] = useState(() => ({
+ ...EMPTY_PLANNING_CATALOG_CONTEXT,
+ }))
const [skillsCatalog, setSkillsCatalog] = useState([])
const [generatingOfferId, setGeneratingOfferId] = useState(null)
@@ -571,6 +594,22 @@ export default function ExerciseProgressionPathBuilder({
[editableMajorSteps, pathSteps],
)
+ const catalogApiPayload = useMemo(
+ () => planningCatalogContextToApi(planningCatalogContext),
+ [planningCatalogContext],
+ )
+
+ const pathQaSplit = useMemo(() => splitPathQaHints(pathQa), [pathQa])
+ const pathQaHighlights = pathQaSplit.highlightTexts
+ const pathQaFixHints = pathQaSplit.fixHints
+
+ const patchCatalogDimension = useCallback((key, value) => {
+ setPlanningCatalogContext((prev) => ({
+ ...prev,
+ [key]: setCatalogSelectItems(prev?.[key], value),
+ }))
+ }, [])
+
const buildPlanningArtifact = useCallback(
() =>
buildPlanningRoadmapArtifactSnapshot({
@@ -581,6 +620,7 @@ export default function ExerciseProgressionPathBuilder({
maxSteps,
progressionRoadmap,
pathSkillExpectations,
+ planningCatalogContext,
}),
[
goalQuery,
@@ -590,6 +630,7 @@ export default function ExerciseProgressionPathBuilder({
maxSteps,
progressionRoadmap,
pathSkillExpectations,
+ planningCatalogContext,
],
)
@@ -634,6 +675,9 @@ export default function ExerciseProgressionPathBuilder({
if (art.roadmap_notes) setRoadmapNotes(String(art.roadmap_notes))
if (art.max_steps) setMaxSteps(Number(art.max_steps))
if (art.path_skill_expectations) setPathSkillExpectations(art.path_skill_expectations)
+ if (art.planning_catalog_context) {
+ setPlanningCatalogContext(parsePlanningCatalogContextFromArtifact(art))
+ }
if (art.progression_roadmap) {
setProgressionRoadmap(art.progression_roadmap)
const majors = mapMajorStepsFromApi(art.progression_roadmap)
@@ -670,16 +714,25 @@ export default function ExerciseProgressionPathBuilder({
let cancelled = false
Promise.all([
api.listFocusAreas({ status: 'active' }),
+ api.listStyleDirections({ status: 'active' }),
+ api.listTrainingTypes({ status: 'active' }),
+ api.listTargetGroups({ status: 'active' }),
api.listSkillsCatalog({ status: 'active' }),
])
- .then(([fa, sk]) => {
+ .then(([fa, sd, tt, tg, sk]) => {
if (cancelled) return
setFocusAreas(Array.isArray(fa) ? fa : [])
+ setStyleDirections(Array.isArray(sd) ? sd : [])
+ setTrainingTypes(Array.isArray(tt) ? tt : [])
+ setTargetGroups(Array.isArray(tg) ? tg : [])
setSkillsCatalog(Array.isArray(sk) ? sk : [])
})
.catch(() => {
if (!cancelled) {
setFocusAreas([])
+ setStyleDirections([])
+ setTrainingTypes([])
+ setTargetGroups([])
setSkillsCatalog([])
}
})
@@ -1095,6 +1148,7 @@ export default function ExerciseProgressionPathBuilder({
start_target_only: true,
progression_graph_id: Number(graphId),
...roadmapStructuredPayload(startSituation, targetState, roadmapNotes),
+ ...catalogApiPayload,
})
applyStartTargetResponse(res)
} catch (e) {
@@ -1133,6 +1187,7 @@ export default function ExerciseProgressionPathBuilder({
roadmap_only: true,
progression_graph_id: Number(graphId),
...roadmapStructuredPayload(startSituation, targetState, roadmapNotes),
+ ...catalogApiPayload,
})
const majors = mapMajorStepsFromApi(res?.progression_roadmap)
if (majors.length < 2) {
@@ -1204,6 +1259,7 @@ export default function ExerciseProgressionPathBuilder({
roadmap_override: override,
progression_graph_id: Number(graphId),
...roadmapStructuredPayload(startSituation, targetState, roadmapNotes),
+ ...catalogApiPayload,
})
applyPathMatchResponse(res, q)
setMaxSteps(validSteps.length)
@@ -1406,6 +1462,16 @@ export default function ExerciseProgressionPathBuilder({
/>
+
Optional zuerst „Start/Ziel analysieren“, anpassen, dann Roadmap-Stufen. Sind Start und Ziel leer, geschieht die Analyse beim Roadmap-Vorschlag automatisch mit. Manuelle Eingaben haben immer Vorrang. @@ -1826,11 +1892,40 @@ export default function ExerciseProgressionPathBuilder({ > Pfad-QS: {pathQa.overall_ok ? 'OK' : 'Hinweise'} - {pathQa.quality_score != null ? ` (${Math.round(Number(pathQa.quality_score) * 100)} %)` : ''} + {pathQaQualityPercent(pathQa) != null ? ` (${pathQaQualityPercent(pathQa)} %)` : ''} + {pathQaShowsStrongResult(pathQa) ? ( +
+ Starker Pfad — KI-Highlights können Feinschliff oder optionale Vertiefung sein. +
+ ) : null} {pathQa.topic_coverage ? ({pathQa.topic_coverage}
) : null} + {pathQaHighlights.length > 0 ? ( + <> ++ KI-Highlights ({pathQaHighlights.length}) +
++ Handlungsbedarf ({pathQaFixHints.length}) +
+{pathQa.bridge_insert_count} Brücken-Übung(en) aus der Bibliothek eingefügt. diff --git a/frontend/src/components/PlanningCatalogContextFields.jsx b/frontend/src/components/PlanningCatalogContextFields.jsx new file mode 100644 index 0000000..7877eb5 --- /dev/null +++ b/frontend/src/components/PlanningCatalogContextFields.jsx @@ -0,0 +1,99 @@ +/** + * Planungskontext — Katalog-Dimensionen für Progressionsgraph-Matching. + */ +import React from 'react' +import { getCatalogSelectId } from '../utils/progressionGraphDraft' + +export default function PlanningCatalogContextFields({ + catalogCtx, + onPatchDimension, + focusAreas = [], + styleDirections = [], + trainingTypes = [], + targetGroups = [], + disabled = false, + helperText = 'Planungskontext steuert Bibliotheks-Matching (Fokusbereich, Stil, Trainingsstil, Zielgruppe) — unabhängig von Technik-Pfaden.', +}) { + return ( + <> +
+ {helperText} +
+ ) : null} + > + ) +} diff --git a/frontend/src/components/ProgressionFindingsPanel.jsx b/frontend/src/components/ProgressionFindingsPanel.jsx index e733693..7483353 100644 --- a/frontend/src/components/ProgressionFindingsPanel.jsx +++ b/frontend/src/components/ProgressionFindingsPanel.jsx @@ -10,8 +10,11 @@ import { formatRematchLogEntry, formatRefineLogEntry, hasRematchSlotHints, + pathQaQualityPercent, + pathQaShowsStrongResult, resolveHintSlotIndex, resolveOfferSlotIndex, + splitPathQaHints, } from '../utils/progressionGraphDraft' function severityStyle(pathQa) { @@ -164,10 +167,15 @@ export default function ProgressionFindingsPanel({ aiBusy = false, evaluateDisabled = false, }) { - const optimizationHints = Array.isArray(pathQa?.optimization_hints) ? pathQa.optimization_hints : [] + const { fixHints: optimizationHints, highlightTexts } = useMemo( + () => splitPathQaHints(pathQa), + [pathQa], + ) const rematchLog = Array.isArray(pathQa?.rematch_log) ? pathQa.rematch_log : [] const refineLog = Array.isArray(pathQa?.refine_log) ? pathQa.refine_log : [] const showRematchAction = hasRematchSlotHints(pathQa) && typeof onRematchSlots === 'function' + const qualityPct = pathQaQualityPercent(pathQa) + const strongResult = pathQaShowsStrongResult(pathQa) return (+ Starker Pfad — KI-Empfehlungen unten können Feinschliff oder optionale Vertiefung sein. +
+ ) : null} {pathQa.topic_coverage ? ({pathQa.topic_coverage}
) : null} + {highlightTexts.length > 0 ? ( + <> ++ KI-Highlights ({highlightTexts.length}) +
+Empfehlungen
- Optimierungspotenziale ({optimizationHints.length}) + Handlungsbedarf ({optimizationHints.length})
- Planungskontext steuert Bibliotheks-Matching (Fokusbereich, Stil, Trainingsstil, Zielgruppe) — unabhängig - von Technik-Pfaden wie Mae Geri. Wird mit dem Graph gespeichert. -
+Optional zuerst „Start/Ziel analysieren“, anpassen, dann Roadmap-Stufen. Sind Start und Ziel leer, geschieht die Analyse beim Roadmap-Vorschlag automatisch. Manuelle Eingaben haben Vorrang. diff --git a/frontend/src/utils/progressionGraphDraft.js b/frontend/src/utils/progressionGraphDraft.js index c654b17..5f1fe1e 100644 --- a/frontend/src/utils/progressionGraphDraft.js +++ b/frontend/src/utils/progressionGraphDraft.js @@ -141,6 +141,44 @@ export function optimizationHintActionLabel(action) { return OPTIMIZATION_ACTION_LABELS[action] || action || 'Hinweis' } +/** LLM-Empfehlungen von technischen Fix-Hinweisen trennen (QS-UI). */ +export function splitPathQaHints(pathQa) { + const hints = Array.isArray(pathQa?.optimization_hints) ? pathQa.optimization_hints : [] + const fixHints = hints.filter((h) => String(h?.issue || '') !== 'llm_recommendation') + const highlightHints = hints.filter((h) => String(h?.issue || '') === 'llm_recommendation') + const recommendations = Array.isArray(pathQa?.recommendations) ? pathQa.recommendations : [] + const highlightTexts = [] + const seen = new Set() + for (const rec of recommendations) { + const text = String(rec || '').trim() + const key = text.toLowerCase() + if (text && !seen.has(key)) { + seen.add(key) + highlightTexts.push({ text, source: 'recommendation' }) + } + } + for (const hint of highlightHints) { + const text = String(hint.reason || hint.title || '').trim() + const key = text.toLowerCase() + if (text && !seen.has(key)) { + seen.add(key) + highlightTexts.push({ text, source: 'hint', hint }) + } + } + return { fixHints, highlightTexts } +} + +export function pathQaQualityPercent(pathQa) { + if (pathQa?.quality_score == null || !Number.isFinite(Number(pathQa.quality_score))) return null + return Math.round(Number(pathQa.quality_score) * 100) +} + +export function pathQaShowsStrongResult(pathQa) { + const pct = pathQaQualityPercent(pathQa) + if (pathQa?.overall_ok && pct != null && pct >= 85) return true + return Boolean(pathQa?.overall_ok && pct != null && pct >= 80 && !(pathQa?.issues || []).length) +} + /** Slot-Index aus optimization_hint (roadmap_major_step_index oder step_index). */ export function resolveHintSlotIndex(hint, draft = null) { if (!hint || typeof hint !== 'object') return null