From 3181cc126d50f2464711cfaf49b639262c1a0164 Mon Sep 17 00:00:00 2001 From: Lars Date: Fri, 19 Jun 2026 12:35:30 +0200 Subject: [PATCH] Enhance Planning AI Context with Catalog Exercise Hints - Introduced support for catalog exercise hints in various functions, including `_build_stage_ai_context`, `try_suggest_ai_stage_step`, and `build_gap_fill_goal_text`, improving the contextual information available for AI suggestions. - Added a new function `catalog_exercise_hints_block` to consolidate hints retrieval from the catalog context. - Updated the `PlanningIntentContext` to include catalog exercise hints, ensuring they are part of the API output. - Implemented tests to verify the inclusion of catalog exercise hints in goal text generation and rematch logic. - Incremented version numbers and updated changelog to reflect these enhancements. --- backend/planning_exercise_path_ai_fill.py | 30 +++++++++++++++++++ backend/planning_exercise_path_builder.py | 11 +++++++ backend/planning_intent_context.py | 16 +++++++++- backend/planning_path_rematch.py | 24 ++++++++++++++- backend/planning_progression_roadmap.py | 2 ++ backend/planning_prompt_variables.py | 22 ++++++++++++++ .../test_planning_exercise_path_ai_fill.py | 14 +++++++++ backend/tests/test_planning_path_rematch.py | 26 ++++++++++++++++ backend/version.py | 15 ++++++++-- docs/HANDOVER.md | 9 +++--- .../PLANNING_CATALOG_PROMPT_SNIPPETS.md | 11 +++---- 11 files changed, 166 insertions(+), 14 deletions(-) diff --git a/backend/planning_exercise_path_ai_fill.py b/backend/planning_exercise_path_ai_fill.py index a679584..aa75705 100644 --- a/backend/planning_exercise_path_ai_fill.py +++ b/backend/planning_exercise_path_ai_fill.py @@ -19,6 +19,8 @@ from planning_exercise_form_context import ( prior_path_steps_before_major, ) from planning_exercise_semantics import PlanningSemanticBrief, brief_to_summary_dict +from planning_catalog_context import ProgressionPlanningCatalogContext +from planning_prompt_variables import catalog_exercise_hints_block _logger = logging.getLogger("shinkan.planning_exercise_path_ai_fill") @@ -54,6 +56,7 @@ def _build_stage_ai_context( step_after: Optional[Mapping[str, Any]] = None, prior_steps: Optional[Sequence[Mapping[str, Any]]] = None, start_situation: Optional[str] = None, + catalog_exercise_hints: Optional[str] = None, ) -> ExerciseFormAiPromptContext: """KI-Kontext für unbesetzte Roadmap-Stufe (keine Brücke zwischen falschen Array-Indizes).""" gap = dict(spec.get("gap") or {}) @@ -97,6 +100,9 @@ def _build_stage_ai_context( sketch = (spec.get("sketch") or "").strip() if sketch and sketch != learning_goal: goal_parts.extend(["", f"Kontext: {sketch}"]) + hints = (catalog_exercise_hints or "").strip() + if hints: + goal_parts.extend(["", "Katalog-Hinweise Übungsanlage:", hints]) goal = "\n".join(goal_parts) focus_hint = topic if brief.topic_type == "technique" else None @@ -118,6 +124,7 @@ def try_suggest_ai_stage_step( brief: PlanningSemanticBrief, spec: Mapping[str, Any], steps: Sequence[Mapping[str, Any]], + catalog: Optional[ProgressionPlanningCatalogContext] = None, ) -> Optional[Dict[str, Any]]: """KI-Vorschlag für leere Roadmap-Stufe.""" major_idx = spec.get("roadmap_major_step_index") @@ -136,6 +143,8 @@ def try_suggest_ai_stage_step( if not gap.get("learning_goal"): gap["learning_goal"] = spec.get("title_hint") or spec.get("sketch") + exercise_hints = catalog_exercise_hints_block(cur, catalog) if catalog else "" + ctx = _build_stage_ai_context( goal_query=goal_query, brief=brief, @@ -143,6 +152,7 @@ def try_suggest_ai_stage_step( step_before=step_before, step_after=step_after, prior_steps=prior_steps, + catalog_exercise_hints=exercise_hints or None, ) try: ai_payload = run_exercise_form_ai_suggestion(cur, ctx=ctx) @@ -189,6 +199,7 @@ def _build_gap_ai_context( gap: Mapping[str, Any], title_hint: Optional[str] = None, sketch_hint: Optional[str] = None, + catalog_exercise_hints: Optional[str] = None, ) -> ExerciseFormAiPromptContext: topic = (brief.primary_topic or "Technik").strip() phase = gap.get("expected_phase") or "vertiefung" @@ -206,6 +217,9 @@ def _build_gap_ai_context( ] if sketch: goal_parts.extend(["", f"Hinweis: {sketch}"]) + hints = (catalog_exercise_hints or "").strip() + if hints: + goal_parts.extend(["", "Katalog-Hinweise Übungsanlage:", hints]) goal = "\n".join(goal_parts) focus_hint = topic if brief.topic_type == "technique" else None @@ -271,8 +285,10 @@ def try_suggest_ai_bridge_step( gap: Mapping[str, Any], title_hint: Optional[str] = None, sketch_hint: Optional[str] = None, + catalog: Optional[ProgressionPlanningCatalogContext] = None, ) -> Optional[Dict[str, Any]]: """Ruft exercise AI suggest auf — kein Speichern in DB.""" + exercise_hints = catalog_exercise_hints_block(cur, catalog) if catalog else "" ctx = _build_gap_ai_context( goal_query=goal_query, brief=brief, @@ -281,6 +297,7 @@ def try_suggest_ai_bridge_step( gap=gap, title_hint=title_hint, sketch_hint=sketch_hint, + catalog_exercise_hints=exercise_hints or None, ) g_plain = strip_html_to_plain(ctx.goal) if not g_plain.strip() and not (ctx.title or "").strip(): @@ -478,6 +495,7 @@ def build_gap_fill_goal_text( step_a: Optional[Mapping[str, Any]] = None, step_b: Optional[Mapping[str, Any]] = None, roadmap_snapshot: Optional[Mapping[str, Any]] = None, + catalog_exercise_hints: Optional[str] = None, ) -> str: """Ausführlicher Zieltext für KI-Neuanlage aus Pfad-, Roadmap- und Stufen-Kontext.""" topic = (brief.primary_topic or "Technik").strip() @@ -555,6 +573,9 @@ def build_gap_fill_goal_text( parts.append(f"Qualitätsprüfung: {spec['rationale']}") if spec.get("sketch"): parts.append(f"Skizze: {spec['sketch']}") + hints = (catalog_exercise_hints or "").strip() + if hints: + parts.append(f"Katalog-Hinweise Übungsanlage:\n{hints}") parts.append( "Die Übung muss die Stufe didaktisch erfüllen: klare Voraussetzungen, messbares Stufenziel, " "Bezug zum Gesamtpfad — keine generische Kraftübung ohne Technikbezug. " @@ -571,6 +592,7 @@ def build_gap_fill_offer( brief: Optional[PlanningSemanticBrief] = None, proposal: Optional[Mapping[str, Any]] = None, roadmap_snapshot: Optional[Mapping[str, Any]] = None, + catalog_exercise_hints: Optional[str] = None, ) -> Dict[str, Any]: source = spec.get("source") idx = int(spec.get("insert_after_index") or 0) @@ -603,6 +625,7 @@ def build_gap_fill_offer( step_a=step_a, step_b=step_b, roadmap_snapshot=enriched_snapshot or None, + catalog_exercise_hints=catalog_exercise_hints, ) ctx_preview = enriched_snapshot or None offer: Dict[str, Any] = { @@ -642,6 +665,7 @@ def apply_gap_fill_after_qa( max_ai_proposals: int = 3, auto_insert_proposals: bool = False, roadmap_snapshot: Optional[Mapping[str, Any]] = None, + catalog: Optional[ProgressionPlanningCatalogContext] = None, ) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]], List[Dict[str, Any]]]: """ Erzeugt gap_fill_offers für die UI; optional KI-Vorschläge einfügen. @@ -653,6 +677,7 @@ def apply_gap_fill_after_qa( out = list(steps) proposals: List[Dict[str, Any]] = [] offers: List[Dict[str, Any]] = [] + exercise_hints = catalog_exercise_hints_block(cur, catalog) if catalog else "" for spec in specs: source = spec.get("source") @@ -666,6 +691,7 @@ def apply_gap_fill_after_qa( brief=brief, spec=spec, steps=out, + catalog=catalog, ) offer = build_gap_fill_offer( spec=spec, @@ -674,6 +700,7 @@ def apply_gap_fill_after_qa( brief=brief, proposal=proposal, roadmap_snapshot=roadmap_snapshot, + catalog_exercise_hints=exercise_hints or None, ) offers.append(offer) if proposal and auto_insert_proposals: @@ -700,6 +727,7 @@ def apply_gap_fill_after_qa( brief=brief, proposal=None, roadmap_snapshot=roadmap_snapshot, + catalog_exercise_hints=exercise_hints or None, ) offers.append(offer) continue @@ -719,6 +747,7 @@ def apply_gap_fill_after_qa( gap=gap, title_hint=str(spec.get("title_hint") or ""), sketch_hint=str(spec.get("sketch") or ""), + catalog=catalog, ) offer = build_gap_fill_offer( @@ -728,6 +757,7 @@ def apply_gap_fill_after_qa( brief=brief, proposal=proposal, roadmap_snapshot=roadmap_snapshot, + catalog_exercise_hints=exercise_hints or None, ) offers.append(offer) diff --git a/backend/planning_exercise_path_builder.py b/backend/planning_exercise_path_builder.py index ccdb97f..377a0ab 100644 --- a/backend/planning_exercise_path_builder.py +++ b/backend/planning_exercise_path_builder.py @@ -24,9 +24,11 @@ from planning_catalog_context import ( load_catalog_context_from_graph_row, merge_catalog_context_into_target, ) +from catalog_prompt_slots import get_rematch_guard_for_catalog from planning_exercise_profiles import PlanningTargetProfile from planning_path_qa_pipeline import run_multistage_path_qa from planning_path_rematch import ( + apply_rematch_catalog_guard, collect_rematch_slot_indices, filter_rematch_slot_indices, prune_stripped_after_rematch, @@ -1737,6 +1739,13 @@ def _run_roadmap_rematch_loop( stripped_off_topic=current_stripped if round_idx == 0 else [], off_topic_steps=off_topic_before_strip if round_idx == 0 and use_initial_off_topic else [], ) + catalog_context = _resolve_planning_catalog_context(cur, body) + rematch_guard = get_rematch_guard_for_catalog(cur, catalog_context) + slot_indices = apply_rematch_catalog_guard( + slot_indices, + rematch_reasons, + rematch_guard=rematch_guard, + ) if not slot_indices: break @@ -2191,6 +2200,7 @@ def _run_evaluate_only_path_qa( max_ai_proposals=0, auto_insert_proposals=False, roadmap_snapshot=path_roadmap_snapshot, + catalog=catalog_context, ) multistage_qa = run_multistage_path_qa( @@ -4294,6 +4304,7 @@ def suggest_progression_path( max_ai_proposals=0, auto_insert_proposals=False, roadmap_snapshot=path_roadmap_snapshot, + catalog=catalog_context, ) if roadmap_gap_offers: diff --git a/backend/planning_intent_context.py b/backend/planning_intent_context.py index ce6e774..1ff0e16 100644 --- a/backend/planning_intent_context.py +++ b/backend/planning_intent_context.py @@ -49,9 +49,10 @@ class PlanningIntentContext: context_notes: str = "" topic_type: str = "general" technique_sibling_excludes: List[str] = field(default_factory=list) + catalog_exercise_hints: Optional[str] = None def to_api_dict(self) -> Dict[str, Any]: - return { + out = { "source_query": self.source_query, "primary_topic": self.primary_topic, "topic_type": self.topic_type, @@ -61,6 +62,10 @@ class PlanningIntentContext: "technique_sibling_excludes": self.technique_sibling_excludes[:16], "context_notes": self.context_notes[:1200] or None, } + hints = (self.catalog_exercise_hints or "").strip() + if hints: + out["catalog_exercise_hints"] = hints[:2000] + return out def build_planning_intent_context( @@ -70,6 +75,8 @@ def build_planning_intent_context( goal_analysis: Optional[Mapping[str, Any]] = None, extra_context: Optional[str] = None, primary_topic: Optional[str] = None, + cur=None, + catalog=None, ) -> PlanningIntentContext: """Intent aus Anfrage, Zielanalyse und optionalem Kontext — ohne Sonderregeln pro Thema.""" ga = dict(goal_analysis or {}) @@ -124,6 +131,12 @@ def build_planning_intent_context( if line not in path_success: path_success.insert(0, line) + catalog_hints = "" + if cur is not None and catalog is not None: + from planning_prompt_variables import catalog_exercise_hints_block + + catalog_hints = catalog_exercise_hints_block(cur, catalog) + return PlanningIntentContext( source_query=(goal_query or "").strip(), primary_topic=topic, @@ -133,6 +146,7 @@ def build_planning_intent_context( explicit_exclusions=explicit, technique_sibling_excludes=siblings[:16], context_notes=combined_notes[:1200], + catalog_exercise_hints=catalog_hints or None, ) diff --git a/backend/planning_path_rematch.py b/backend/planning_path_rematch.py index 4f47dfd..f98d533 100644 --- a/backend/planning_path_rematch.py +++ b/backend/planning_path_rematch.py @@ -7,6 +7,8 @@ from typing import Any, Dict, List, Mapping, Optional, Sequence, Set, Tuple from planning_progression_roadmap import ProgressionRoadmapContext, StageSpecArtifact +_UNFILLED_REMATCH_REASON = "Keine passende Übung für Roadmap-Stufe" + def _slot_priority_for_rematch( body, @@ -103,7 +105,7 @@ def collect_rematch_slot_indices( if isinstance(item, (list, tuple)) and len(item) >= 2: idx, spec = item[0], item[1] midx = getattr(spec, "major_step_index", idx) - _register(int(midx), "Keine passende Übung für Roadmap-Stufe") + _register(int(midx), _UNFILLED_REMATCH_REASON) elif isinstance(item, dict): midx = _resolve_major(item) if midx is not None: @@ -114,6 +116,25 @@ def collect_rematch_slot_indices( return indices, reasons +def apply_rematch_catalog_guard( + slot_indices: Set[int], + rematch_reasons: Mapping[int, str], + *, + rematch_guard: Optional[str], +) -> Set[int]: + """ + Bei gesetztem rematch_guard (Katalog-Slot): kein Auto-Rematch nur wegen leerer Roadmap-Stufe. + Off-Topic, explizite QS-Hinweise und Stufen-Verfeinerung bleiben aktiv. + """ + if not (rematch_guard or "").strip(): + return set(slot_indices) + return { + idx + for idx in slot_indices + if str(rematch_reasons.get(idx) or "").strip() != _UNFILLED_REMATCH_REASON + } + + def filter_rematch_slot_indices( steps: Sequence[Mapping[str, Any]], slot_indices: Set[int], @@ -372,6 +393,7 @@ def prune_stripped_after_rematch( __all__ = [ + "apply_rematch_catalog_guard", "collect_rematch_slot_indices", "filter_rematch_slot_indices", "prune_stripped_after_rematch", diff --git a/backend/planning_progression_roadmap.py b/backend/planning_progression_roadmap.py index 3bf3dcb..72bb917 100644 --- a/backend/planning_progression_roadmap.py +++ b/backend/planning_progression_roadmap.py @@ -1244,6 +1244,8 @@ def run_progression_roadmap_pipeline( resolved.target_state, ), primary_topic=goal_analysis.primary_topic, + cur=cur, + catalog=catalog, ) heuristic_specs = build_stage_specs( diff --git a/backend/planning_prompt_variables.py b/backend/planning_prompt_variables.py index fcec48e..89d6de5 100644 --- a/backend/planning_prompt_variables.py +++ b/backend/planning_prompt_variables.py @@ -34,6 +34,27 @@ _PLANNING_PROMPT_VARIABLE_PROVIDERS: tuple[PlanningPromptVariableProvider, ...] ) +def catalog_exercise_hints_block( + cur, + catalog: Optional[ProgressionPlanningCatalogContext] = None, + *, + slug: Optional[str] = None, +) -> str: + """Kombinierte hints_on_exercise aus aktivem Katalog-Kontext (Gap-Fill / Intent).""" + if cur is None or catalog is None: + return "" + from catalog_prompt_slots import CATALOG_KINDS, placeholder_key + + merged = merge_planning_prompt_variables(cur, {}, catalog=catalog, slug=slug) + lines: list[str] = [] + for cfg in CATALOG_KINDS: + key = placeholder_key(cfg.kind, "hints_on_exercise") + text = (merged.get(key) or "").strip() + if text: + lines.append(f"{cfg.label_de}: {text}") + return "\n".join(lines) + + def merge_planning_prompt_variables( cur, base_variables: Mapping[str, str], @@ -113,6 +134,7 @@ def planning_prompt_placeholder_catalog() -> dict: __all__ = [ + "catalog_exercise_hints_block", "merge_planning_prompt_variables", "planning_prompt_placeholder_catalog", ] diff --git a/backend/tests/test_planning_exercise_path_ai_fill.py b/backend/tests/test_planning_exercise_path_ai_fill.py index f39b3bf..bcf93a5 100644 --- a/backend/tests/test_planning_exercise_path_ai_fill.py +++ b/backend/tests/test_planning_exercise_path_ai_fill.py @@ -83,6 +83,20 @@ def test_strip_off_topic_steps_from_path(): assert [s["exercise_id"] for s in out] == [1, 2, 4] +def test_build_gap_fill_goal_text_includes_catalog_exercise_hints(): + from planning_exercise_semantics import build_semantic_brief + + brief = build_semantic_brief("Mae Geri") + text = build_gap_fill_goal_text( + goal_query="Mae Geri lernen", + brief=brief, + spec={"source": "roadmap_unfilled", "phase": "grundlage", "title_hint": "Stand"}, + catalog_exercise_hints="Primärfokus: Kihon und Partnerübungen mit Technikbezug.", + ) + assert "Katalog-Hinweise Übungsanlage" in text + assert "Kihon" in text + + def test_build_gap_fill_goal_text_includes_topic(): brief = build_semantic_brief("Mae Geri Perfektion") text = build_gap_fill_goal_text( diff --git a/backend/tests/test_planning_path_rematch.py b/backend/tests/test_planning_path_rematch.py index 2ee19f5..69b122b 100644 --- a/backend/tests/test_planning_path_rematch.py +++ b/backend/tests/test_planning_path_rematch.py @@ -336,3 +336,29 @@ def test_filter_rematch_skips_preserved_slots(): off_topic_steps=[], ) assert filtered == {1} + + +def test_apply_rematch_catalog_guard_skips_unfilled_only(): + from planning_path_rematch import apply_rematch_catalog_guard + + indices = {0, 1, 2} + reasons = { + 0: "QS-Tier-1", + 1: "Keine passende Übung für Roadmap-Stufe", + 2: "Passt nicht zur Haupttechnik", + } + filtered = apply_rematch_catalog_guard( + indices, + reasons, + rematch_guard="Keine leeren Slots erzwingen.", + ) + assert filtered == {0, 2} + + +def test_apply_rematch_catalog_guard_inactive_without_guard(): + from planning_path_rematch import apply_rematch_catalog_guard + + indices = {1} + reasons = {1: "Keine passende Übung für Roadmap-Stufe"} + assert apply_rematch_catalog_guard(indices, reasons, rematch_guard=None) == {1} + assert apply_rematch_catalog_guard(indices, reasons, rematch_guard="") == {1} diff --git a/backend/version.py b/backend/version.py index b81f759..9e27847 100644 --- a/backend/version.py +++ b/backend/version.py @@ -1,8 +1,8 @@ # Shinkan Jinkendo Version Information -APP_VERSION = "0.8.237" +APP_VERSION = "0.8.238" BUILD_DATE = "2026-05-22" -DB_SCHEMA_VERSION = "20260607094" +DB_SCHEMA_VERSION = "20260607095" MODULE_VERSIONS = { "legal_documents": "1.4.0", # Admin: Live-Vorschau pro Abschnitt + modale Vollvorschau (Editor + Dokumentenliste) @@ -53,11 +53,20 @@ MODULE_VERSIONS = { } CHANGELOG = [ + { + "version": "0.8.238", + "date": "2026-05-22", + "changes": [ + "Planungs-KI H1.5: rematch_guard im Auto-Rematch (kein Rematch nur wegen leerer Roadmap-Stufe).", + "hints_on_exercise in Gap-Fill, Übungs-KI-Kontext und intent_context_json (Roadmap-Pipeline).", + "Migration 095: keine Migrations-Seeds in catalog_prompt_slots (Prod-sichere Katalogstruktur).", + ], + }, { "version": "0.8.237", "date": "2026-05-22", "changes": [ - "Migration 094: catalog_prompt_slots vollständig befüllt (Karate, SV, alle Trainingsstile/Zielgruppen).", + "Migration 094/095: Katalog-Prompt-Slots ohne Migrations-Seeds — Inhalte Admin oder Laufzeit-Fallback.", "catalog_slot_fallbacks: Namens-Fallback bis Admin-Override — gleiche Qualität wie H1-Registry.", ], }, diff --git a/docs/HANDOVER.md b/docs/HANDOVER.md index 6159fe6..3f7929b 100644 --- a/docs/HANDOVER.md +++ b/docs/HANDOVER.md @@ -1,7 +1,7 @@ # Shinkan Jinkendo – Entwicklungsstand & Handover -**Stand:** 2026-05-22 (F15 Graph-Match & getrennte Pfad-QS, lokal nach **0.8.233**) -**App-Version / DB-Schema:** App **`0.8.233`** (Planungs-KI F11–F14, Katalog-Kontext); **F15** siehe §2.8 — DB unverändert (`DB_SCHEMA_VERSION`, Migration **088**). +**Stand:** 2026-05-22 (Katalog-Prompt-Slots H2/H1.5, **0.8.238**) +**App-Version / DB-Schema:** App **`0.8.238`**; DB Migration **095** (keine Slot-Seeds; Prod-sichere Katalogstruktur). 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**. @@ -115,7 +115,8 @@ Das Schema ist gegenüber dem Code zurück: Migration **`022_skills_schema_compl | **F13** | **`planning_catalog_context`** (Fokus/Stil/TT/ZG) im Match + Graph-Artefakt | ✅ **0.8.233** | | **F14** | **`ProgressionGraphEditor`** — Slot-UI + Planungskontext-Dropdowns | ✅ **0.8.233** | | **F15** | Unified Slot-Review (Match-Dialog), getrennte Pfad-QS, `findings_stale` | ✅ lokal (nach 0.8.233) | -| **H1** | Katalog-Prompt-Snippets (modulare LLM-Anweisungen) | 🔲 Spec **`docs/architecture/PLANNING_CATALOG_PROMPT_SNIPPETS.md`** | +| **H1–H2.1** | Katalog-Prompt-Slots (DB, Resolver, Admin-UI, granulare Prompts) | ✅ **0.8.234–238** — Spec **`docs/architecture/PLANNING_CATALOG_PROMPT_SNIPPETS.md`** | +| **H1.5** | `rematch_guard`, `hints_on_exercise` in Rematch/Gap-Fill/Intent | ✅ **0.8.238** | **Architektur (verbindlich):** Drei Schichten — (1) **Katalog-Dimensionen** (DB, jetzt im Match verdrahtet; **H1:** zusätzlich Prompt-Snippets), (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. @@ -148,7 +149,7 @@ Das Schema ist gegenüber dem Code zurück: Migration **`022_skills_schema_compl 5. Phase D′ — Auto KI-Gap-Fill bei persistent leeren Slots 6. **Trainingsplanung Phase G** — Gruppenkontext-Pack, Scopes `training_section` / `framework_slot` (Ist-Doku §16) 7. Technik-Katalog konfigurierbar (Backlog) -8. **H1** — Katalog-Prompt-Snippets (modulare LLM-Anweisungen) +8. **H1–H2.1** — Katalog-Prompt-Slots ✅ · **Prompt-Editor-Überarbeitung** → eigene Session #### Übungs-KI Formular / Schnellanlage (Stand **0.8.171**) diff --git a/docs/architecture/PLANNING_CATALOG_PROMPT_SNIPPETS.md b/docs/architecture/PLANNING_CATALOG_PROMPT_SNIPPETS.md index 19e29f6..85e8b02 100644 --- a/docs/architecture/PLANNING_CATALOG_PROMPT_SNIPPETS.md +++ b/docs/architecture/PLANNING_CATALOG_PROMPT_SNIPPETS.md @@ -1,7 +1,7 @@ # Planungs-KI — Katalog-Prompt-Slots (Snippets) **Stand:** 2026-05-22 -**Status:** **H2** umgesetzt (0.8.235) · **H2.1** Admin-UI + granulare Prompts (0.8.236) +**Status:** **H2.1** umgesetzt (0.8.236) · **H1.5** Rematch-Guard + Gap-Fill-Hints (0.8.238) · **Prompt-Editor-Überarbeitung** bewusst ausgelagert **Bezüge:** `PLANNING_PROGRESSION_GRAPH_KI.md` §4.4 · `AI_PROMPT_TARGET_ARCHITECTURE.md` §2.4 · `planning_catalog_context.py` · `catalog_prompt_slots.py` --- @@ -173,12 +173,12 @@ Hardcodierte `SNIPPET_REGISTRY` — Proof of Concept für `catalog_guidance_bloc - [x] Slot-Editor an Fokusbereich / Trainingsstil / Zielgruppe / Stilrichtung (`CatalogPromptSlotsEditor`, Stammdaten-Katalog) - [x] Prompt-Templates mit granularen Platzhaltern (Migration 093) -- [ ] Platzhalter-Hilfe im KI-Prompt-Editor (erweitert) +- [ ] **Prompt-Editor komplett überarbeiten** (Platzhalter-Hilfe, UX) — **eigene Session** -### H1.5 +### H1.5 ✓ (0.8.238) -- [ ] `rematch_guard` im Rematch-Loop -- [ ] Intent-Prompts + Gap-Fill: `hints_on_exercise` +- [x] `rematch_guard` im Rematch-Loop (`apply_rematch_catalog_guard`) +- [x] Gap-Fill + Intent: `hints_on_exercise` via `catalog_exercise_hints_block` / `intent_context_json` ### H3 — Trainingsplanung (Phase G) @@ -211,6 +211,7 @@ Hardcodierte `SNIPPET_REGISTRY` — Proof of Concept für `catalog_guidance_bloc | Datum | Änderung | |-------|----------| +| 2026-05-22 | **H1.5** (0.8.238): rematch_guard; hints_on_exercise in Gap-Fill/Intent; Migration 095 ohne Seeds | | 2026-05-22 | **H2.1** (0.8.236): Admin-UI `CatalogPromptSlotsEditor`; Migration 093 granulare Prompt-Templates | | 2026-05-22 | **H2** (0.8.235): Slot-Typ-Register + `catalog_prompt_slots` DB, granulare Platzhalter, Admin-API | | 2026-05-22 | Konzept §4–§8: zwei Ebenen Slot-Typ vs. Slot-Wert; Platzhalter `{kind}_{slot_key}` |