# 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)