# Training Profile Resolver (Layer 1) — technisches Scaffold **Stand:** 2026-04-06 **Zweck:** Erweiterbare technische Basis für spätere trainingsprofil-basierte Auswertungen, ohne freie Formel-/Skript-Engine und ohne Kopplung an KI oder Charts. --- ## 1. Einordnung in Layer 1 | Aspekt | Beschreibung | |--------|----------------| | Ort | `backend/data_layer/training_profile/` | | Rolle | Reine Orchestrierung: Templates → registrierte Built-in-Algorithmen → strukturiertes Ergebnis inkl. Focus-Area-Beiträge | | Single Source of Truth | Berechnungslogik der Algorithmen lebt in Python-Modulen; Templates wählen nur **Algorithmus-ID + Parameter + Dimensionen + FA-Mapping** | | Rückwärtskompatibel | Keine Änderungen an bestehenden Data-Layer-Metriken, Placeholdern oder Chart-Routern | --- ## 2. Modulübersicht | Pfad | Inhalt | |------|--------| | `models.py` | `CalculationTemplate`, `DimensionSpec`, `FocusAreaMapping`, `TrainingBaseProfile`, `TrainingEvaluationResult`, `AlgorithmRunResult` | | `resolver.py` | `resolve_training_evaluation()`, `resolve_for_base_profile()` | | `algorithms/registry.py` | `register_algorithm`, `get_algorithm`, `list_algorithm_ids` | | `algorithms/builtin/threshold_band.py` | Beispiel: Schwellen-Bänder → Score 0–1 | | `algorithms/builtin/linear_range.py` | Beispiel: lineare Abbildung [min,max] → [0,1] | | `templates/registry.py` | Beispiel-Templates (deklarativ, in-code) | | `profiles/registry.py` | Beispiel-Trainings-Basisprofile (Default-Template, optionale Dimensions-Whitelist) | --- ## 3. Built-in-Algorithmen - Algorithmen sind **fest im Code** implementiert und über eine **ID** referenzierbar. - Neue Algorithmen: Funktion mit Signatur `(*, inputs, params) -> AlgorithmRunResult` und `register_algorithm(id, fn)` (Start-up-Registrierung in `registry.py` oder Import eines Moduls, das registriert). - **Nicht** vorgesehen: Nutzerdefinierte Ausdrücke, DSL, `eval`, externe Skripte. Implementiert (Beispiele): - `threshold_band` — `params.value_key`, `params.bands` (Liste mit `max` / `score`) - `linear_range` — `params.value_key`, `min_value`, `max_value`, optional `invert` --- ## 4. Templates (deklarativ) Ein `CalculationTemplate` besteht aus: - `id`, `version`, `label` - `dimensions`: Liste von `DimensionSpec` mit: - `key` — Dimensionsname - `algorithm_id` — referenziert registrierten Algorithmus - `inputs` — erwartete Schlüssel im flachen `activity_inputs`-Dict des Aufrufers - `params` — JSON-serialisierbare Parameter für den Algorithmus - `maps_to` — Tupel `(focus_area_key, weight)` — gewichteter Anteil der **normalisierten** Dimension am jeweiligen Focus Area Aggregation: Pro Dimension wird `normalized_score * weight` pro Focus Area addiert (`focus_area_contributions`). --- ## 5. Trainings-Basisprofile (Scaffold) `TrainingBaseProfile`: - `key`, `label` - `default_template_id` — verweist auf ein `CalculationTemplate` - optional `allowed_dimension_keys` — nur diese Dimensionen aus dem Template werden ausgeführt (Filter) Aktuell **nur In-Code-Registry**; später denkbar: DB-Verknüpfung Trainingstyp → Profil-Key. --- ## 6. Ergebnisstruktur (`TrainingEvaluationResult`) - `template_id`, `template_version`, `base_profile_key` - `dimension_results[]` — pro Dimension: Scores, fehlende Inputs, Evidence - `focus_area_contributions` — `dict[str, float]` (Focus-Area-Key → aggregierter Beitrag) - `confidence` — `high` | `medium` | `low` | `insufficient` (heuristisch aus fehlenden Pflicht-Inputs) - `evidence` — Metadaten (z. B. Anzahl Dimensionen, Input-Keys) - optional `trace` — bei `include_trace=True` für Debugging `to_serializable()` liefert ein JSON-taugliches Dict für APIs/Persistenz. --- ## 7. Öffentliche API (Import) ```python from data_layer.training_profile import ( resolve_training_evaluation, resolve_for_base_profile, TrainingEvaluationResult, CalculationTemplate, ) ``` Registries: ```python from data_layer.training_profile.templates.registry import get_calculation_template from data_layer.training_profile.profiles.registry import get_training_base_profile from data_layer.training_profile.algorithms.registry import get_algorithm, list_algorithm_ids ``` --- ## 8. Erweiterungspunkte (für spätere Produktlogik) 1. **Neue Algorithmen** — neue Datei unter `algorithms/builtin/`, in `registry.py` registrieren. 2. **Templates** — weitere `CalculationTemplate`-Instanzen in `templates/registry.py` oder später aus DB laden (Loader baut dieselben Dataclasses). 3. **Profile** — weitere `TrainingBaseProfile`-Einträge; Anbindung an `training_types` / Aktivität. 4. **Confidence/Evidence** — feinere Regeln (Datenqualität, Mindestkriterien) im Resolver oder in den Algorithmen. 5. **Normalisierung der FA-Beiträge** — optional globale Skalierung/Cap (aktuell rein additive Gewichtung). --- ## 9. Was absichtlich offen ist - Finale Domänenregeln (welche Dimensionen für welchen Sport) - Vollständige Liste Basisprofile und Templates - Persistenz von Evaluationsergebnissen - Integration in Placeholder-Resolver, Charts, Admin-UI - Validierung gegen `focus_area_definitions` (DB-Keys) --- ## 10. Kritische Einschätzung | Bereich | Bewertung | |---------|-----------| | Registry + Algorithmus-Schnittstelle | Robust, testbar, erweiterbar | | Template-Modelle (frozen dataclasses) | Stabil, typsicher, serialisierbar | | Beispiel-Algorithmen | Minimal, nur zur Demonstration der Pipeline | | Confidence | Heuristik — für Produktion noch abzustimmen | | Focus-Area-Gewichte | Additiv, nicht normiert — Domänenentscheidung für später | --- ## 11. Tests `backend/tests/test_training_profile_resolver.py` — Registry, Resolver, Profil-Filter, Serialisierung, unbekannter Algorithmus. Ausführen (aus `backend/`): ```bash python -m pytest tests/test_training_profile_resolver.py -v ```