mitai-jinkendo/.claude/docs/technical/TRAINING_PROFILE_RESOLVER_LAYER1.md

149 lines
5.8 KiB
Markdown
Raw Normal View History

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