Implements complete placeholder registry for Activity & Training metrics following Phase 0c Multi-Layer Architecture pattern. SCOPE: 17 Activity Placeholders - Group 1 (3): Legacy Resolver - activity_summary, activity_detail, trainingstyp_verteilung - Group 2 (7): Basic Metrics - volume, frequency, quality, load, monotony, strain, rest compliance - Group 3 (7): Advanced Metrics - 5x ability_balance, vo2max_trend, activity_score IMPLEMENTATION: - File: backend/placeholder_registrations/activity_metrics.py (~1,100 lines) - Pattern: Nutrition Part A (common_metadata + evidence-based tagging) - Evidence: CODE_DERIVED (58%), DRAFT_DERIVED (16%), MIXED (15%), TO_VERIFY (6%), UNRESOLVED (5%) - Formulas: All documented in known_limitations (Load Model, Monotony, Strain, Ability Balance, Activity Score) CRITICAL ISSUES IDENTIFIED (NOT FIXED per NO LOGIC CHANGES): 1. quality_label field mismatch (quality_sessions_pct) - TO_VERIFY 2. RPE moderate quality mapping bug (proxy_internal_load_7d) - CODE_DERIVED 3. JSONB dependencies (6 placeholders) - ability_balance_*, rest_day_compliance 4. vo2max_trend_28d questionable category (Recovery vs. Activity) - TO_VERIFY TESTING: ✓ All 17 placeholders registered successfully ✓ Registry size: 48 (31 pre-existing + 17 new) ✓ Dev backend integration: no errors ✓ Auto-registration on module import: working ARCHITECTURE ALIGNMENT: - Phase 0c Multi-Layer: 14/17 aligned (Group 2 + 3) - Old Resolver Pattern: 3/17 (Group 1 - documented, should be refactored) - Layer separation: data_layer → resolver → export FILES: - NEW: backend/placeholder_registrations/activity_metrics.py - MODIFIED: backend/placeholder_registrations/__init__.py (added import) - MODIFIED: CLAUDE.md (placeholder registry rules) DOCUMENTATION: - Gap Analysis: .claude/task/rework_0b_placeholder/ACTIVITY_CLUSTER_GAP_ANALYSIS.md - Code Inspection: .claude/task/rework_0b_placeholder/ACTIVITY_CLUSTER_CODE_INSPECTION.md - Implementation Report: .claude/task/rework_0b_placeholder/ACTIVITY_CLUSTER_IMPLEMENTATION_REPORT.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1113 lines
62 KiB
Python
1113 lines
62 KiB
Python
"""
|
||
Activity Metrics Placeholder Registrations
|
||
|
||
Registers all 17 activity-related placeholders in the central placeholder registry.
|
||
|
||
Evidence-based metadata with clear tagging of source.
|
||
|
||
Groups:
|
||
- Legacy Resolver (3): activity_summary, activity_detail, trainingstyp_verteilung
|
||
- Basic Metrics (7): training_minutes_week, training_frequency_7d, quality_sessions_pct,
|
||
proxy_internal_load_7d, monotony_score, strain_score, rest_day_compliance
|
||
- Advanced Metrics (7): ability_balance_*, vo2max_trend_28d, activity_score
|
||
"""
|
||
|
||
from placeholder_registry import (
|
||
PlaceholderMetadata,
|
||
MissingValuePolicy,
|
||
EvidenceType,
|
||
OutputType,
|
||
PlaceholderType,
|
||
register_placeholder
|
||
)
|
||
|
||
|
||
# =============================================================================
|
||
# GRUPPE 1: Legacy Resolver (3 Placeholders)
|
||
# =============================================================================
|
||
|
||
def register_activity_group_1():
|
||
"""
|
||
Register Group 1: Legacy Resolver placeholders.
|
||
|
||
These use old resolver pattern (direct formatting in resolver, no data layer).
|
||
"""
|
||
|
||
# ── activity_summary ──────────────────────────────────────────────────────
|
||
|
||
activity_summary_metadata = PlaceholderMetadata(
|
||
key="activity_summary",
|
||
category="Aktivität",
|
||
description="Zusammenfassung der letzten 14 Tage Aktivität",
|
||
resolver_module="backend/placeholder_resolver.py",
|
||
resolver_function="_format_activity_summary",
|
||
data_layer_module=None,
|
||
data_layer_function=None,
|
||
source_tables=["activity_log", "training_types"],
|
||
semantic_contract=(
|
||
"Liefert eine kompakte textuelle Zusammenfassung der Trainingsaktivitäten "
|
||
"der letzten 14 Tage. Beinhaltet: Anzahl Einheiten, Gesamtdauer, "
|
||
"Trainingstypen-Verteilung (Top 3), durchschnittliche Dauer pro Einheit."
|
||
),
|
||
business_meaning=(
|
||
"Schneller Überblick für KI-Prompts über aktuelle Trainingsaktivität. "
|
||
"Erlaubt Prompt-Autoren, Trainingsvolumen und -vielfalt auf einen Blick "
|
||
"zu erfassen ohne einzelne Datenpunkte zu konsumieren."
|
||
),
|
||
unit="text",
|
||
time_window="14d",
|
||
output_type=OutputType.TEXT_SUMMARY,
|
||
placeholder_type=PlaceholderType.INTERPRETED,
|
||
format_hint="Mehrere Sätze, menschenlesbar, Deutsch",
|
||
example_output=(
|
||
"14 Einheiten (315 min gesamt). Top-Typen: Krafttraining (5x, 180 min), "
|
||
"Ausdauer (4x, 90 min), Mobilität (3x, 30 min). Ø Dauer: 22 min/Einheit."
|
||
),
|
||
minimum_data_requirements=None,
|
||
quality_filter_policy=None,
|
||
confidence_logic=(
|
||
"Keine formale Confidence-Berechnung. Verfügbarkeit = mindestens 1 "
|
||
"activity_log Eintrag in 14d."
|
||
),
|
||
missing_value_policy=MissingValuePolicy(
|
||
available=False,
|
||
value_raw=None,
|
||
missing_reason="no_data",
|
||
legacy_display="Keine Aktivitätsdaten"
|
||
),
|
||
known_limitations=(
|
||
"OLD RESOLVER PATTERN: Keine Data Layer Funktion. Formatierung direkt "
|
||
"im Resolver. JOIN mit training_types für Typ-Namen. "
|
||
"CRITICAL: Keine Qualitätsprüfung - auch 1-Minuten-Einheiten werden gezählt."
|
||
),
|
||
layer_1_decision="NONE - Old resolver pattern (direct SQL in resolver)",
|
||
layer_2a_decision="Placeholder Resolver (formatting + SQL query)",
|
||
layer_2b_reuse_possible=False,
|
||
architecture_alignment=(
|
||
"NOT ALIGNED with Phase 0c Multi-Layer Architecture. "
|
||
"Should be refactored to use data_layer function."
|
||
),
|
||
issue_53_alignment="NOT ALIGNED - no layer separation"
|
||
)
|
||
|
||
activity_summary_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("category", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
activity_summary_metadata.set_evidence("resolver_module", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("data_layer_module", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("semantic_contract", EvidenceType.MIXED)
|
||
activity_summary_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
activity_summary_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("time_window", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("output_type", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("placeholder_type", EvidenceType.MIXED)
|
||
activity_summary_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("minimum_data_requirements", EvidenceType.UNRESOLVED)
|
||
activity_summary_metadata.set_evidence("quality_filter_policy", EvidenceType.UNRESOLVED)
|
||
activity_summary_metadata.set_evidence("confidence_logic", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("missing_value_policy", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("layer_1_decision", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("layer_2a_decision", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("architecture_alignment", EvidenceType.CODE_DERIVED)
|
||
activity_summary_metadata.set_evidence("issue_53_alignment", EvidenceType.CODE_DERIVED)
|
||
|
||
register_placeholder(activity_summary_metadata)
|
||
|
||
# ── activity_detail ───────────────────────────────────────────────────────
|
||
|
||
activity_detail_metadata = PlaceholderMetadata(
|
||
key="activity_detail",
|
||
category="Aktivität",
|
||
description="Detaillierte Liste der letzten 14 Tage Aktivität",
|
||
resolver_module="backend/placeholder_resolver.py",
|
||
resolver_function="_format_activity_detail",
|
||
data_layer_module=None,
|
||
data_layer_function=None,
|
||
source_tables=["activity_log", "training_types"],
|
||
semantic_contract=(
|
||
"Liefert eine strukturierte Liste aller Trainingseinheiten der letzten 14 Tage. "
|
||
"Jede Einheit: Datum, Trainingstyp, Dauer (Minuten), optional Notizen. "
|
||
"Sortiert chronologisch absteigend (neueste zuerst)."
|
||
),
|
||
business_meaning=(
|
||
"Detaillierte Trainingshistorie für KI-Prompts, die Muster, Progressionen "
|
||
"oder Abweichungen analysieren sollen. Erlaubt Erkennung von Trainingszyklen, "
|
||
"Pausentagen, Intensitätsmustern."
|
||
),
|
||
unit="list",
|
||
time_window="14d",
|
||
output_type=OutputType.LIST,
|
||
placeholder_type=PlaceholderType.RAW_DATA,
|
||
format_hint="Liste von Strings, eine Zeile pro Einheit: 'YYYY-MM-DD: Typ (Dauer min)'",
|
||
example_output=(
|
||
"2026-03-28: Krafttraining (45 min)\\n"
|
||
"2026-03-27: Laufen (30 min)\\n"
|
||
"2026-03-25: Yoga (20 min)"
|
||
),
|
||
minimum_data_requirements=None,
|
||
quality_filter_policy=None,
|
||
confidence_logic="Keine Confidence-Berechnung. Rohdaten-Liste.",
|
||
missing_value_policy=MissingValuePolicy(
|
||
available=False,
|
||
value_raw=None,
|
||
missing_reason="no_data",
|
||
legacy_display="Keine Aktivitätsdaten"
|
||
),
|
||
known_limitations=(
|
||
"OLD RESOLVER PATTERN: Keine Data Layer Funktion. "
|
||
"Formatierung direkt im Resolver. "
|
||
"CRITICAL: Keine Qualitätsfilterung - auch ungültige Einheiten (z.B. 0 min) "
|
||
"werden gelistet. JOIN mit training_types für Typ-Namen."
|
||
),
|
||
layer_1_decision="NONE - Old resolver pattern (direct SQL in resolver)",
|
||
layer_2a_decision="Placeholder Resolver (formatting + SQL query)",
|
||
layer_2b_reuse_possible=False,
|
||
architecture_alignment=(
|
||
"NOT ALIGNED with Phase 0c Multi-Layer Architecture. "
|
||
"Should be refactored to use data_layer function."
|
||
),
|
||
issue_53_alignment="NOT ALIGNED - no layer separation"
|
||
)
|
||
|
||
activity_detail_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("category", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
activity_detail_metadata.set_evidence("resolver_module", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("data_layer_module", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("semantic_contract", EvidenceType.MIXED)
|
||
activity_detail_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
activity_detail_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("time_window", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("output_type", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("placeholder_type", EvidenceType.MIXED)
|
||
activity_detail_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("minimum_data_requirements", EvidenceType.UNRESOLVED)
|
||
activity_detail_metadata.set_evidence("quality_filter_policy", EvidenceType.UNRESOLVED)
|
||
activity_detail_metadata.set_evidence("confidence_logic", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("missing_value_policy", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("layer_1_decision", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("layer_2a_decision", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("architecture_alignment", EvidenceType.CODE_DERIVED)
|
||
activity_detail_metadata.set_evidence("issue_53_alignment", EvidenceType.CODE_DERIVED)
|
||
|
||
register_placeholder(activity_detail_metadata)
|
||
|
||
# ── trainingstyp_verteilung ───────────────────────────────────────────────
|
||
|
||
trainingstyp_verteilung_metadata = PlaceholderMetadata(
|
||
key="trainingstyp_verteilung",
|
||
category="Aktivität",
|
||
description="Trainingstypen-Verteilung der letzten 14 Tage als JSON",
|
||
resolver_module="backend/placeholder_resolver.py",
|
||
resolver_function="_format_trainingstyp_verteilung",
|
||
data_layer_module=None,
|
||
data_layer_function=None,
|
||
source_tables=["activity_log", "training_types"],
|
||
semantic_contract=(
|
||
"Liefert eine JSON-Struktur mit der Verteilung der Trainingstypen über 14 Tage. "
|
||
"Für jeden Trainingstyp: Anzahl Einheiten, Gesamtdauer (Minuten), "
|
||
"Prozentanteil an Gesamtdauer. Sortiert nach Dauer absteigend."
|
||
),
|
||
business_meaning=(
|
||
"Analyse-Placeholder für Trainingsvielfalt und -schwerpunkte. "
|
||
"Erlaubt KI-Prompts, Imbalancen zu erkennen (z.B. nur Kraft, keine Ausdauer) "
|
||
"oder Zielkonformität zu prüfen (z.B. 'zu wenig Mobilität')."
|
||
),
|
||
unit="json",
|
||
time_window="14d",
|
||
output_type=OutputType.JSON,
|
||
placeholder_type=PlaceholderType.INTERPRETED,
|
||
format_hint="JSON Object mit Trainingstyp als Key, Value: {count, duration_min, percentage}",
|
||
example_output=(
|
||
'{"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,
|
||
quality_filter_policy=None,
|
||
confidence_logic="Keine Confidence-Berechnung. Aggregation basiert auf verfügbaren Daten.",
|
||
missing_value_policy=MissingValuePolicy(
|
||
available=False,
|
||
value_raw=None,
|
||
missing_reason="no_data",
|
||
legacy_display="{}"
|
||
),
|
||
known_limitations=(
|
||
"OLD RESOLVER PATTERN: Keine Data Layer Funktion. "
|
||
"Aggregation direkt im Resolver. "
|
||
"CRITICAL: Keine Qualitätsfilterung - auch ungültige Einheiten werden aggregiert. "
|
||
"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_2a_decision="Placeholder Resolver (aggregation + JSON formatting)",
|
||
layer_2b_reuse_possible=True,
|
||
architecture_alignment=(
|
||
"PARTIALLY ALIGNED: JSON output structure suitable for chart endpoints, "
|
||
"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("category", EvidenceType.CODE_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("resolver_module", EvidenceType.CODE_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("data_layer_module", EvidenceType.CODE_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("semantic_contract", EvidenceType.MIXED)
|
||
trainingstyp_verteilung_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("time_window", EvidenceType.CODE_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("output_type", EvidenceType.CODE_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("placeholder_type", EvidenceType.MIXED)
|
||
trainingstyp_verteilung_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("minimum_data_requirements", EvidenceType.UNRESOLVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("quality_filter_policy", EvidenceType.UNRESOLVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("confidence_logic", EvidenceType.CODE_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("missing_value_policy", EvidenceType.CODE_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("layer_1_decision", EvidenceType.CODE_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("layer_2a_decision", EvidenceType.CODE_DERIVED)
|
||
trainingstyp_verteilung_metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.TO_VERIFY)
|
||
trainingstyp_verteilung_metadata.set_evidence("architecture_alignment", EvidenceType.MIXED)
|
||
trainingstyp_verteilung_metadata.set_evidence("issue_53_alignment", EvidenceType.MIXED)
|
||
|
||
register_placeholder(trainingstyp_verteilung_metadata)
|
||
|
||
|
||
# =============================================================================
|
||
# GRUPPE 2: Basic Metrics (7 Placeholders)
|
||
# =============================================================================
|
||
|
||
def register_activity_group_2():
|
||
"""
|
||
Register Group 2: Basic Activity Metrics.
|
||
|
||
All use Phase 0c Data Layer architecture.
|
||
"""
|
||
|
||
# Common metadata for most Group 2 placeholders
|
||
common_metadata_7d = {
|
||
"category": "Aktivität",
|
||
"resolver_module": "backend/placeholder_resolver.py",
|
||
"data_layer_module": "backend/data_layer/activity_metrics.py",
|
||
"source_tables": ["activity_log"],
|
||
"time_window": "7d",
|
||
"output_type": OutputType.NUMERIC,
|
||
"placeholder_type": PlaceholderType.INTERPRETED,
|
||
"confidence_logic": "datenpunktbasierte Coverage-Logik (calculate_confidence in data layer)",
|
||
"missing_value_policy": MissingValuePolicy(
|
||
available=False,
|
||
value_raw=None,
|
||
missing_reason="insufficient_data",
|
||
legacy_display="nicht genug Daten"
|
||
),
|
||
"layer_1_decision": "Data Layer (activity_metrics.py)",
|
||
"layer_2a_decision": "Placeholder Resolver (formatting only)",
|
||
"architecture_alignment": "Phase 0c Multi-Layer Architecture conform",
|
||
"issue_53_alignment": "Layer separation established"
|
||
}
|
||
|
||
# Common evidence for Group 2 placeholders
|
||
common_evidence_7d = {
|
||
"category": EvidenceType.CODE_DERIVED,
|
||
"resolver_module": EvidenceType.CODE_DERIVED,
|
||
"data_layer_module": EvidenceType.CODE_DERIVED,
|
||
"source_tables": EvidenceType.CODE_DERIVED,
|
||
"time_window": EvidenceType.CODE_DERIVED,
|
||
"output_type": EvidenceType.CODE_DERIVED,
|
||
"placeholder_type": EvidenceType.MIXED,
|
||
"confidence_logic": EvidenceType.CODE_DERIVED,
|
||
"missing_value_policy": EvidenceType.CODE_DERIVED,
|
||
"layer_1_decision": EvidenceType.CODE_DERIVED,
|
||
"layer_2a_decision": EvidenceType.CODE_DERIVED,
|
||
"layer_2b_reuse_possible": EvidenceType.TO_VERIFY,
|
||
"architecture_alignment": EvidenceType.CODE_DERIVED,
|
||
"issue_53_alignment": EvidenceType.CODE_DERIVED,
|
||
"minimum_data_requirements": EvidenceType.UNRESOLVED,
|
||
"quality_filter_policy": EvidenceType.UNRESOLVED
|
||
}
|
||
|
||
# ── training_minutes_week ─────────────────────────────────────────────────
|
||
|
||
training_minutes_week_metadata = PlaceholderMetadata(
|
||
key="training_minutes_week",
|
||
description="Gesamte Trainingsminuten in 7 Tagen",
|
||
resolver_function="get_training_minutes_week",
|
||
data_layer_function="get_weekly_training_volume",
|
||
semantic_contract=(
|
||
"Liefert die Summe aller Trainingsminuten über die letzten 7 Tage. "
|
||
"Basiert auf activity_log.duration_minutes. Keine Qualitätsfilterung - "
|
||
"alle Einheiten werden summiert unabhängig von Dauer oder Intensität."
|
||
),
|
||
business_meaning=(
|
||
"Kernmetrik für Trainingsvolumen und Periodisierung. "
|
||
"Erlaubt Erkennung von Übertraining (zu hoch), Detraining (zu niedrig), "
|
||
"und Trendanalysen (Volumen steigend/fallend)."
|
||
),
|
||
unit="Minuten",
|
||
format_hint="Ganzzahl",
|
||
example_output="315",
|
||
known_limitations=(
|
||
"Keine Qualitätsfilterung. 1-Minuten-Einheiten zählen gleich wie "
|
||
"60-Minuten-Sessions. Keine Intensitätsgewichtung. "
|
||
"EDGE CASE: duration_minutes = 0 oder NULL werden als 0 gezählt."
|
||
),
|
||
layer_2b_reuse_possible=True,
|
||
**common_metadata_7d
|
||
)
|
||
|
||
training_minutes_week_metadata.evidence.update(common_evidence_7d)
|
||
training_minutes_week_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||
training_minutes_week_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
training_minutes_week_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
training_minutes_week_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
training_minutes_week_metadata.set_evidence("semantic_contract", EvidenceType.MIXED)
|
||
training_minutes_week_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
training_minutes_week_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
|
||
training_minutes_week_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
||
training_minutes_week_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
training_minutes_week_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED)
|
||
|
||
register_placeholder(training_minutes_week_metadata)
|
||
|
||
# ── training_frequency_7d ─────────────────────────────────────────────────
|
||
|
||
training_frequency_7d_metadata = PlaceholderMetadata(
|
||
key="training_frequency_7d",
|
||
description="Anzahl Trainingseinheiten in 7 Tagen",
|
||
resolver_function="get_training_frequency_7d",
|
||
data_layer_function="get_training_frequency",
|
||
semantic_contract=(
|
||
"Liefert die Anzahl der Trainingseinheiten über die letzten 7 Tage. "
|
||
"Basiert auf COUNT(activity_log.id). Keine Qualitätsfilterung - "
|
||
"jede Einheit wird gezählt unabhängig von Dauer oder Intensität."
|
||
),
|
||
business_meaning=(
|
||
"Frequenz-Metrik für Trainingsregelmäßigkeit. "
|
||
"Erlaubt Erkennung von Konsistenz (z.B. 4-5 Einheiten/Woche), "
|
||
"Pausentagen, und Trainingszyklen."
|
||
),
|
||
unit="Anzahl Einheiten",
|
||
format_hint="Ganzzahl",
|
||
example_output="5",
|
||
known_limitations=(
|
||
"Keine Qualitätsfilterung. 1-Minuten-Einheiten zählen gleich wie "
|
||
"60-Minuten-Sessions. "
|
||
"EDGE CASE: Mehrere Einheiten am selben Tag werden separat gezählt "
|
||
"(kein Tages-Grouping)."
|
||
),
|
||
layer_2b_reuse_possible=True,
|
||
**common_metadata_7d
|
||
)
|
||
|
||
training_frequency_7d_metadata.evidence.update(common_evidence_7d)
|
||
training_frequency_7d_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||
training_frequency_7d_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
training_frequency_7d_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
training_frequency_7d_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
training_frequency_7d_metadata.set_evidence("semantic_contract", EvidenceType.MIXED)
|
||
training_frequency_7d_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
training_frequency_7d_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
|
||
training_frequency_7d_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
||
training_frequency_7d_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
training_frequency_7d_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED)
|
||
|
||
register_placeholder(training_frequency_7d_metadata)
|
||
|
||
# ── quality_sessions_pct ──────────────────────────────────────────────────
|
||
|
||
# Custom metadata for quality_sessions_pct (28d time window, different source tables)
|
||
quality_metadata_custom = {**common_metadata_7d}
|
||
quality_metadata_custom["time_window"] = "28d"
|
||
quality_metadata_custom["source_tables"] = ["activity_log", "training_types"]
|
||
|
||
quality_sessions_pct_metadata = PlaceholderMetadata(
|
||
key="quality_sessions_pct",
|
||
description="Prozentsatz Qualitäts-Sessions in 28 Tagen",
|
||
resolver_function="get_quality_sessions_pct",
|
||
data_layer_function="calculate_quality_sessions_percentage",
|
||
semantic_contract=(
|
||
"Liefert den Prozentsatz der Trainingseinheiten, die als 'Qualitäts-Sessions' "
|
||
"klassifiziert werden (duration >= 30 min UND intensity >= moderate). "
|
||
"Berechnung: (quality_sessions / total_sessions) × 100."
|
||
),
|
||
business_meaning=(
|
||
"Qualitäts-Metrik für Trainingseffektivität. "
|
||
"Niedrige Werte (<50%) deuten auf zu viele kurze/low-intensity Sessions. "
|
||
"Hohe Werte (>80%) deuten auf konsequent forderndes Training."
|
||
),
|
||
unit="Prozent",
|
||
format_hint="Ganzzahl 0-100",
|
||
example_output="68",
|
||
known_limitations=(
|
||
"CRITICAL TO_VERIFY: Code nutzt quality_label Feld (may not exist). "
|
||
"Canonical expects duration >= 30min + intensity >= moderate. "
|
||
"MISMATCH: quality_label vs. calculated quality. "
|
||
"EDGE CASE: Einheiten ohne training_type_id werden ignoriert."
|
||
),
|
||
layer_2b_reuse_possible=True,
|
||
**quality_metadata_custom
|
||
)
|
||
|
||
quality_sessions_pct_metadata.evidence.update(common_evidence_7d)
|
||
quality_sessions_pct_metadata.evidence["time_window"] = EvidenceType.CODE_DERIVED
|
||
quality_sessions_pct_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||
quality_sessions_pct_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
quality_sessions_pct_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
quality_sessions_pct_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
quality_sessions_pct_metadata.set_evidence("semantic_contract", EvidenceType.TO_VERIFY)
|
||
quality_sessions_pct_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
quality_sessions_pct_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
|
||
quality_sessions_pct_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
||
quality_sessions_pct_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
quality_sessions_pct_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED)
|
||
quality_sessions_pct_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED)
|
||
|
||
register_placeholder(quality_sessions_pct_metadata)
|
||
|
||
# ── proxy_internal_load_7d ────────────────────────────────────────────────
|
||
|
||
# Custom metadata for proxy_internal_load (different source tables)
|
||
proxy_load_metadata_custom = {**common_metadata_7d}
|
||
proxy_load_metadata_custom["source_tables"] = ["activity_log", "training_types"]
|
||
|
||
proxy_internal_load_7d_metadata = PlaceholderMetadata(
|
||
key="proxy_internal_load_7d",
|
||
description="Proxy Internal Load über 7 Tage",
|
||
resolver_function="get_proxy_internal_load_7d",
|
||
data_layer_function="calculate_proxy_internal_load",
|
||
semantic_contract=(
|
||
"Liefert einen Proxy-Wert für die interne Trainingsbelastung über 7 Tage. "
|
||
"Berechnet als: Summe(duration × intensity_factor × quality_factor). "
|
||
"Intensity_factor basiert auf RPE-Mapping (1-10 → 0.1-1.0). "
|
||
"Quality_factor basiert auf quality_label (easy/moderate/hard → 0.8/1.0/1.2)."
|
||
),
|
||
business_meaning=(
|
||
"Load-Monitoring-Metrik für Periodisierung und Übertrainings-Prävention. "
|
||
"Erlaubt Vergleich interner Belastung über Zeit (nicht nur Volumen). "
|
||
"Basis für Monotony und Strain Scores."
|
||
),
|
||
unit="Load-Punkte",
|
||
format_hint="Ganzzahl",
|
||
example_output="1850",
|
||
known_limitations=(
|
||
"PROXY-WERT: Nicht trainings wissenschaftlich validiert. "
|
||
"RPE-Mapping vereinfacht (linear 1-10 → 0.1-1.0). "
|
||
"CRITICAL BUG: RPE 4-5 maps to 'moderate' quality but 'moderate' "
|
||
"not in quality_factors dict (easy/hard only). "
|
||
"EDGE CASE: Einheiten ohne RPE bekommen intensity_factor = 0.5 (default)."
|
||
),
|
||
layer_2b_reuse_possible=True,
|
||
**proxy_load_metadata_custom
|
||
)
|
||
|
||
proxy_internal_load_7d_metadata.evidence.update(common_evidence_7d)
|
||
proxy_internal_load_7d_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||
proxy_internal_load_7d_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
proxy_internal_load_7d_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
proxy_internal_load_7d_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
proxy_internal_load_7d_metadata.set_evidence("semantic_contract", EvidenceType.CODE_DERIVED)
|
||
proxy_internal_load_7d_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
proxy_internal_load_7d_metadata.set_evidence("unit", EvidenceType.DRAFT_DERIVED)
|
||
proxy_internal_load_7d_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
||
proxy_internal_load_7d_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
proxy_internal_load_7d_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED)
|
||
proxy_internal_load_7d_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED)
|
||
|
||
register_placeholder(proxy_internal_load_7d_metadata)
|
||
|
||
# ── monotony_score ────────────────────────────────────────────────────────
|
||
|
||
monotony_score_metadata = PlaceholderMetadata(
|
||
key="monotony_score",
|
||
description="Trainings-Monotonie-Score über 7 Tage",
|
||
resolver_function="get_monotony_score",
|
||
data_layer_function="calculate_monotony_score",
|
||
semantic_contract=(
|
||
"Liefert einen Monotonie-Score für die Trainingsbelastung über 7 Tage. "
|
||
"Berechnet als: mean(daily_duration) / std_dev(daily_duration). "
|
||
"Hohe Werte (>2.0) = monotones Training (gleichbleibende Belastung). "
|
||
"Niedrige Werte (<1.5) = variable Belastung."
|
||
),
|
||
business_meaning=(
|
||
"Variabilitäts-Metrik für Periodisierung. "
|
||
"Hohe Monotonie erhöht Übertrainings-Risiko (Foster et al. 2001). "
|
||
"Kombination mit Strain Score für Übertrainings-Warnung."
|
||
),
|
||
unit="Score (dimensionslos)",
|
||
format_hint="Dezimalzahl, typisch 0.5-3.0",
|
||
example_output="1.8",
|
||
known_limitations=(
|
||
"FORMULA: mean / std_dev. "
|
||
"EDGE CASE: std_dev = 0 (alle Tage gleich) → division by zero → return mean as fallback. "
|
||
"EDGE CASE: < 3 Trainingstage → nicht aussagekräftig, aber wird trotzdem berechnet. "
|
||
"ZEITFENSTER: 7 Tage möglicherweise zu kurz für verlässliche Monotonie-Analyse "
|
||
"(Foster original: 28 Tage)."
|
||
),
|
||
layer_2b_reuse_possible=True,
|
||
**common_metadata_7d
|
||
)
|
||
|
||
monotony_score_metadata.evidence.update(common_evidence_7d)
|
||
monotony_score_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||
monotony_score_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
monotony_score_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
monotony_score_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
monotony_score_metadata.set_evidence("semantic_contract", EvidenceType.CODE_DERIVED)
|
||
monotony_score_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
monotony_score_metadata.set_evidence("unit", EvidenceType.DRAFT_DERIVED)
|
||
monotony_score_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
||
monotony_score_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
monotony_score_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED)
|
||
|
||
register_placeholder(monotony_score_metadata)
|
||
|
||
# ── strain_score ──────────────────────────────────────────────────────────
|
||
|
||
strain_score_metadata = PlaceholderMetadata(
|
||
key="strain_score",
|
||
description="Trainings-Strain-Score über 7 Tage",
|
||
resolver_function="get_strain_score",
|
||
data_layer_function="calculate_strain_score",
|
||
semantic_contract=(
|
||
"Liefert einen Strain-Score für die Gesamtbelastung über 7 Tage. "
|
||
"Berechnet als: proxy_internal_load_7d × monotony_score. "
|
||
"Kombiniert Volumen (Load) mit Variabilität (Monotonie) zu Gesamt-Strain."
|
||
),
|
||
business_meaning=(
|
||
"Übertrainings-Risiko-Metrik (Foster et al. 2001). "
|
||
"Hohe Werte = hohes Risiko (hohe Last + monotones Training). "
|
||
"Schwellenwerte: <5000 = moderat, 5000-8000 = erhöht, >8000 = kritisch."
|
||
),
|
||
unit="Strain-Punkte",
|
||
format_hint="Ganzzahl, typisch 1000-10000",
|
||
example_output="3330",
|
||
known_limitations=(
|
||
"FORMULA: load × monotony. "
|
||
"ABHÄNGIG von proxy_internal_load_7d (bereits Proxy-Wert). "
|
||
"SCHWELLENWERTE: Nicht wissenschaftlich validiert für diese App. "
|
||
"EDGE CASE: Wenn monotony_score Fallback-Logik greift (std_dev=0), "
|
||
"wird Strain = Load × mean (nicht original Formel)."
|
||
),
|
||
layer_2b_reuse_possible=True,
|
||
**common_metadata_7d
|
||
)
|
||
|
||
strain_score_metadata.evidence.update(common_evidence_7d)
|
||
strain_score_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||
strain_score_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
strain_score_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
strain_score_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
strain_score_metadata.set_evidence("semantic_contract", EvidenceType.CODE_DERIVED)
|
||
strain_score_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
strain_score_metadata.set_evidence("unit", EvidenceType.DRAFT_DERIVED)
|
||
strain_score_metadata.set_evidence("format_hint", EvidenceType.DRAFT_DERIVED)
|
||
strain_score_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
strain_score_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED)
|
||
|
||
register_placeholder(strain_score_metadata)
|
||
|
||
# ── rest_day_compliance ───────────────────────────────────────────────────
|
||
|
||
# Custom metadata for rest_day_compliance (28d time window, different source tables)
|
||
rest_metadata_custom = {**common_metadata_7d}
|
||
rest_metadata_custom["time_window"] = "28d"
|
||
rest_metadata_custom["source_tables"] = ["rest_days", "activity_log"]
|
||
|
||
rest_day_compliance_metadata = PlaceholderMetadata(
|
||
key="rest_day_compliance",
|
||
description="Ruhetag-Compliance über 28 Tage",
|
||
resolver_function="get_rest_day_compliance",
|
||
data_layer_function="calculate_rest_day_compliance",
|
||
semantic_contract=(
|
||
"Liefert den Prozentsatz der geplanten Ruhetage, die tatsächlich eingehalten wurden. "
|
||
"Berechnung: (eingehaltene_ruhetage / geplante_ruhetage) × 100. "
|
||
"Ruhetag = Eintrag in rest_days OHNE korrespondierenden activity_log Eintrag am selben Tag."
|
||
),
|
||
business_meaning=(
|
||
"Regenerations-Compliance-Metrik. "
|
||
"Niedrige Werte (<70%) = schlechte Regeneration, Übertrainings-Risiko. "
|
||
"Hohe Werte (>90%) = gute Disziplin bei Regeneration."
|
||
),
|
||
unit="Prozent",
|
||
format_hint="Ganzzahl 0-100",
|
||
example_output="85",
|
||
known_limitations=(
|
||
"JSONB DEPENDENCY: Nutzt rest_config->>'focus' JSONB Feld. "
|
||
"EDGE CASE: rest_config NULL → Ruhetag wird ignoriert (nicht gezählt). "
|
||
"EDGE CASE: Kein activity_log Eintrag am Ruhetag = compliant (korrekt). "
|
||
"EDGE CASE: Mehrere activity_log Einträge am Ruhetag = alle zählen als violation."
|
||
),
|
||
layer_2b_reuse_possible=False,
|
||
**rest_metadata_custom
|
||
)
|
||
|
||
rest_day_compliance_metadata.evidence.update(common_evidence_7d)
|
||
rest_day_compliance_metadata.evidence["time_window"] = EvidenceType.CODE_DERIVED
|
||
rest_day_compliance_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||
rest_day_compliance_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
rest_day_compliance_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
rest_day_compliance_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
rest_day_compliance_metadata.set_evidence("semantic_contract", EvidenceType.MIXED)
|
||
rest_day_compliance_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
rest_day_compliance_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
|
||
rest_day_compliance_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
||
rest_day_compliance_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
rest_day_compliance_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED)
|
||
rest_day_compliance_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED)
|
||
rest_day_compliance_metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.CODE_DERIVED)
|
||
|
||
register_placeholder(rest_day_compliance_metadata)
|
||
|
||
|
||
# =============================================================================
|
||
# GRUPPE 3: Advanced Metrics (7 Placeholders)
|
||
# =============================================================================
|
||
|
||
def register_activity_group_3():
|
||
"""
|
||
Register Group 3: Advanced Activity Metrics.
|
||
|
||
Includes ability balance metrics (5), VO2 Max trend, and activity score.
|
||
"""
|
||
|
||
# Common metadata for ability_balance placeholders
|
||
common_metadata_ability = {
|
||
"category": "Aktivität",
|
||
"resolver_module": "backend/placeholder_resolver.py",
|
||
"data_layer_module": "backend/data_layer/activity_metrics.py",
|
||
"data_layer_function": "calculate_ability_balance",
|
||
"source_tables": ["activity_log", "training_types"],
|
||
"time_window": "28d",
|
||
"output_type": OutputType.NUMERIC,
|
||
"placeholder_type": PlaceholderType.SCORE,
|
||
"unit": "Score (0-100)",
|
||
"format_hint": "Ganzzahl 0-100",
|
||
"confidence_logic": "datenpunktbasierte Coverage-Logik (calculate_confidence in data layer)",
|
||
"missing_value_policy": MissingValuePolicy(
|
||
available=False,
|
||
value_raw=None,
|
||
missing_reason="insufficient_data",
|
||
legacy_display="nicht genug Daten"
|
||
),
|
||
"layer_1_decision": "Data Layer (activity_metrics.calculate_ability_balance)",
|
||
"layer_2a_decision": "Placeholder Resolver (extract specific ability from dict)",
|
||
"architecture_alignment": "Phase 0c Multi-Layer Architecture conform",
|
||
"issue_53_alignment": "Layer separation established"
|
||
}
|
||
|
||
# Common evidence for ability_balance placeholders
|
||
common_evidence_ability = {
|
||
"category": EvidenceType.CODE_DERIVED,
|
||
"resolver_module": EvidenceType.CODE_DERIVED,
|
||
"data_layer_module": EvidenceType.CODE_DERIVED,
|
||
"data_layer_function": EvidenceType.CODE_DERIVED,
|
||
"source_tables": EvidenceType.CODE_DERIVED,
|
||
"time_window": EvidenceType.CODE_DERIVED,
|
||
"output_type": EvidenceType.CODE_DERIVED,
|
||
"placeholder_type": EvidenceType.MIXED,
|
||
"unit": EvidenceType.CODE_DERIVED,
|
||
"format_hint": EvidenceType.CODE_DERIVED,
|
||
"confidence_logic": EvidenceType.CODE_DERIVED,
|
||
"missing_value_policy": EvidenceType.CODE_DERIVED,
|
||
"layer_1_decision": EvidenceType.CODE_DERIVED,
|
||
"layer_2a_decision": EvidenceType.CODE_DERIVED,
|
||
"layer_2b_reuse_possible": EvidenceType.TO_VERIFY,
|
||
"architecture_alignment": EvidenceType.CODE_DERIVED,
|
||
"issue_53_alignment": EvidenceType.CODE_DERIVED,
|
||
"minimum_data_requirements": EvidenceType.UNRESOLVED,
|
||
"quality_filter_policy": EvidenceType.UNRESOLVED
|
||
}
|
||
|
||
# ── ability_balance_strength ──────────────────────────────────────────────
|
||
|
||
ability_balance_strength_metadata = PlaceholderMetadata(
|
||
key="ability_balance_strength",
|
||
description="Fähigkeiten-Balance-Score: Kraft (28d)",
|
||
resolver_function="get_ability_balance_strength",
|
||
semantic_contract=(
|
||
"Liefert einen normierten Score (0-100) für die relative Trainingsbelastung "
|
||
"der Fähigkeit 'Kraft' über 28 Tage. Berechnung: "
|
||
"(kraft_load / max_load_aller_fähigkeiten) × 100. "
|
||
"Basiert auf training_types.abilities JSONB Feld (strength_percentage)."
|
||
),
|
||
business_meaning=(
|
||
"Balance-Metrik für Trainingsvielfalt. "
|
||
"Zeigt ob Kraft überproportional (>80), balanciert (40-60), oder unterrepräsentiert (<20) trainiert wird. "
|
||
"Vergleich mit anderen Fähigkeiten zeigt Imbalancen."
|
||
),
|
||
example_output="75",
|
||
known_limitations=(
|
||
"JSONB DEPENDENCY: training_types.abilities JSONB Feld muss populated sein. "
|
||
"FORMULA: max-normalized (nicht prozentual vom Total). "
|
||
"Höchste Fähigkeit = 100, andere relativ dazu. "
|
||
"EDGE CASE: abilities NULL → Trainingstyp wird mit 0% für alle Fähigkeiten gewertet. "
|
||
"EDGE CASE: Alle Fähigkeiten = 0 (keine Trainings) → division by zero → return 0."
|
||
),
|
||
layer_2b_reuse_possible=True,
|
||
**common_metadata_ability
|
||
)
|
||
|
||
ability_balance_strength_metadata.evidence.update(common_evidence_ability)
|
||
ability_balance_strength_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||
ability_balance_strength_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
ability_balance_strength_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
ability_balance_strength_metadata.set_evidence("semantic_contract", EvidenceType.CODE_DERIVED)
|
||
ability_balance_strength_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
ability_balance_strength_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
ability_balance_strength_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED)
|
||
|
||
register_placeholder(ability_balance_strength_metadata)
|
||
|
||
# ── ability_balance_endurance ─────────────────────────────────────────────
|
||
|
||
ability_balance_endurance_metadata = PlaceholderMetadata(
|
||
key="ability_balance_endurance",
|
||
description="Fähigkeiten-Balance-Score: Ausdauer (28d)",
|
||
resolver_function="get_ability_balance_endurance",
|
||
semantic_contract=(
|
||
"Liefert einen normierten Score (0-100) für die relative Trainingsbelastung "
|
||
"der Fähigkeit 'Ausdauer' über 28 Tage. Berechnung: "
|
||
"(ausdauer_load / max_load_aller_fähigkeiten) × 100. "
|
||
"Basiert auf training_types.abilities JSONB Feld (endurance_percentage)."
|
||
),
|
||
business_meaning=(
|
||
"Balance-Metrik für Trainingsvielfalt. "
|
||
"Zeigt ob Ausdauer überproportional (>80), balanciert (40-60), oder unterrepräsentiert (<20) trainiert wird."
|
||
),
|
||
example_output="92",
|
||
known_limitations=(
|
||
"JSONB DEPENDENCY: training_types.abilities JSONB Feld muss populated sein. "
|
||
"FORMULA: max-normalized (nicht prozentual vom Total). "
|
||
"EDGE CASE: abilities NULL → 0% Ausdauer. "
|
||
"EDGE CASE: Alle Fähigkeiten = 0 → return 0."
|
||
),
|
||
layer_2b_reuse_possible=True,
|
||
**common_metadata_ability
|
||
)
|
||
|
||
ability_balance_endurance_metadata.evidence.update(common_evidence_ability)
|
||
ability_balance_endurance_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||
ability_balance_endurance_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
ability_balance_endurance_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
ability_balance_endurance_metadata.set_evidence("semantic_contract", EvidenceType.CODE_DERIVED)
|
||
ability_balance_endurance_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
ability_balance_endurance_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
ability_balance_endurance_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED)
|
||
|
||
register_placeholder(ability_balance_endurance_metadata)
|
||
|
||
# ── ability_balance_mental ────────────────────────────────────────────────
|
||
|
||
ability_balance_mental_metadata = PlaceholderMetadata(
|
||
key="ability_balance_mental",
|
||
description="Fähigkeiten-Balance-Score: Geist & Meditation (28d)",
|
||
resolver_function="get_ability_balance_mental",
|
||
semantic_contract=(
|
||
"Liefert einen normierten Score (0-100) für die relative Trainingsbelastung "
|
||
"der Fähigkeit 'Geist & Meditation' über 28 Tage. Berechnung: "
|
||
"(mental_load / max_load_aller_fähigkeiten) × 100. "
|
||
"Basiert auf training_types.abilities JSONB Feld (mental_percentage)."
|
||
),
|
||
business_meaning=(
|
||
"Balance-Metrik für ganzheitliches Training. "
|
||
"Zeigt ob mentale/meditative Praxis im Verhältnis zu physischem Training steht. "
|
||
"Oft niedrig (<20) bei rein physisch orientierten Trainern."
|
||
),
|
||
example_output="15",
|
||
known_limitations=(
|
||
"JSONB DEPENDENCY: training_types.abilities JSONB Feld muss populated sein. "
|
||
"FORMULA: max-normalized (nicht prozentual vom Total). "
|
||
"EDGE CASE: abilities NULL → 0% Mental. "
|
||
"EDGE CASE: Alle Fähigkeiten = 0 → return 0."
|
||
),
|
||
layer_2b_reuse_possible=True,
|
||
**common_metadata_ability
|
||
)
|
||
|
||
ability_balance_mental_metadata.evidence.update(common_evidence_ability)
|
||
ability_balance_mental_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||
ability_balance_mental_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
ability_balance_mental_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
ability_balance_mental_metadata.set_evidence("semantic_contract", EvidenceType.CODE_DERIVED)
|
||
ability_balance_mental_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
ability_balance_mental_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
ability_balance_mental_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED)
|
||
|
||
register_placeholder(ability_balance_mental_metadata)
|
||
|
||
# ── ability_balance_coordination ──────────────────────────────────────────
|
||
|
||
ability_balance_coordination_metadata = PlaceholderMetadata(
|
||
key="ability_balance_coordination",
|
||
description="Fähigkeiten-Balance-Score: Koordination (28d)",
|
||
resolver_function="get_ability_balance_coordination",
|
||
semantic_contract=(
|
||
"Liefert einen normierten Score (0-100) für die relative Trainingsbelastung "
|
||
"der Fähigkeit 'Koordination' über 28 Tage. Berechnung: "
|
||
"(koordination_load / max_load_aller_fähigkeiten) × 100. "
|
||
"Basiert auf training_types.abilities JSONB Feld (coordination_percentage)."
|
||
),
|
||
business_meaning=(
|
||
"Balance-Metrik für motorische Vielfalt. "
|
||
"Zeigt ob Koordinations-Training (Kampfsport, Tanz, komplexe Bewegungsmuster) "
|
||
"im Trainingsplan vertreten ist. Oft niedrig (<20) bei reinem Kraft/Ausdauer-Training."
|
||
),
|
||
example_output="28",
|
||
known_limitations=(
|
||
"JSONB DEPENDENCY: training_types.abilities JSONB Feld muss populated sein. "
|
||
"FORMULA: max-normalized (nicht prozentual vom Total). "
|
||
"EDGE CASE: abilities NULL → 0% Koordination. "
|
||
"EDGE CASE: Alle Fähigkeiten = 0 → return 0."
|
||
),
|
||
layer_2b_reuse_possible=True,
|
||
**common_metadata_ability
|
||
)
|
||
|
||
ability_balance_coordination_metadata.evidence.update(common_evidence_ability)
|
||
ability_balance_coordination_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||
ability_balance_coordination_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
ability_balance_coordination_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
ability_balance_coordination_metadata.set_evidence("semantic_contract", EvidenceType.CODE_DERIVED)
|
||
ability_balance_coordination_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
ability_balance_coordination_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
ability_balance_coordination_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED)
|
||
|
||
register_placeholder(ability_balance_coordination_metadata)
|
||
|
||
# ── ability_balance_mobility ──────────────────────────────────────────────
|
||
|
||
ability_balance_mobility_metadata = PlaceholderMetadata(
|
||
key="ability_balance_mobility",
|
||
description="Fähigkeiten-Balance-Score: Mobilität (28d)",
|
||
resolver_function="get_ability_balance_mobility",
|
||
semantic_contract=(
|
||
"Liefert einen normierten Score (0-100) für die relative Trainingsbelastung "
|
||
"der Fähigkeit 'Mobilität' über 28 Tage. Berechnung: "
|
||
"(mobilität_load / max_load_aller_fähigkeiten) × 100. "
|
||
"Basiert auf training_types.abilities JSONB Feld (mobility_percentage)."
|
||
),
|
||
business_meaning=(
|
||
"Balance-Metrik für Beweglichkeits-Training. "
|
||
"Zeigt ob Mobilität (Stretching, Yoga, Fasziendehnung) im Trainingsplan vertreten ist. "
|
||
"Wichtig für Verletzungsprävention und Regeneration. Oft vernachlässigt (<20)."
|
||
),
|
||
example_output="22",
|
||
known_limitations=(
|
||
"JSONB DEPENDENCY: training_types.abilities JSONB Feld muss populated sein. "
|
||
"FORMULA: max-normalized (nicht prozentual vom Total). "
|
||
"EDGE CASE: abilities NULL → 0% Mobilität. "
|
||
"EDGE CASE: Alle Fähigkeiten = 0 → return 0."
|
||
),
|
||
layer_2b_reuse_possible=True,
|
||
**common_metadata_ability
|
||
)
|
||
|
||
ability_balance_mobility_metadata.evidence.update(common_evidence_ability)
|
||
ability_balance_mobility_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||
ability_balance_mobility_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
ability_balance_mobility_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
ability_balance_mobility_metadata.set_evidence("semantic_contract", EvidenceType.CODE_DERIVED)
|
||
ability_balance_mobility_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
ability_balance_mobility_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
ability_balance_mobility_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED)
|
||
|
||
register_placeholder(ability_balance_mobility_metadata)
|
||
|
||
# ── vo2max_trend_28d ──────────────────────────────────────────────────────
|
||
|
||
vo2max_trend_28d_metadata = PlaceholderMetadata(
|
||
key="vo2max_trend_28d",
|
||
description="VO2 Max Trend über 28 Tage",
|
||
category="Aktivität",
|
||
resolver_module="backend/placeholder_resolver.py",
|
||
resolver_function="get_vo2max_trend_28d",
|
||
data_layer_module="backend/data_layer/activity_metrics.py",
|
||
data_layer_function="calculate_vo2max_trend",
|
||
source_tables=["vitals_baseline"],
|
||
time_window="28d",
|
||
output_type=OutputType.NUMERIC,
|
||
placeholder_type=PlaceholderType.INTERPRETED,
|
||
semantic_contract=(
|
||
"Liefert den Trend der VO2 Max Werte über 28 Tage als Delta (letzter - erster Wert). "
|
||
"Positiver Wert = Verbesserung der aeroben Fitness, "
|
||
"negativer Wert = Verschlechterung. "
|
||
"Basiert auf vitals_baseline.vo2_max (gemessen oder geschätzt)."
|
||
),
|
||
business_meaning=(
|
||
"Fitness-Trend-Metrik für aerobe Kapazität. "
|
||
"Indikator für Trainingseffektivität bei Ausdauer-fokussiertem Training. "
|
||
"QUESTIONABLE CATEGORY: VO2 Max ist primär Vitalwert/Recovery, nicht Activity."
|
||
),
|
||
unit="ml/kg/min (Delta)",
|
||
format_hint="Dezimalzahl mit Vorzeichen, typisch -3.0 bis +3.0",
|
||
example_output="+1.2",
|
||
minimum_data_requirements=None,
|
||
quality_filter_policy=None,
|
||
confidence_logic=(
|
||
"datenpunktbasierte Coverage-Logik. "
|
||
"Mindestens 2 VO2 Max Messungen in 28d erforderlich für Trend."
|
||
),
|
||
missing_value_policy=MissingValuePolicy(
|
||
available=False,
|
||
value_raw=None,
|
||
missing_reason="insufficient_data",
|
||
legacy_display="nicht genug Daten"
|
||
),
|
||
known_limitations=(
|
||
"QUESTIONABLE CATEGORY: VO2 Max primär Recovery-Cluster, nicht Activity-Cluster. "
|
||
"DEPENDENCY: vitals_baseline.vo2_max Feld (oft NULL wenn nicht gemessen). "
|
||
"EDGE CASE: Nur 1 Messung → kein Trend → missing_value. "
|
||
"EDGE CASE: Große Zeitlücken zwischen Messungen → Trend nicht aussagekräftig."
|
||
),
|
||
layer_1_decision="Data Layer (activity_metrics.calculate_vo2max_trend) - QUESTIONABLE",
|
||
layer_2a_decision="Placeholder Resolver (formatting only)",
|
||
layer_2b_reuse_possible=True,
|
||
architecture_alignment="Phase 0c Multi-Layer Architecture conform",
|
||
issue_53_alignment="Layer separation established"
|
||
)
|
||
|
||
vo2max_trend_28d_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("category", EvidenceType.TO_VERIFY)
|
||
vo2max_trend_28d_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("resolver_module", EvidenceType.CODE_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("data_layer_module", EvidenceType.CODE_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("time_window", EvidenceType.CODE_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("output_type", EvidenceType.CODE_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("placeholder_type", EvidenceType.MIXED)
|
||
vo2max_trend_28d_metadata.set_evidence("semantic_contract", EvidenceType.MIXED)
|
||
vo2max_trend_28d_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("format_hint", EvidenceType.DRAFT_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("minimum_data_requirements", EvidenceType.UNRESOLVED)
|
||
vo2max_trend_28d_metadata.set_evidence("quality_filter_policy", EvidenceType.UNRESOLVED)
|
||
vo2max_trend_28d_metadata.set_evidence("confidence_logic", EvidenceType.CODE_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("missing_value_policy", EvidenceType.CODE_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("known_limitations", EvidenceType.MIXED)
|
||
vo2max_trend_28d_metadata.set_evidence("layer_1_decision", EvidenceType.CODE_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("layer_2a_decision", EvidenceType.CODE_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.TO_VERIFY)
|
||
vo2max_trend_28d_metadata.set_evidence("architecture_alignment", EvidenceType.CODE_DERIVED)
|
||
vo2max_trend_28d_metadata.set_evidence("issue_53_alignment", EvidenceType.CODE_DERIVED)
|
||
|
||
register_placeholder(vo2max_trend_28d_metadata)
|
||
|
||
# ── activity_score ────────────────────────────────────────────────────────
|
||
|
||
activity_score_metadata = PlaceholderMetadata(
|
||
key="activity_score",
|
||
description="Gesamtaktivitäts-Score (gewichtet)",
|
||
category="Aktivität",
|
||
resolver_module="backend/placeholder_resolver.py",
|
||
resolver_function="get_activity_score",
|
||
data_layer_module="backend/data_layer/scores.py",
|
||
data_layer_function="calculate_activity_score",
|
||
source_tables=["activity_log", "training_types", "rest_days", "vitals_baseline", "user_focus_area_weights"],
|
||
time_window="composite (7d, 14d, 28d mixed)",
|
||
output_type=OutputType.NUMERIC,
|
||
placeholder_type=PlaceholderType.SCORE,
|
||
semantic_contract=(
|
||
"Liefert einen gewichteten Gesamtscore (0-100) für Trainingsaktivität. "
|
||
"Berechnung: Gewichteter Durchschnitt aus 5 Komponenten: "
|
||
"1. Volumen (training_minutes_week vs. Ziel), "
|
||
"2. Frequenz (training_frequency_7d vs. Ziel), "
|
||
"3. Qualität (quality_sessions_pct), "
|
||
"4. Balance (Ability Balance Scores), "
|
||
"5. Recovery (rest_day_compliance). "
|
||
"Gewichtung dynamisch aus user_focus_area_weights."
|
||
),
|
||
business_meaning=(
|
||
"Meta-Score für Gesamtaktivitäts-Qualität. "
|
||
"Kombiniert Volumen, Konsistenz, Qualität, Vielfalt und Regeneration. "
|
||
"Ziel-abhängig: Gewichtung variiert je nach User-Fokus (Kraft vs. Ausdauer vs. Balance)."
|
||
),
|
||
unit="Score (0-100)",
|
||
format_hint="Ganzzahl",
|
||
example_output="78",
|
||
minimum_data_requirements=None,
|
||
quality_filter_policy=None,
|
||
confidence_logic=(
|
||
"Composite Confidence basierend auf Komponenten-Confidence. "
|
||
"Mindestens 3/5 Komponenten müssen verfügbar sein für Score-Berechnung."
|
||
),
|
||
missing_value_policy=MissingValuePolicy(
|
||
available=False,
|
||
value_raw=None,
|
||
missing_reason="insufficient_data",
|
||
legacy_display="nicht genug Daten"
|
||
),
|
||
known_limitations=(
|
||
"COMPOSITE SCORE: Komplexe Abhängigkeiten zu allen Activity-Metriken. "
|
||
"FOCUS-DEPENDENT: Gewichtung variiert je nach user_focus_area_weights (dynamisch). "
|
||
"EDGE CASE: Wenn user_focus_area_weights fehlt → default weighting (alle gleich). "
|
||
"ZEITFENSTER MIXED: Komponenten nutzen unterschiedliche Zeitfenster (7d, 14d, 28d). "
|
||
"QUESTIONABLE: Vermischt Metriken mit unterschiedlicher Verlässlichkeit "
|
||
"(z.B. quality_sessions_pct hat TO_VERIFY Issues)."
|
||
),
|
||
layer_1_decision="Data Layer (scores.calculate_activity_score)",
|
||
layer_2a_decision="Placeholder Resolver (formatting only)",
|
||
layer_2b_reuse_possible=False,
|
||
architecture_alignment="Phase 0c Multi-Layer Architecture conform",
|
||
issue_53_alignment="Layer separation established"
|
||
)
|
||
|
||
activity_score_metadata.set_evidence("key", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("category", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("description", EvidenceType.DRAFT_DERIVED)
|
||
activity_score_metadata.set_evidence("resolver_module", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("data_layer_module", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("time_window", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("output_type", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("placeholder_type", EvidenceType.MIXED)
|
||
activity_score_metadata.set_evidence("semantic_contract", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
activity_score_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("minimum_data_requirements", EvidenceType.UNRESOLVED)
|
||
activity_score_metadata.set_evidence("quality_filter_policy", EvidenceType.UNRESOLVED)
|
||
activity_score_metadata.set_evidence("confidence_logic", EvidenceType.MIXED)
|
||
activity_score_metadata.set_evidence("missing_value_policy", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("layer_1_decision", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("layer_2a_decision", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("architecture_alignment", EvidenceType.CODE_DERIVED)
|
||
activity_score_metadata.set_evidence("issue_53_alignment", EvidenceType.CODE_DERIVED)
|
||
|
||
register_placeholder(activity_score_metadata)
|
||
|
||
|
||
# =============================================================================
|
||
# Auto-Registration
|
||
# =============================================================================
|
||
|
||
# Register all groups when module is imported
|
||
register_activity_group_1()
|
||
register_activity_group_2()
|
||
register_activity_group_3()
|