- Adjusted the total number of placeholders from 116 to 114 across various documentation and code files to reflect the current state of the system. - Enhanced TDEE calculation logic in `nutrition_metrics.py` to prioritize Mifflin–St Jeor BMR with PAL when demographic data is available, with a fallback to a weight-based estimate. - Updated placeholder registrations to ensure consistency with the new metadata structure and improved data handling. - Revised documentation to clarify the authoritative source of placeholder metadata and the implications of the changes on existing functionalities. These updates improve the accuracy and consistency of the placeholder system and enhance the nutritional assessment capabilities within the application.
450 lines
26 KiB
Python
450 lines
26 KiB
Python
"""
|
||
Placeholder Registrations - Nutrition Part C
|
||
|
||
Registers 5 nutrition-related placeholders in this file (nutrition_score: siehe nutrition_score.py):
|
||
- macro_consistency_score
|
||
- energy_balance_7d
|
||
- energy_deficit_surplus
|
||
- intake_volatility
|
||
- nutrition_days
|
||
|
||
All placeholders follow Phase 0c Multi-Layer Architecture.
|
||
"""
|
||
|
||
from placeholder_registry import (
|
||
PlaceholderMetadata,
|
||
MissingValuePolicy,
|
||
EvidenceType,
|
||
OutputType,
|
||
PlaceholderType,
|
||
register_placeholder
|
||
)
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 1. macro_consistency_score
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
macro_consistency_metadata = PlaceholderMetadata(
|
||
key="macro_consistency_score",
|
||
category="Ernährung",
|
||
description="Makro-Konsistenz Score (0-100)",
|
||
|
||
# Technical
|
||
resolver_module="backend/placeholder_resolver.py",
|
||
resolver_function="_safe_int('macro_consistency_score', pid)",
|
||
data_layer_module="backend/data_layer/nutrition_metrics.py",
|
||
data_layer_function="calculate_macro_consistency_score",
|
||
source_tables=["nutrition_log"],
|
||
|
||
# Semantic
|
||
semantic_contract="Liefert einen standardisierten Score (0-100), der die Stabilität bzw. Varianz der Makronährstoffzufuhr über 28 Tage bewertet. Niedriger CV (Coefficient of Variation) = höherer Score.",
|
||
business_meaning="Verdichteter Konsistenzindikator für Ernährungsumsetzung. Score basiert auf durchschnittlicher Variabilität der Makros (kcal, protein, fat, carbs).",
|
||
unit="score (0-100)",
|
||
time_window="28d",
|
||
output_type=OutputType.NUMERIC,
|
||
placeholder_type=PlaceholderType.INTERPRETED,
|
||
format_hint="Ganzzahl 0-100",
|
||
example_output="74",
|
||
|
||
# Quality
|
||
minimum_data_requirements="Mindestens 18 Einträge in 28 Tagen (60% coverage) für verlässliche Varianzberechnung.",
|
||
quality_filter_policy="Unvollständige oder stark lückenhafte Tage schwächen Aussagekraft. NULL-Werte bei einzelnen Makros werden für CV-Berechnung übersprungen.",
|
||
confidence_logic="Aus Datenabdeckung ableiten: 18+ Einträge = ausreichend für CV-Berechnung. Score selbst ist bereits ein Konsistenzmaß.",
|
||
missing_value_policy=MissingValuePolicy(
|
||
available=False,
|
||
value_raw=None,
|
||
missing_reason="insufficient_data",
|
||
legacy_display="nicht verfügbar"
|
||
),
|
||
known_limitations=(
|
||
"Score-Formel: CV (Coefficient of Variation) = std_dev / mean für jeden Makro. "
|
||
"Durchschnittlicher CV über alle 4 Makros. "
|
||
"Thresholds: CV<0.2=100, CV<0.3=85, CV<0.4=70, CV<0.5=55, CV>=0.5=max(30,100-CV*100). "
|
||
"WICHTIG: Niedrige Konsistenz ist nicht automatisch schlecht (bewusste Zyklen, Refeed-Tage). "
|
||
"Interpretation hängt vom Zielkontext ab."
|
||
),
|
||
|
||
# Architecture
|
||
layer_1_decision="Data Layer (nutrition_metrics.calculate_macro_consistency_score)",
|
||
layer_2a_decision="Placeholder Resolver (_safe_int, keine zusätzliche Logik)",
|
||
layer_2b_reuse_possible="Ja - Chart für Konsistenz-Verlauf oder Score-Trend möglich",
|
||
architecture_alignment="Phase 0c conform - Data Layer liefert Score, Resolver formatiert nur",
|
||
issue_53_alignment="Konform - Data Layer berechnet, Resolver wraps",
|
||
|
||
# Evidence (not exported, internal tracking)
|
||
evidence={}
|
||
)
|
||
|
||
# Evidence tagging
|
||
macro_consistency_metadata.set_evidence("resolver_module", EvidenceType.CODE_DERIVED)
|
||
macro_consistency_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
macro_consistency_metadata.set_evidence("data_layer_module", EvidenceType.CODE_DERIVED)
|
||
macro_consistency_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
macro_consistency_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED)
|
||
macro_consistency_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
|
||
macro_consistency_metadata.set_evidence("time_window", EvidenceType.CODE_DERIVED)
|
||
macro_consistency_metadata.set_evidence("output_type", EvidenceType.CODE_DERIVED)
|
||
macro_consistency_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
||
macro_consistency_metadata.set_evidence("minimum_data_requirements", EvidenceType.CODE_DERIVED)
|
||
macro_consistency_metadata.set_evidence("quality_filter_policy", EvidenceType.CODE_DERIVED)
|
||
macro_consistency_metadata.set_evidence("confidence_logic", EvidenceType.CODE_DERIVED)
|
||
macro_consistency_metadata.set_evidence("semantic_contract", EvidenceType.DRAFT_DERIVED)
|
||
macro_consistency_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
macro_consistency_metadata.set_evidence("known_limitations", EvidenceType.MIXED) # Formula from code, interpretation from draft
|
||
macro_consistency_metadata.set_evidence("layer_1_decision", EvidenceType.TO_VERIFY)
|
||
macro_consistency_metadata.set_evidence("layer_2a_decision", EvidenceType.TO_VERIFY)
|
||
macro_consistency_metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.TO_VERIFY)
|
||
|
||
register_placeholder(macro_consistency_metadata)
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 2. energy_balance_7d
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
energy_balance_metadata = PlaceholderMetadata(
|
||
key="energy_balance_7d",
|
||
category="Ernährung",
|
||
description="Energiebilanz 7-Tage (kcal/Tag Durchschnitt)",
|
||
|
||
# Technical
|
||
resolver_module="backend/placeholder_resolver.py",
|
||
resolver_function="_safe_float('energy_balance_7d', pid, decimals=0)",
|
||
data_layer_module="backend/data_layer/nutrition_metrics.py",
|
||
data_layer_function="calculate_energy_balance_7d",
|
||
source_tables=["nutrition_log", "weight_log", "profiles"],
|
||
|
||
# Semantic
|
||
semantic_contract="Liefert die geschätzte Energiebilanz über 7 Tage als Differenz zwischen durchschnittlicher Energieaufnahme und geschätztem TDEE (Total Daily Energy Expenditure). Positiver Wert = Überschuss, Negativer Wert = Defizit.",
|
||
business_meaning="Kernindikator für Defizit-/Überschussrichtung im Kurzfristfenster. Zeigt, ob aktuelle Ernährung auf Gewichtsverlust, Erhaltung oder Aufbau ausgerichtet ist.",
|
||
unit="kcal/day (Durchschnitt)",
|
||
time_window="7d",
|
||
output_type=OutputType.NUMERIC,
|
||
placeholder_type=PlaceholderType.INTERPRETED,
|
||
format_hint="Ganzzahl, gerundet auf 0 Dezimalstellen",
|
||
example_output="-380",
|
||
|
||
# Quality
|
||
minimum_data_requirements="Mindestens 4 Tage mit Kalorienerfassung in 7-Tage-Fenster. Aktuelles Gewicht aus weight_log erforderlich.",
|
||
quality_filter_policy=(
|
||
"Unvollständige Intake-Daten und fehlende Gewichtsmessung reduzieren Verlässlichkeit. "
|
||
"TDEE: Mifflin–St Jeor × PAL 1.55 wenn Höhe, Geschlecht, DOB und Gewicht vorhanden, sonst kg×32.5."
|
||
),
|
||
confidence_logic=(
|
||
"Kombiniert Intake-Abdeckung und Robustheit des Verbrauchsmodells. "
|
||
"Niedrigere Confidence bei <7 Tagen Daten oder fehlendem Gewicht. "
|
||
"PAL=1.55 ist ein Festwert (moderate Aktivität), kein individuelles Aktivitätslogging."
|
||
),
|
||
missing_value_policy=MissingValuePolicy(
|
||
available=False,
|
||
value_raw=None,
|
||
missing_reason="insufficient_data",
|
||
legacy_display="nicht verfügbar"
|
||
),
|
||
known_limitations=(
|
||
"TDEE: Bei vollständigem Profil (Größe, Geschlecht, DOB, Gewicht) Mifflin–St Jeor BMR × 1.55; "
|
||
"sonst Fallback kg×32.5. PAL ist nicht nutzerkonfigurierbar. "
|
||
"Energiebilanz ist modellbasiert, nicht gemessen. "
|
||
"Einheit kcal/Tag (Tagesmittel), nicht 7-Tage-Summe."
|
||
),
|
||
|
||
# Architecture
|
||
layer_1_decision="Data Layer (nutrition_metrics.calculate_energy_balance_7d) - berechnet Balance aus Intake und TDEE",
|
||
layer_2a_decision="Placeholder Resolver (_safe_float, rundet auf 0 Dezimalstellen)",
|
||
layer_2b_reuse_possible="Ja - Chart für Energiebilanz-Verlauf oder Defizit-Trend",
|
||
architecture_alignment="Phase 0c conform - Data Layer berechnet Balance, Resolver formatiert",
|
||
issue_53_alignment="Konform - Berechnung in Data Layer",
|
||
|
||
# Evidence
|
||
evidence={}
|
||
)
|
||
|
||
# Evidence tagging
|
||
energy_balance_metadata.set_evidence("resolver_module", EvidenceType.CODE_DERIVED)
|
||
energy_balance_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
energy_balance_metadata.set_evidence("data_layer_module", EvidenceType.CODE_DERIVED)
|
||
energy_balance_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
energy_balance_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED)
|
||
energy_balance_metadata.set_evidence("unit", EvidenceType.MIXED) # Code says kcal/day, canonical was ambiguous
|
||
energy_balance_metadata.set_evidence("time_window", EvidenceType.CODE_DERIVED)
|
||
energy_balance_metadata.set_evidence("output_type", EvidenceType.CODE_DERIVED)
|
||
energy_balance_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
||
energy_balance_metadata.set_evidence("minimum_data_requirements", EvidenceType.CODE_DERIVED)
|
||
energy_balance_metadata.set_evidence("quality_filter_policy", EvidenceType.CODE_DERIVED)
|
||
energy_balance_metadata.set_evidence("confidence_logic", EvidenceType.MIXED)
|
||
energy_balance_metadata.set_evidence("semantic_contract", EvidenceType.DRAFT_DERIVED)
|
||
energy_balance_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
energy_balance_metadata.set_evidence("known_limitations", EvidenceType.MIXED) # TDEE formula from code, limitations from both
|
||
energy_balance_metadata.set_evidence("layer_1_decision", EvidenceType.TO_VERIFY)
|
||
energy_balance_metadata.set_evidence("layer_2a_decision", EvidenceType.TO_VERIFY)
|
||
energy_balance_metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.TO_VERIFY)
|
||
|
||
register_placeholder(energy_balance_metadata)
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 3. energy_deficit_surplus
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
energy_deficit_surplus_metadata = PlaceholderMetadata(
|
||
key="energy_deficit_surplus",
|
||
category="Ernährung",
|
||
description="Energie Defizit/Überschuss Status",
|
||
|
||
# Technical
|
||
resolver_module="backend/placeholder_resolver.py",
|
||
resolver_function="_safe_str('energy_deficit_surplus', pid)",
|
||
data_layer_module="backend/data_layer/nutrition_metrics.py",
|
||
data_layer_function="calculate_energy_deficit_surplus",
|
||
source_tables=["nutrition_log", "weight_log"], # Indirect via energy_balance_7d
|
||
|
||
# Semantic
|
||
semantic_contract="Liefert qualitative Einordnung, ob aktuelle Energiezufuhr relativ zum geschätzten Bedarf in einem Defizit ('deficit'), auf Erhaltung ('maintenance') oder im Überschuss ('surplus') liegt.",
|
||
business_meaning="Leicht interpretierbarer Energie-Statusindikator. Vereinfacht Energiebilanz zu verständlichen Kategorien.",
|
||
unit="state (string)",
|
||
time_window="7d",
|
||
output_type=OutputType.STRING,
|
||
placeholder_type=PlaceholderType.INTERPRETED,
|
||
format_hint="Einer von drei Statuswerten: 'deficit', 'maintenance', 'surplus'",
|
||
example_output="deficit",
|
||
|
||
# Quality
|
||
minimum_data_requirements="Wie energy_balance_7d: mindestens 4 Tage mit Kalorienerfassung + aktuelles Gewicht.",
|
||
quality_filter_policy="Wie energy_balance_7d: unvollständige Intake-Daten und vereinfachte TDEE-Schätzung reduzieren Verlässlichkeit.",
|
||
confidence_logic="Abgeleitet von energy_balance_7d. Confidence der Balance überträgt sich auf Status.",
|
||
missing_value_policy=MissingValuePolicy(
|
||
available=False,
|
||
value_raw=None,
|
||
missing_reason="insufficient_data",
|
||
legacy_display="nicht verfügbar"
|
||
),
|
||
known_limitations=(
|
||
"Status-Schwellen: balance < -200 kcal/day = 'deficit', "
|
||
"balance > +200 kcal/day = 'surplus', "
|
||
"-200 bis +200 = 'maintenance'. "
|
||
"WICHTIG: Nur so gut wie zugrunde liegende TDEE-Schätzung (siehe energy_balance_7d). "
|
||
"Minimale Abweichungen nahe Maintenance-Schwelle können zu Statuswechsel führen. "
|
||
"200 kcal Schwelle ist willkürlich gewählt - physiologisch könnten auch 100-300 kcal sinnvoll sein."
|
||
),
|
||
|
||
# Architecture
|
||
layer_1_decision="Data Layer (nutrition_metrics.calculate_energy_deficit_surplus) - mapped Balance zu Status",
|
||
layer_2a_decision="Placeholder Resolver (_safe_str, keine zusätzliche Logik)",
|
||
layer_2b_reuse_possible="Ja - Status-Anzeige oder Kategorien-Chart",
|
||
architecture_alignment="Phase 0c conform - Status-Mapping in Data Layer",
|
||
issue_53_alignment="Konform - Kategorisierung in Data Layer",
|
||
|
||
# Evidence
|
||
evidence={}
|
||
)
|
||
|
||
# Evidence tagging
|
||
energy_deficit_surplus_metadata.set_evidence("resolver_module", EvidenceType.CODE_DERIVED)
|
||
energy_deficit_surplus_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
energy_deficit_surplus_metadata.set_evidence("data_layer_module", EvidenceType.CODE_DERIVED)
|
||
energy_deficit_surplus_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
energy_deficit_surplus_metadata.set_evidence("source_tables", EvidenceType.MIXED) # Indirect via energy_balance_7d
|
||
energy_deficit_surplus_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
|
||
energy_deficit_surplus_metadata.set_evidence("time_window", EvidenceType.CODE_DERIVED)
|
||
energy_deficit_surplus_metadata.set_evidence("output_type", EvidenceType.CODE_DERIVED)
|
||
energy_deficit_surplus_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
||
energy_deficit_surplus_metadata.set_evidence("minimum_data_requirements", EvidenceType.MIXED)
|
||
energy_deficit_surplus_metadata.set_evidence("quality_filter_policy", EvidenceType.MIXED)
|
||
energy_deficit_surplus_metadata.set_evidence("confidence_logic", EvidenceType.MIXED)
|
||
energy_deficit_surplus_metadata.set_evidence("semantic_contract", EvidenceType.DRAFT_DERIVED)
|
||
energy_deficit_surplus_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
energy_deficit_surplus_metadata.set_evidence("known_limitations", EvidenceType.MIXED) # Thresholds from code, interpretation mixed
|
||
energy_deficit_surplus_metadata.set_evidence("layer_1_decision", EvidenceType.TO_VERIFY)
|
||
energy_deficit_surplus_metadata.set_evidence("layer_2a_decision", EvidenceType.TO_VERIFY)
|
||
energy_deficit_surplus_metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.TO_VERIFY)
|
||
|
||
register_placeholder(energy_deficit_surplus_metadata)
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 4. intake_volatility
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
intake_volatility_metadata = PlaceholderMetadata(
|
||
key="intake_volatility",
|
||
category="Ernährung",
|
||
description="Intake-Volatilität (Klassifikation)",
|
||
|
||
# Technical
|
||
resolver_module="backend/placeholder_resolver.py",
|
||
resolver_function="_safe_str('intake_volatility', pid)",
|
||
data_layer_module="backend/data_layer/nutrition_metrics.py",
|
||
data_layer_function="calculate_intake_volatility",
|
||
source_tables=["nutrition_log"],
|
||
|
||
# Semantic
|
||
semantic_contract="Liefert qualitative Klassifikation der Variabilität der täglichen Kalorienaufnahme über 28 Tage. 'stable' = hohe Konstanz, 'moderate' = mittlere Schwankung, 'high' = starke Variabilität.",
|
||
business_meaning="Konsistenz- und Adhärenzindikator für Ernährungsumsetzung. Zeigt, wie gleichmäßig die Kalorienaufnahme über die Zeit ist.",
|
||
unit="category (string)",
|
||
time_window="28d",
|
||
output_type=OutputType.STRING,
|
||
placeholder_type=PlaceholderType.INTERPRETED,
|
||
format_hint="Einer von drei Werten: 'stable', 'moderate', 'high'",
|
||
example_output="moderate",
|
||
|
||
# Quality
|
||
minimum_data_requirements="Wie macro_consistency_score: mindestens 18 Einträge in 28 Tagen (60% coverage).",
|
||
quality_filter_policy="Ausreißer, lückenhafte Tage und unvollständige Logs reduzieren Verlässlichkeit. Abgeleitet von macro_consistency_score.",
|
||
confidence_logic="Aus Datenabdeckung und Vollständigkeit ableiten. Abhängig von macro_consistency_score Confidence.",
|
||
missing_value_policy=MissingValuePolicy(
|
||
available=False,
|
||
value_raw=None,
|
||
missing_reason="insufficient_data",
|
||
legacy_display="nicht verfügbar"
|
||
),
|
||
known_limitations=(
|
||
"Klassifikation basiert auf macro_consistency_score: "
|
||
"score >= 80: 'stable', score >= 60: 'moderate', score < 60: 'high'. "
|
||
"WICHTIG: Hohe Volatilität ist nicht automatisch schlecht (bewusste Refeed-/Diet-Break-Tage, unregelmäßige Wochenenden). "
|
||
"Interpretation hängt von Zielkontext und Trainingslogik ab. "
|
||
"Vereinfacht komplexes Konsistenzmuster zu drei Kategorien."
|
||
),
|
||
|
||
# Architecture
|
||
layer_1_decision="Data Layer (nutrition_metrics.calculate_intake_volatility) - mapped macro_consistency_score zu Kategorie",
|
||
layer_2a_decision="Placeholder Resolver (_safe_str, keine zusätzliche Logik)",
|
||
layer_2b_reuse_possible="Ja - Kategorie-Anzeige oder Trend-Chart",
|
||
architecture_alignment="Phase 0c conform - Kategorisierung in Data Layer",
|
||
issue_53_alignment="Konform - Mapping in Data Layer",
|
||
|
||
# Evidence
|
||
evidence={}
|
||
)
|
||
|
||
# Evidence tagging
|
||
intake_volatility_metadata.set_evidence("resolver_module", EvidenceType.CODE_DERIVED)
|
||
intake_volatility_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
intake_volatility_metadata.set_evidence("data_layer_module", EvidenceType.CODE_DERIVED)
|
||
intake_volatility_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
intake_volatility_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED)
|
||
intake_volatility_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
|
||
intake_volatility_metadata.set_evidence("time_window", EvidenceType.CODE_DERIVED)
|
||
intake_volatility_metadata.set_evidence("output_type", EvidenceType.CODE_DERIVED)
|
||
intake_volatility_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
||
intake_volatility_metadata.set_evidence("minimum_data_requirements", EvidenceType.MIXED)
|
||
intake_volatility_metadata.set_evidence("quality_filter_policy", EvidenceType.MIXED)
|
||
intake_volatility_metadata.set_evidence("confidence_logic", EvidenceType.MIXED)
|
||
intake_volatility_metadata.set_evidence("semantic_contract", EvidenceType.DRAFT_DERIVED)
|
||
intake_volatility_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
intake_volatility_metadata.set_evidence("known_limitations", EvidenceType.MIXED) # Thresholds from code, interpretation mixed
|
||
intake_volatility_metadata.set_evidence("layer_1_decision", EvidenceType.TO_VERIFY)
|
||
intake_volatility_metadata.set_evidence("layer_2a_decision", EvidenceType.TO_VERIFY)
|
||
intake_volatility_metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.TO_VERIFY)
|
||
|
||
register_placeholder(intake_volatility_metadata)
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 5. nutrition_days
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
nutrition_days_metadata = PlaceholderMetadata(
|
||
key="nutrition_days",
|
||
category="Ernährung",
|
||
description="Anzahl valider Ernährungstage (30d)",
|
||
|
||
# Technical
|
||
resolver_module="backend/placeholder_resolver.py",
|
||
resolver_function="get_nutrition_days(pid, 30)",
|
||
data_layer_module="backend/data_layer/nutrition_metrics.py",
|
||
data_layer_function="get_nutrition_days_data",
|
||
source_tables=["nutrition_log"],
|
||
|
||
# Semantic
|
||
semantic_contract="Liefert die Anzahl der Tage mit valider Ernährungserfassung im 30-Tage-Fenster. Zählt alle unique Datums-Einträge in nutrition_log.",
|
||
business_meaning="Direktes Maß für Datenabdeckung und Aussagekraft der Ernährungsplaceholder. Zeigt, an wie vielen Tagen im Zeitfenster Ernährungsdaten erfasst wurden.",
|
||
unit="days",
|
||
time_window="30d",
|
||
output_type=OutputType.NUMERIC,
|
||
placeholder_type=PlaceholderType.META,
|
||
format_hint="Ganzzahl 0-30",
|
||
example_output="22",
|
||
|
||
# Quality
|
||
minimum_data_requirements="Keine Mindestmenge für Existenz des Placeholders selbst. Wert kann 0 sein.",
|
||
quality_filter_policy=(
|
||
"Definition 'valider Tag': Jeder Tag mit mindestens einem Eintrag in nutrition_log gilt als valide. "
|
||
"WICHTIG: Sagt NICHTS über Qualität oder Vollständigkeit des einzelnen Tages. "
|
||
"Auch Teil-Tage (z.B. nur Frühstück erfasst) zählen als valider Tag. "
|
||
"Keine Prüfung auf Mindest-Kalorienanzahl oder vollständige Makros."
|
||
),
|
||
confidence_logic="Nicht klassisch nötig - der Wert selbst dient als Verlässlichkeitsindikator für andere Ernährungsplaceholder.",
|
||
missing_value_policy=MissingValuePolicy(
|
||
available=True, # Always available, even if 0 days
|
||
value_raw=0,
|
||
missing_reason=None,
|
||
legacy_display="0"
|
||
),
|
||
known_limitations=(
|
||
"Zählt nur UNIQUE dates mit Einträgen, nicht die Anzahl der Einträge. "
|
||
"Sagt nichts über Qualität der einzelnen Tage (z.B. Vollständigkeit, Plausibilität). "
|
||
"Nur Abdeckungsmaß, kein Qualitätsmaß. "
|
||
"Bei mehreren Einträgen pro Tag wird Tag nur einmal gezählt."
|
||
),
|
||
|
||
# Architecture
|
||
layer_1_decision="Data Layer (nutrition_metrics.get_nutrition_days_data) - zählt unique dates",
|
||
layer_2a_decision="Placeholder Resolver (get_nutrition_days, formatiert zu String)",
|
||
layer_2b_reuse_possible="Ja - Coverage-Chart oder Datenqualitäts-Dashboard",
|
||
architecture_alignment="Phase 0c conform - Count in Data Layer, Formatting in Resolver",
|
||
issue_53_alignment="Konform - Zählung in Data Layer",
|
||
|
||
# Evidence
|
||
evidence={}
|
||
)
|
||
|
||
# Evidence tagging
|
||
nutrition_days_metadata.set_evidence("resolver_module", EvidenceType.CODE_DERIVED)
|
||
nutrition_days_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED)
|
||
nutrition_days_metadata.set_evidence("data_layer_module", EvidenceType.CODE_DERIVED)
|
||
nutrition_days_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED)
|
||
nutrition_days_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED)
|
||
nutrition_days_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
|
||
nutrition_days_metadata.set_evidence("time_window", EvidenceType.CODE_DERIVED)
|
||
nutrition_days_metadata.set_evidence("output_type", EvidenceType.CODE_DERIVED)
|
||
nutrition_days_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
||
nutrition_days_metadata.set_evidence("minimum_data_requirements", EvidenceType.CODE_DERIVED)
|
||
nutrition_days_metadata.set_evidence("quality_filter_policy", EvidenceType.MIXED) # Logic from code, definition from inspection
|
||
nutrition_days_metadata.set_evidence("confidence_logic", EvidenceType.DRAFT_DERIVED)
|
||
nutrition_days_metadata.set_evidence("semantic_contract", EvidenceType.MIXED) # Count logic from code, interpretation from draft
|
||
nutrition_days_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
||
nutrition_days_metadata.set_evidence("known_limitations", EvidenceType.MIXED)
|
||
nutrition_days_metadata.set_evidence("layer_1_decision", EvidenceType.TO_VERIFY)
|
||
nutrition_days_metadata.set_evidence("layer_2a_decision", EvidenceType.TO_VERIFY)
|
||
nutrition_days_metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.TO_VERIFY)
|
||
|
||
register_placeholder(nutrition_days_metadata)
|
||
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# Registration Summary
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
"""
|
||
Part C Registration Complete:
|
||
- macro_consistency_score: Score-based consistency indicator (CV-based)
|
||
- energy_balance_7d: kcal/day average balance (intake - estimated TDEE)
|
||
- energy_deficit_surplus: Status classification (deficit/maintenance/surplus)
|
||
- intake_volatility: Category classification (stable/moderate/high)
|
||
- nutrition_days: Count of valid nutrition days (meta indicator)
|
||
|
||
Total Nutrition Cluster:
|
||
- Part A: 4 placeholders (kcal_avg, protein_avg, carb_avg, fat_avg)
|
||
- Part B: 5 placeholders (protein targets + adequacy)
|
||
- Part C: 5 placeholders in dieser Datei (consistency + balance + meta)
|
||
- nutrition_score: eigenes Modul nutrition_score.py
|
||
→ 15 Ernährungs-Platzhalter gesamt (A+B+C+nutrition_score)
|
||
|
||
All registrations follow Phase 0c Multi-Layer Architecture:
|
||
- Layer 1 (Data Layer): Calculations
|
||
- Layer 2a (Placeholder Resolver): Formatting only
|
||
- No logic changes from existing implementations
|
||
- Evidence-based metadata tagging
|
||
"""
|