feat: Enhance activity metrics documentation and registry updates
- Added details for Issue #53 regarding the audit of activity placeholders between Layer 1 and Layer 2a in `CLAUDE.md` and `README.md`. - Updated the `ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE.md` to reflect the new registry checks and dynamic session metrics handling. - Revised the `placeholder_resolver.py` and `activity_metrics.py` to clarify the registration of activity metrics and session insights, ensuring consistency in the handling of dynamic keys and metrics. - Improved descriptions and semantic contracts in `activity_session_insights.py` to better outline the structure and limitations of session data.
This commit is contained in:
parent
680ecd1c06
commit
c3be745efa
|
|
@ -117,6 +117,7 @@ _Dieser Ordner `.claude/docs/` ist per `.gitignore`-Ausnahme **versioniert** (Sp
|
||||||
| `ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE.md` | Session-Metriken EAV, Attributprofile, Layer-1, Prod-Migration |
|
| `ACTIVITY_SESSION_METRICS_EAV_AGENT_GUIDE.md` | Session-Metriken EAV, Attributprofile, Layer-1, Prod-Migration |
|
||||||
| `ACTIVITY_COMPOSITE_METRICS_IMPLEMENTATION_CONCEPT.md` | Composite-Metriken in EAV (JSONB), Archetypen, CSV-Slots, Layer-1-Expand, Migration/Test-Checkliste |
|
| `ACTIVITY_COMPOSITE_METRICS_IMPLEMENTATION_CONCEPT.md` | Composite-Metriken in EAV (JSONB), Archetypen, CSV-Slots, Layer-1-Expand, Migration/Test-Checkliste |
|
||||||
| `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` | **Zielarchitektur** Aktivität (Spine/EAV/Composites/Import/Layer 1–2) + **Phasenplan A–F** Produktionsreife |
|
| `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` | **Zielarchitektur** Aktivität (Spine/EAV/Composites/Import/Layer 1–2) + **Phasenplan A–F** Produktionsreife |
|
||||||
|
| `ACTIVITY_LAYER2A_PLACEHOLDER_AUDIT.md` | Issue #53: Aktivitäts-Platzhalter Layer 1 ↔ 2a (Audit Schritt 1) |
|
||||||
| `ACTIVITY_SCALAR_KANON_TABLE.md` | **Skalar-Kanon** Aktivität (eine Semantik → eine Quelle); Phase A |
|
| `ACTIVITY_SCALAR_KANON_TABLE.md` | **Skalar-Kanon** Aktivität (eine Semantik → eine Quelle); Phase A |
|
||||||
| *(Code)* `backend/data_layer/activity_data_canon.py` | **Kanon** activity CSV-Modul vs. EAV-primär; Legacy-Lesefallback |
|
| *(Code)* `backend/data_layer/activity_data_canon.py` | **Kanon** activity CSV-Modul vs. EAV-primär; Legacy-Lesefallback |
|
||||||
| `V9D_PHASE2_VITALS_SLEEP.md` | v9d Vitalwerte/Schlaf (Release-Bezug) |
|
| `V9D_PHASE2_VITALS_SLEEP.md` | v9d Vitalwerte/Schlaf (Release-Bezug) |
|
||||||
|
|
|
||||||
70
.claude/docs/technical/ACTIVITY_LAYER2A_PLACEHOLDER_AUDIT.md
Normal file
70
.claude/docs/technical/ACTIVITY_LAYER2A_PLACEHOLDER_AUDIT.md
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
# Aktivität: Layer-2a-Platzhalter — Audit Schritt 1 (Issue #53)
|
||||||
|
|
||||||
|
**Stand:** 2026-04-16
|
||||||
|
**Bezug:** [Issue #53 — Multi-Layer Architecture](../../../docs/issues/issue-53-phase-0c-multi-layer-architecture.md): Layer 1 = strukturierte Daten, Layer 2a = KI-Formatierung (keine parallele Domänen-Logik im Resolver).
|
||||||
|
|
||||||
|
**Ziel dieses Dokuments:** Jeder Aktivitäts-Platzhalter hat genau eine **Layer‑1‑Quelle** (`data_layer/activity_metrics.py`); `placeholder_resolver.py` formatiert oder serialisiert nur noch.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Ergebnisübersicht
|
||||||
|
|
||||||
|
| Kategorie | Anzahl | Resolver-SQL für Aktivität? |
|
||||||
|
|-----------|--------|------------------------------|
|
||||||
|
| Gebündelt in `PLACEHOLDER_MAP` (Training/Aktivität) | 20 | **Nein** |
|
||||||
|
| Abweichungen / offene Punkte | 0 | — |
|
||||||
|
|
||||||
|
**Hinweis:** `{{rest_days_count}}` steht in der Karte unter „Schlaf & Erholung“ und nutzt `recovery_metrics.get_rest_days_data` — nicht in dieser Tabelle.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Platzhalter → Layer 1 → Layer 2a
|
||||||
|
|
||||||
|
| Key | Layer 1 (`activity_metrics`) | Layer 2a (`placeholder_resolver`) | Bemerkung |
|
||||||
|
|-----|------------------------------|-------------------------------------|-----------|
|
||||||
|
| `activity_summary` | `get_activity_summary_data` | `get_activity_summary` | String-Zusammenfassung |
|
||||||
|
| `activity_detail` | `get_activity_detail_data` (+ `enrich_sessions_with_metrics`) | `get_activity_detail` | Dynamische `session_metrics[]` pro Zeile (Profil/EAV) |
|
||||||
|
| `trainingstyp_verteilung` | `get_training_type_distribution_data` | `get_trainingstyp_verteilung` | Ausgabe: Top-3-Text (kein JSON); Registry 2026-04 an Ist angeglichen |
|
||||||
|
| `training_minutes_week` | `calculate_training_minutes_week` | `_safe_int` | |
|
||||||
|
| `training_frequency_7d` | `calculate_training_frequency_7d` | `_safe_int` | |
|
||||||
|
| `quality_sessions_pct` | `calculate_quality_sessions_pct` | `_safe_int` | |
|
||||||
|
| `proxy_internal_load_7d` | `calculate_proxy_internal_load_7d` | `_safe_int` | |
|
||||||
|
| `monotony_score` | `calculate_monotony_score` | `_safe_float` | |
|
||||||
|
| `strain_score` | `calculate_strain_score` | `_safe_int` | |
|
||||||
|
| `rest_day_compliance` | `calculate_rest_day_compliance` | `_safe_int` | |
|
||||||
|
| `ability_balance_strength` | `calculate_ability_balance_strength` | `_safe_int` | abilities in `activity_log` |
|
||||||
|
| `ability_balance_endurance` | `calculate_ability_balance_endurance` | `_safe_int` | |
|
||||||
|
| `ability_balance_mental` | `calculate_ability_balance_mental` | `_safe_int` | |
|
||||||
|
| `ability_balance_coordination` | `calculate_ability_balance_coordination` | `_safe_int` | |
|
||||||
|
| `ability_balance_mobility` | `calculate_ability_balance_mobility` | `_safe_int` | |
|
||||||
|
| `vo2max_trend_28d` | `calculate_vo2max_trend_28d` | `_safe_float` | |
|
||||||
|
| `activity_score` | `calculate_activity_score` | `_safe_int` | |
|
||||||
|
| `training_frequency_by_type_md` | `get_training_frequency_by_type_data` | `get_training_frequency_by_type_md` | Markdown-Tabelle |
|
||||||
|
| `training_inter_session_gap_md` | `get_training_inter_session_gap_data` | `get_training_inter_session_gap_md` | Markdown-Text |
|
||||||
|
| `training_sessions_recent_json` | `get_training_sessions_recent_weeks_data` (+ `enrich_sessions_with_metrics`) | `_safe_json('training_sessions_recent_json')` | JSON inkl. `session_metrics[]` pro Session |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Schichten-Disziplin (Checkliste)
|
||||||
|
|
||||||
|
- [x] Kein `SELECT` auf `activity_log` / `activity_session_metrics` in den **Layer‑2a**-Funktionen oben — nur Aufrufe in Layer 1 bzw. `_safe_*`-Wrapper.
|
||||||
|
- [x] `get_activity_detail` / `get_training_sessions_recent_json` liefern EAV nur über **bereits gemergte** `session_metrics` (Merge-Kanon: `activity_log` vor EAV).
|
||||||
|
- [x] Registry-Metadaten: `data_layer_module` / `data_layer_function` pro Key in `placeholder_registrations/activity_metrics.py` und `activity_session_insights.py`.
|
||||||
|
- [x] Korrektur Registry: `activity_summary.resolver_function` = `get_activity_summary` (war veraltet: `_format_activity_summary`).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Nächste Schritte (Roadmap)
|
||||||
|
|
||||||
|
2. ~~**Registry-Texte:** `semantic_contract` / `known_limitations` für dynamische `session_metrics` (tcp/ttp) und Merge-Kanon — **erledigt** (`activity_detail`, `training_sessions_recent_json`); dazu **`trainingstyp_verteilung`**-Metadaten von veraltetem „JSON/Resolver-SQL“ auf Ist (**Layer 1 + Top-3-Text**) korrigiert.~~
|
||||||
|
3. **History / Layer 2b:** EAV-Zeitreihen nicht über Platzhalter, sondern dedizierte Layer‑1-/Chart-Pfade.
|
||||||
|
4. **Optional:** Gitea-Issue „Activity Layer 2a“ bei Änderungen an `activity_metrics` pflegen.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Referenzen
|
||||||
|
|
||||||
|
- `backend/placeholder_resolver.py` — `PLACEHOLDER_MAP` (Training/Aktivität)
|
||||||
|
- `backend/placeholder_registrations/activity_metrics.py`
|
||||||
|
- `backend/placeholder_registrations/activity_session_insights.py`
|
||||||
|
- `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` §2.1a (Navigation Read vs. Berechnen)
|
||||||
|
|
@ -89,6 +89,8 @@ Router: `backend/routers/admin_training_parameters.py`, `backend/routers/admin_a
|
||||||
|
|
||||||
## 5. Agent-Checkliste (nächste Iterationen)
|
## 5. Agent-Checkliste (nächste Iterationen)
|
||||||
|
|
||||||
|
**Layer 2a (Platzhalter Aktivität):** Abgleich Registry ↔ Resolver ↔ Layer 1 — [`ACTIVITY_LAYER2A_PLACEHOLDER_AUDIT.md`](./ACTIVITY_LAYER2A_PLACEHOLDER_AUDIT.md) (Issue #53). **Schritt 2:** `semantic_contract` / `known_limitations` für dynamische `session_metrics` und Korrektur `trainingstyp_verteilung` in der Registry.
|
||||||
|
|
||||||
Siehe **Phasen A–F** in [`ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md`](./ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md). Kurz:
|
Siehe **Phasen A–F** in [`ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md`](./ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md). Kurz:
|
||||||
|
|
||||||
- [x] **Phase A:** Kanon-Tabelle (eine Quelle pro Semantik) — [`ACTIVITY_SCALAR_KANON_TABLE.md`](./ACTIVITY_SCALAR_KANON_TABLE.md).
|
- [x] **Phase A:** Kanon-Tabelle (eine Quelle pro Semantik) — [`ACTIVITY_SCALAR_KANON_TABLE.md`](./ACTIVITY_SCALAR_KANON_TABLE.md).
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,8 @@ frontend/src/
|
||||||
- **Phase A:** Skalar-Kanon schriftlich fixiert — `.claude/docs/technical/ACTIVITY_SCALAR_KANON_TABLE.md`; `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` v1.1; Agent-Guide Checkliste Phase A erledigt.
|
- **Phase A:** Skalar-Kanon schriftlich fixiert — `.claude/docs/technical/ACTIVITY_SCALAR_KANON_TABLE.md`; `ACTIVITY_PRODUCTION_ARCHITECTURE_AND_PHASES.md` v1.1; Agent-Guide Checkliste Phase A erledigt.
|
||||||
- **Phase B:** `GET /api/activity` (Liste) reichert jede Zeile mit `session_metrics` über `enrich_sessions_with_metrics` an (gleiche Merge-Logik wie Detail); Consumer-Audit-Tabelle in Produktions-Architektur-Dok §4 Phase B.
|
- **Phase B:** `GET /api/activity` (Liste) reichert jede Zeile mit `session_metrics` über `enrich_sessions_with_metrics` an (gleiche Merge-Logik wie Detail); Consumer-Audit-Tabelle in Produktions-Architektur-Dok §4 Phase B.
|
||||||
- **Phase B (Export):** `routers/exportdata.py` — JSON-Export `activity` mit `session_metrics`; CSV-Gesamtexport Training-Details mit EAV-Zusammenfassung; ZIP `data/activity.csv` mit Zusatzspalte `session_metrics_json` (Standard-Import unverändert).
|
- **Phase B (Export):** `routers/exportdata.py` — JSON-Export `activity` mit `session_metrics`; CSV-Gesamtexport Training-Details mit EAV-Zusammenfassung; ZIP `data/activity.csv` mit Zusatzspalte `session_metrics_json` (Standard-Import unverändert).
|
||||||
|
- **Issue #53 / Layer 2a:** `ACTIVITY_LAYER2A_PLACEHOLDER_AUDIT.md` — alle 20 Aktivitäts-Platzhalter gegen Layer 1 geprüft; Registry-Fix `activity_summary.resolver_function` → `get_activity_summary`.
|
||||||
|
- **Layer 2a Schritt 2:** Registry-Texte `activity_detail`, `training_sessions_recent_json` (dynamische session_metrics, Merge-Kanon); `trainingstyp_verteilung` Metadaten an Phase-0c-Code angeglichen.
|
||||||
|
|
||||||
### Updates (11.04.2026 - Ernährung: TDEE, Bilanz, Kalorien-Score)
|
### Updates (11.04.2026 - Ernährung: TDEE, Bilanz, Kalorien-Score)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
"""
|
"""
|
||||||
Activity Metrics Placeholder Registrations
|
Activity Metrics Placeholder Registrations
|
||||||
|
|
||||||
Registers 17 Aktivitäts-Platzhalter hier; 3 Session-/Erholungs-Keys in activity_session_insights.py (20 gesamt).
|
Registers 17 Aktivitäts-Platzhalter hier; 3 weitere Keys in activity_session_insights.py (**20 gesamt** in PLACEHOLDER_MAP).
|
||||||
|
|
||||||
Evidence-based metadata with clear tagging of source.
|
Evidence-based metadata with clear tagging of source.
|
||||||
|
|
||||||
|
|
@ -43,7 +43,7 @@ def register_activity_group_1():
|
||||||
category="Aktivität",
|
category="Aktivität",
|
||||||
description="Zusammenfassung der letzten 14 Tage Aktivität",
|
description="Zusammenfassung der letzten 14 Tage Aktivität",
|
||||||
resolver_module="backend/placeholder_resolver.py",
|
resolver_module="backend/placeholder_resolver.py",
|
||||||
resolver_function="_format_activity_summary",
|
resolver_function="get_activity_summary",
|
||||||
data_layer_module=None,
|
data_layer_module=None,
|
||||||
data_layer_function=None,
|
data_layer_function=None,
|
||||||
source_tables=["activity_log", "training_types"],
|
source_tables=["activity_log", "training_types"],
|
||||||
|
|
@ -127,17 +127,23 @@ def register_activity_group_1():
|
||||||
activity_detail_metadata = PlaceholderMetadata(
|
activity_detail_metadata = PlaceholderMetadata(
|
||||||
key="activity_detail",
|
key="activity_detail",
|
||||||
category="Aktivität",
|
category="Aktivität",
|
||||||
description="Detaillierte Liste der letzten 14 Tage Aktivität (Kopfzeile + EAV-Metriken)",
|
description=(
|
||||||
|
"Letzte 14 Tage: pro Session Kopfzeile (activity_log) plus gemergte Profil-Metriken "
|
||||||
|
"(dynamische Keys je training_category / training_type_id)"
|
||||||
|
),
|
||||||
resolver_module="backend/placeholder_resolver.py",
|
resolver_module="backend/placeholder_resolver.py",
|
||||||
resolver_function="get_activity_detail",
|
resolver_function="get_activity_detail",
|
||||||
data_layer_module="backend/data_layer/activity_metrics.py",
|
data_layer_module="backend/data_layer/activity_metrics.py",
|
||||||
data_layer_function="get_activity_detail_data",
|
data_layer_function="get_activity_detail_data",
|
||||||
source_tables=["activity_log", "activity_session_metrics", "training_parameters"],
|
source_tables=["activity_log", "activity_session_metrics", "training_parameters"],
|
||||||
semantic_contract=(
|
semantic_contract=(
|
||||||
"Liefert bis zu 50 Einheiten (neueste zuerst) der letzten 14 Tage über "
|
"Layer 1: get_activity_detail_data lädt Sessions, enrich_sessions_with_metrics fügt "
|
||||||
"get_activity_detail_data: activity_log-Spalten plus "
|
"session_metrics hinzu — effektive Liste aus merge_column_backed_and_eav_metrics: nur "
|
||||||
"enrich_sessions_with_metrics (activity_session_metrics / Profil-EAV). "
|
"Parameter aus dem Attributschema (tcp/ttp), sortiert nach key. "
|
||||||
"Formatter hängt nicht-leere EAV-Werte als „| EAV: key=value; …“ an."
|
"Leseregel Kanon: activity_log-Spalte (source_field, Registry-Feld, Legacy-Spalte für "
|
||||||
|
"EAV-primäre Keys) schlägt EAV, wenn beide Werte liefern. "
|
||||||
|
"Layer 2a: Zeilen mit „| EAV: key=value; …“ nur für nicht-leere session_metrics; "
|
||||||
|
"die Menge der Keys ist admin-/profilabhängig, kein festes Prompt-Schema."
|
||||||
),
|
),
|
||||||
business_meaning=(
|
business_meaning=(
|
||||||
"Detaillierte Trainingshistorie für KI-Prompts, die Muster, Progressionen "
|
"Detaillierte Trainingshistorie für KI-Prompts, die Muster, Progressionen "
|
||||||
|
|
@ -167,8 +173,10 @@ def register_activity_group_1():
|
||||||
),
|
),
|
||||||
known_limitations=(
|
known_limitations=(
|
||||||
"Keine Profil-Qualitätsfilterung in dieser Liste. Max. 20 Zeilen im Prompt-Output "
|
"Keine Profil-Qualitätsfilterung in dieser Liste. Max. 20 Zeilen im Prompt-Output "
|
||||||
"(Hard-Limit Resolver). Doppelte Spalten (z.B. duration_min in Kopf und EAV) können "
|
"(Hard-Limit Resolver). session_metrics kann leer sein (kein Typ, kein Profil, keine EAV-Zeilen). "
|
||||||
"in EAV wiederholt erscheinen — KI kann dominante Spalte nutzen."
|
"Keys und Anzahl Metriken variieren je Instanz/Admin — nicht von festen Platzhaltern in anderen "
|
||||||
|
"Prompts ausgehen. Nur im effektiven Merge erscheinende Parameter; keine verwaisten EAV-Keys "
|
||||||
|
"außerhalb des Schemas."
|
||||||
),
|
),
|
||||||
layer_1_decision="activity_metrics.get_activity_detail_data (+ enrich_sessions_with_metrics)",
|
layer_1_decision="activity_metrics.get_activity_detail_data (+ enrich_sessions_with_metrics)",
|
||||||
layer_2a_decision="get_activity_detail (Formatierung)",
|
layer_2a_decision="get_activity_detail (Formatierung)",
|
||||||
|
|
@ -211,56 +219,47 @@ def register_activity_group_1():
|
||||||
trainingstyp_verteilung_metadata = PlaceholderMetadata(
|
trainingstyp_verteilung_metadata = PlaceholderMetadata(
|
||||||
key="trainingstyp_verteilung",
|
key="trainingstyp_verteilung",
|
||||||
category="Aktivität",
|
category="Aktivität",
|
||||||
description="Trainingstypen-Verteilung der letzten 14 Tage als JSON",
|
description="Verteilung nach training_category (14 Tage): Top 3 als kompakte Prozent-Textzeile",
|
||||||
resolver_module="backend/placeholder_resolver.py",
|
resolver_module="backend/placeholder_resolver.py",
|
||||||
resolver_function="_format_trainingstyp_verteilung",
|
resolver_function="get_trainingstyp_verteilung",
|
||||||
data_layer_module=None,
|
data_layer_module="backend/data_layer/activity_metrics.py",
|
||||||
data_layer_function=None,
|
data_layer_function="get_training_type_distribution_data",
|
||||||
source_tables=["activity_log", "training_types"],
|
source_tables=["activity_log"],
|
||||||
semantic_contract=(
|
semantic_contract=(
|
||||||
"Liefert eine JSON-Struktur mit der Verteilung der Trainingstypen über 14 Tage. "
|
"Layer 1: get_training_type_distribution_data — Anteil je training_category am "
|
||||||
"Für jeden Trainingstyp: Anzahl Einheiten, Gesamtdauer (Minuten), "
|
"Gesamt-Session-Count im Fenster (auch unkategorisierte zählen im Nenner). "
|
||||||
"Prozentanteil an Gesamtdauer. Sortiert nach Dauer absteigend."
|
"Layer 2a: Top 3 Kategorien als „Name: p%“ kommagetrennt; bei fehlenden Daten Kurz-Hinweis."
|
||||||
),
|
),
|
||||||
business_meaning=(
|
business_meaning=(
|
||||||
"Analyse-Placeholder für Trainingsvielfalt und -schwerpunkte. "
|
"Analyse-Placeholder für Trainingsvielfalt und -schwerpunkte. "
|
||||||
"Erlaubt KI-Prompts, Imbalancen zu erkennen (z.B. nur Kraft, keine Ausdauer) "
|
"Erlaubt KI-Prompts, Imbalancen zu erkennen (z.B. nur Kraft, keine Ausdauer) "
|
||||||
"oder Zielkonformität zu prüfen (z.B. 'zu wenig Mobilität')."
|
"oder Zielkonformität zu prüfen (z.B. 'zu wenig Mobilität')."
|
||||||
),
|
),
|
||||||
unit="json",
|
unit="text",
|
||||||
time_window="14d",
|
time_window="14d",
|
||||||
output_type=OutputType.JSON,
|
output_type=OutputType.TEXT_SUMMARY,
|
||||||
placeholder_type=PlaceholderType.INTERPRETED,
|
placeholder_type=PlaceholderType.INTERPRETED,
|
||||||
format_hint="JSON Object mit Trainingstyp als Key, Value: {count, duration_min, percentage}",
|
format_hint="Eine Zeile: bis zu drei „Kategorie: Prozent%“, durch Komma getrennt",
|
||||||
example_output=(
|
example_output="cardio: 45%, strength: 30%, mobility: 15%",
|
||||||
'{"Krafttraining": {"count": 5, "duration_min": 180, "percentage": 57}, '
|
|
||||||
'"Ausdauer": {"count": 4, "duration_min": 90, "percentage": 29}, '
|
|
||||||
'"Mobilität": {"count": 3, "duration_min": 45, "percentage": 14}}'
|
|
||||||
),
|
|
||||||
minimum_data_requirements=None,
|
minimum_data_requirements=None,
|
||||||
quality_filter_policy=None,
|
quality_filter_policy=None,
|
||||||
confidence_logic="Keine Confidence-Berechnung. Aggregation basiert auf verfügbaren Daten.",
|
confidence_logic="Wie get_training_type_distribution_data (calculate_confidence über categorized_count)",
|
||||||
missing_value_policy=MissingValuePolicy(
|
missing_value_policy=MissingValuePolicy(
|
||||||
available=False,
|
available=False,
|
||||||
value_raw=None,
|
value_raw=None,
|
||||||
missing_reason="no_data",
|
missing_reason="no_data",
|
||||||
legacy_display="{}"
|
legacy_display="Keine kategorisierten Trainings"
|
||||||
),
|
),
|
||||||
known_limitations=(
|
known_limitations=(
|
||||||
"OLD RESOLVER PATTERN: Keine Data Layer Funktion. "
|
"Nur Sessions mit gesetztem training_category fließen in die Verteilungsliste; "
|
||||||
"Aggregation direkt im Resolver. "
|
"Prozente beziehen sich auf alle Sessions im Fenster (Nenner = total_sessions). "
|
||||||
"CRITICAL: Keine Qualitätsfilterung - auch ungültige Einheiten werden aggregiert. "
|
"Keine Qualitätsfilterung der Einheiten. Kein drill-down nach training_type_id in diesem Platzhalter."
|
||||||
"JOIN mit training_types für Typ-Namen. "
|
|
||||||
"EDGE CASE: Einheiten ohne training_type_id werden ignoriert (LEFT JOIN)."
|
|
||||||
),
|
),
|
||||||
layer_1_decision="NONE - Old resolver pattern (direct SQL aggregation in resolver)",
|
layer_1_decision="activity_metrics.get_training_type_distribution_data",
|
||||||
layer_2a_decision="Placeholder Resolver (aggregation + JSON formatting)",
|
layer_2a_decision="get_trainingstyp_verteilung (Top 3 als Text)",
|
||||||
layer_2b_reuse_possible=True,
|
layer_2b_reuse_possible=True,
|
||||||
architecture_alignment=(
|
architecture_alignment="Phase 0c — Layer 1 + Formatierung",
|
||||||
"PARTIALLY ALIGNED: JSON output structure suitable for chart endpoints, "
|
issue_53_alignment="Layer 1"
|
||||||
"but no data layer separation. Should be refactored."
|
|
||||||
),
|
|
||||||
issue_53_alignment="PARTIALLY ALIGNED - output format good, layer separation missing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
trainingstyp_verteilung_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
trainingstyp_verteilung_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||||||
|
|
|
||||||
|
|
@ -130,8 +130,8 @@ def register_activity_session_insights():
|
||||||
key="training_sessions_recent_json",
|
key="training_sessions_recent_json",
|
||||||
category="Aktivität",
|
category="Aktivität",
|
||||||
description=(
|
description=(
|
||||||
"JSON: letzte ISO-Kalenderwochen mit Einheiten (Datum, Art, Dauer, kcal, HF Ø/max, RPE, Kategorie, "
|
"JSON: ISO-Wochen mit Sessions (activity_log-Kopf) plus session_metrics[] — gemergte Profil-Metriken "
|
||||||
"session_id, session_metrics[] aus EAV)"
|
"(dynamische Keys)"
|
||||||
),
|
),
|
||||||
resolver_module="backend/placeholder_resolver.py",
|
resolver_module="backend/placeholder_resolver.py",
|
||||||
resolver_function="_safe_json",
|
resolver_function="_safe_json",
|
||||||
|
|
@ -139,9 +139,15 @@ def register_activity_session_insights():
|
||||||
data_layer_function="get_training_sessions_recent_weeks_data",
|
data_layer_function="get_training_sessions_recent_weeks_data",
|
||||||
source_tables=["activity_log", "training_types", "activity_session_metrics", "training_parameters"],
|
source_tables=["activity_log", "training_types", "activity_session_metrics", "training_parameters"],
|
||||||
semantic_contract=(
|
semantic_contract=(
|
||||||
"Struktur weeks[].week_iso, sessions[] mit Feldern für KI-Auswertung; "
|
"Root: weeks[] mit week_iso; sessions[] pro Einheit u. a. id, date, activity_type, "
|
||||||
"session_metrics[] = Layer-1-EAV-Werte (key, data_type, unit, value) wenn konfiguriert/gespeichert. "
|
"duration_min, kcal_active, hr_avg, hr_max, rpe, training_category, training_type_name, "
|
||||||
"Default 4 ISO-Wochen zurück."
|
"session_metrics[]. "
|
||||||
|
"session_metrics: effektive Liste nach merge_column_backed_and_eav_metrics — Einträge mit "
|
||||||
|
"training_parameter_id, key, data_type, unit, value; nur Parameter aus Attributschema "
|
||||||
|
"(training_category_parameter + training_type_parameter Overrides), keys sortiert. "
|
||||||
|
"Kanon Lesen: activity_log-Spalte vor EAV bei Konflikt. "
|
||||||
|
"meta: weeks_requested, days_loaded, session_count, confidence. "
|
||||||
|
"Default ca. 4 ISO-Wochen (28 Tage Rohdatenfenster)."
|
||||||
),
|
),
|
||||||
business_meaning="Rohkontext für wochenweise Auswertung (Erholung, Intensität) in der KI",
|
business_meaning="Rohkontext für wochenweise Auswertung (Erholung, Intensität) in der KI",
|
||||||
unit="JSON string",
|
unit="JSON string",
|
||||||
|
|
@ -160,8 +166,11 @@ def register_activity_session_insights():
|
||||||
legacy_display="{}",
|
legacy_display="{}",
|
||||||
),
|
),
|
||||||
known_limitations=(
|
known_limitations=(
|
||||||
"Token-Länge bei vielen Sessions beachten. training_type_name nur bei gesetztem training_type_id. "
|
"Token-Länge bei vielen Sessions. training_type_name nur bei gesetztem training_type_id. "
|
||||||
"session_metrics nur befüllt, wenn Admin-Profile zugeordnet und Werte in EAV gespeichert sind."
|
"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. "
|
||||||
|
"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_1_decision="activity_metrics.get_training_sessions_recent_weeks_data",
|
||||||
layer_2a_decision="_safe_json('training_sessions_recent_json')",
|
layer_2a_decision="_safe_json('training_sessions_recent_json')",
|
||||||
|
|
|
||||||
|
|
@ -1524,7 +1524,7 @@ PLACEHOLDER_MAP: Dict[str, Callable[[str], str]] = {
|
||||||
'{{intake_volatility}}': lambda pid: _safe_str('intake_volatility', pid),
|
'{{intake_volatility}}': lambda pid: _safe_str('intake_volatility', pid),
|
||||||
'{{nutrition_score}}': lambda pid: _safe_int('nutrition_score', pid),
|
'{{nutrition_score}}': lambda pid: _safe_int('nutrition_score', pid),
|
||||||
|
|
||||||
# Training / Aktivität (17 Registry-Keys — gebündelt; activity_score hier, nicht unter Meta Scores)
|
# Training / Aktivität (20 Keys: 17 activity_metrics + 3 activity_session_insights; activity_score hier, nicht unter Meta Scores)
|
||||||
'{{activity_summary}}': get_activity_summary,
|
'{{activity_summary}}': get_activity_summary,
|
||||||
'{{activity_detail}}': get_activity_detail,
|
'{{activity_detail}}': get_activity_detail,
|
||||||
'{{trainingstyp_verteilung}}': get_trainingstyp_verteilung,
|
'{{trainingstyp_verteilung}}': get_trainingstyp_verteilung,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user