""" Registry: Trainings-Häufigkeit, Pausen zwischen Einheiten, wöchentliche Session-JSON (KI-Rohkontext). """ from placeholder_registry import ( PlaceholderMetadata, MissingValuePolicy, EvidenceType, OutputType, PlaceholderType, register_placeholder, ) def _ev(meta: PlaceholderMetadata, field: str, et: EvidenceType = EvidenceType.CODE_DERIVED): meta.set_evidence(field, et) def register_activity_session_insights(): md_freq = PlaceholderMetadata( key="training_frequency_by_type_md", category="Aktivität", description=( "Markdown-Tabelle: pro Trainingsart (activity_type) Sessions, Ø/Woche, " "Dauer, kcal, HF, RPE, kcal/min (Intensitätsproxy)" ), resolver_module="backend/placeholder_resolver.py", resolver_function="get_training_frequency_by_type_md", data_layer_module="backend/data_layer/activity_metrics.py", data_layer_function="get_training_frequency_by_type_data", source_tables=["activity_log"], semantic_contract=( "Aggregat über activity_log gruppiert nach activity_type (Roh-Label). " "sessions_per_week = count / (days/7). avg_kcal_per_min = Summe kcal / Summe min." ), business_meaning="KI: Häufigkeit & Belastung pro Sportart, Erholungs-/Überlastungs-Kontext", unit="Markdown", time_window="default 28 Tage", output_type=OutputType.TEXT_SUMMARY, placeholder_type=PlaceholderType.INTERPRETED, format_hint="GitHub-Flavored Markdown-Tabelle", example_output="| Art | n | Ø/Woche | … |", minimum_data_requirements="Mindestens eine Session im Fenster", quality_filter_policy=None, confidence_logic="Wie calculate_confidence anhand Session-Anzahl", missing_value_policy=MissingValuePolicy( available=False, value_raw=None, missing_reason="no_data", legacy_display="Keine Trainingsdaten", ), known_limitations=( "Gruppierung nach activity_type-String (Import-Namen), nicht nur training_type_id. " "HF/RPE oft NULL je nach Quelle. Pausen-Analyse separater Platzhalter." ), layer_1_decision="activity_metrics.get_training_frequency_by_type_data", layer_2a_decision="get_training_frequency_by_type_md", layer_2b_reuse_possible=True, architecture_alignment="Phase 0c", issue_53_alignment="Layer 1", evidence={}, ) for f in ( "key", "category", "description", "resolver_module", "resolver_function", "data_layer_module", "data_layer_function", "source_tables", "semantic_contract", "unit", "time_window", "output_type", "placeholder_type", "format_hint", "example_output", "minimum_data_requirements", "confidence_logic", "missing_value_policy", "layer_1_decision", "layer_2a_decision", "layer_2b_reuse_possible", "architecture_alignment", "issue_53_alignment", ): _ev(md_freq, f) _ev(md_freq, "business_meaning", EvidenceType.DRAFT_DERIVED) _ev(md_freq, "known_limitations", EvidenceType.MIXED) register_placeholder(md_freq) md_gap = PlaceholderMetadata( key="training_inter_session_gap_md", category="Aktivität", description="Median/Mittel/Min der Stunden zwischen aufeinanderfolgenden Trainingseinheiten", resolver_module="backend/placeholder_resolver.py", resolver_function="get_training_inter_session_gap_md", data_layer_module="backend/data_layer/activity_metrics.py", data_layer_function="get_training_inter_session_gap_data", source_tables=["activity_log"], semantic_contract=( "Sessions chronologisch; Zeitstempel = date + start_time oder 12:00. " "Lücken in Stunden zwischen aufeinanderfolgenden Starts." ), business_meaning="KI: ausreichend Erholung zwischen Belastungen? Doppelbelastung?", unit="Markdown", time_window="default 28 Tage", output_type=OutputType.TEXT_SUMMARY, placeholder_type=PlaceholderType.INTERPRETED, format_hint="Kurzer Markdown-Fließtext", example_output="**Pause zwischen Trainings** …", minimum_data_requirements="Mindestens 2 Sessions", quality_filter_policy=None, confidence_logic="calculate_confidence über Session-Anzahl", missing_value_policy=MissingValuePolicy( available=False, value_raw=None, missing_reason="insufficient_data", legacy_display="Zu wenige Trainings", ), known_limitations=( "Kein Unterscheidung aktiv/passiv außerhalb activity_log. " "Fehlende Uhrzeit verzerrt Reihenfolge am selben Tag nicht (nur ein künstlicher Mittag)." ), layer_1_decision="activity_metrics.get_training_inter_session_gap_data", layer_2a_decision="get_training_inter_session_gap_md", layer_2b_reuse_possible=True, architecture_alignment="Phase 0c", issue_53_alignment="Layer 1", evidence={}, ) for f in ( "key", "category", "description", "resolver_module", "resolver_function", "data_layer_module", "data_layer_function", "source_tables", "semantic_contract", "unit", "time_window", "output_type", "placeholder_type", "format_hint", "example_output", "minimum_data_requirements", "confidence_logic", "missing_value_policy", "layer_1_decision", "layer_2a_decision", "layer_2b_reuse_possible", "architecture_alignment", "issue_53_alignment", ): _ev(md_gap, f) _ev(md_gap, "business_meaning", EvidenceType.DRAFT_DERIVED) _ev(md_gap, "known_limitations", EvidenceType.MIXED) register_placeholder(md_gap) pj = PlaceholderMetadata( key="training_sessions_recent_json", category="Aktivität", description=( "JSON: ISO-Wochen mit Sessions (activity_log-Kopf) plus session_metrics als kompaktes " "{key: Wert}-Objekt; Zahlen für Prompts gekürzt. Semantik: {{training_parameters_glossary_md}}." ), resolver_module="backend/placeholder_resolver.py", resolver_function="_safe_json", data_layer_module="backend/data_layer/activity_metrics.py", data_layer_function="get_training_sessions_recent_weeks_data", source_tables=["activity_log", "training_types", "activity_session_metrics", "training_parameters"], semantic_contract=( "Root: weeks[] mit week_iso; sessions[] pro Einheit u. a. id, date, activity_type, " "duration_min, kcal_active, hr_avg, hr_max, rpe, training_category, training_type_name, " "session_metrics (Objekt key→Wert, keine wiederholten Labels). " "Merge wie merge_column_backed_and_eav_metrics; nur Keys aus Attributschema. " "meta.session_metrics_shape=key_value, meta.metric_semantics_placeholder verweist auf Glossary-Platzhalter. " "Alle JSON-Platzhalter mit _safe_json: Zahlen rekursiv kompakt gerundet. " "Default ca. 4 ISO-Wochen (28 Tage Rohdatenfenster)." ), business_meaning="Rohkontext für wochenweise Auswertung (Erholung, Intensität) in der KI", unit="JSON string", time_window="4 ISO-Wochen (28 Tage Datenfenster)", output_type=OutputType.JSON, placeholder_type=PlaceholderType.RAW_DATA, format_hint="JSON-Objekt als String", example_output='{"weeks":[...],"meta":{...}}', minimum_data_requirements="Optional Sessions; meta.confidence bei leer insufficient", quality_filter_policy=None, confidence_logic="meta.confidence aus Session-Anzahl", missing_value_policy=MissingValuePolicy( available=False, value_raw=None, missing_reason="no_data", legacy_display="{}", ), known_limitations=( "Token-Länge bei vielen Sessions. training_type_name nur bei gesetztem training_type_id. " "session_metrics oft [] (kein Typ, kein Profil, keine gespeicherten Werte). " "Anzahl und Namen der Metrik-Keys sind instanz-/adminabhängig — JSON nicht als festes Schema " "für Downstream-Parsing harter Logik verwenden. " "Pflicht für Metrik-Bedeutung: {{training_parameters_glossary_md}} (Katalog); im JSON keine Namen/Beschreibungen pro Session. " "Composite-Parameter (JSON in EAV) noch nicht im MVP expandiert; ggf. Roh-value_text in späterer Phase." ), layer_1_decision="activity_metrics.get_training_sessions_recent_weeks_data", layer_2a_decision="_safe_json('training_sessions_recent_json')", layer_2b_reuse_possible=True, architecture_alignment="Phase 0c", issue_53_alignment="Layer 1", evidence={}, ) for f in ( "key", "category", "description", "resolver_module", "resolver_function", "data_layer_module", "data_layer_function", "source_tables", "semantic_contract", "unit", "time_window", "output_type", "placeholder_type", "format_hint", "example_output", "minimum_data_requirements", "confidence_logic", "missing_value_policy", "layer_1_decision", "layer_2a_decision", "layer_2b_reuse_possible", "architecture_alignment", "issue_53_alignment", ): _ev(pj, f) _ev(pj, "business_meaning", EvidenceType.DRAFT_DERIVED) _ev(pj, "known_limitations", EvidenceType.MIXED) register_placeholder(pj) md_gloss = PlaceholderMetadata( key="training_parameters_glossary_md", category="Aktivität", description=( "Markdown-Tabelle: alle aktiven training_parameters (key, DE/EN, Beschreibungen, Typ, Einheit, Kategorie). " "Ergänzung zu training_sessions_recent_json für KI (Bedeutung dynamischer Metrik-Keys)." ), resolver_module="backend/placeholder_resolver.py", resolver_function="get_training_parameters_glossary_md", data_layer_module="backend/data_layer/activity_metrics.py", data_layer_function="get_training_parameters_ki_glossary_data", source_tables=["training_parameters"], semantic_contract=( "SELECT auf training_parameters WHERE is_active; sortiert category, key. " "profile_id-Parameter im Resolver reserviert, aktuell globaler Katalog." ), business_meaning="KI: Legende zu session_metrics-Keys und Custom-Parametern", unit="Markdown", time_window="n/a (Katalog-Snapshot)", output_type=OutputType.TEXT_SUMMARY, placeholder_type=PlaceholderType.INTERPRETED, format_hint="GitHub-Flavored Markdown-Tabelle", example_output="| Feld (key) | DE | EN | Beschreibung DE | … |", minimum_data_requirements="Optional leer → Kurztext statt Tabelle", quality_filter_policy=None, confidence_logic="Immer verfügbar wenn DB erreichbar", missing_value_policy=MissingValuePolicy( available=False, value_raw=None, missing_reason="no_data", legacy_display="Keine aktiven Trainingsparameter im Katalog.", ), known_limitations=( "Keine profil-spezifische Einschränkung auf tatsächlich genutzte Keys (V2). " "Tabellen können bei großem Katalog lang werden." ), layer_1_decision="activity_metrics.get_training_parameters_ki_glossary_data", layer_2a_decision="get_training_parameters_glossary_md", layer_2b_reuse_possible=True, architecture_alignment="Phase 0c", issue_53_alignment="Layer 2a", evidence={}, ) for f in ( "key", "category", "description", "resolver_module", "resolver_function", "data_layer_module", "data_layer_function", "source_tables", "semantic_contract", "unit", "time_window", "output_type", "placeholder_type", "format_hint", "example_output", "minimum_data_requirements", "confidence_logic", "missing_value_policy", "layer_1_decision", "layer_2a_decision", "layer_2b_reuse_possible", "architecture_alignment", "issue_53_alignment", ): _ev(md_gloss, f) _ev(md_gloss, "business_meaning", EvidenceType.DRAFT_DERIVED) _ev(md_gloss, "known_limitations", EvidenceType.MIXED) register_placeholder(md_gloss) register_activity_session_insights()