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