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}) +

+ + + ) : null} {Array.isArray(pathQa.issues) && pathQa.issues.length > 0 ? ( ) : null} + {pathQaFixHints.length > 0 ? ( + <> +

+ Handlungsbedarf ({pathQaFixHints.length}) +

+ + + ) : null} {Number(pathQa.bridge_insert_count) > 0 ? (

{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 ? ( +

+ {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 (
@@ -204,13 +212,50 @@ export default function ProgressionFindingsPanel({ > Pfad-QS: {pathQa.overall_ok ? 'OK' : 'Hinweise'} - {pathQa.quality_score != null - ? ` (${Math.round(Number(pathQa.quality_score) * 100)} %)` - : ''} + {qualityPct != null ? ` (${qualityPct} %)` : ''} + {strongResult ? ( +

+ 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}) +

+ + + ) : null} {Array.isArray(pathQa.issues) && pathQa.issues.length > 0 ? ( ) : null} - {Array.isArray(pathQa.recommendations) && pathQa.recommendations.length > 0 ? ( + {Array.isArray(pathQa.recommendations) && + pathQa.recommendations.length > 0 && + highlightTexts.length === 0 ? ( <>

Empfehlungen

-
-
- - -
-
- - -
-
- - -
-
- - -
-
-

- 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