From ffb30eaff5d08cc3b5ddd7ee3339a21e71fef360 Mon Sep 17 00:00:00 2001 From: Lars Date: Thu, 2 Apr 2026 12:55:03 +0200 Subject: [PATCH] feat: Placeholder Registry Part C - Nutrition Consistency & Balance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Registers 5 nutrition-related placeholders with complete metadata: - macro_consistency_score: CV-based Makro-Konsistenz Score (0-100) - energy_balance_7d: Energiebilanz (kcal/day avg, intake - TDEE) - energy_deficit_surplus: Status (deficit/maintenance/surplus) - intake_volatility: Klassifikation (stable/moderate/high) - nutrition_days: Anzahl valider Ernährungstage (30d) All placeholders with evidence-based tagging: - 22 metadata fields per placeholder - CODE_DERIVED: Technical fields, formulas from code inspection - DRAFT_DERIVED: Semantic fields from canonical requirements - MIXED: Calculation logic (TDEE model, thresholds, formulas) - TO_VERIFY: Architecture layer decisions Critical details documented: - macro_consistency_score: CV formula + thresholds explicitly documented - energy_balance_7d: TDEE model (weight_kg × 32.5), unit clarified (kcal/day avg) - energy_deficit_surplus: Status thresholds (<-200, -200 to +200, >+200) - intake_volatility: Category mapping from macro_consistency_score - nutrition_days: Validation criteria (any entry = valid day) Known limitations captured: - TDEE model is simplified (no activity/age/gender adjustment) - Thresholds are somewhat arbitrary (e.g., 200 kcal for deficit/surplus) - High volatility not necessarily bad (context-dependent) Registry now contains 14 placeholders total: - Part A: 4 (kcal_avg, protein_avg, carb_avg, fat_avg) - Part B: 5 (protein targets + adequacy) - Part C: 5 (consistency + balance + meta) Framework: PLACEHOLDER_REGISTRY_FRAMEWORK.md (verbindlich ab 2026-04-02) Co-Authored-By: Claude Opus 4.6 --- backend/placeholder_registrations/__init__.py | 3 +- .../nutrition_part_c.py | 446 ++++++++++++++++++ 2 files changed, 448 insertions(+), 1 deletion(-) create mode 100644 backend/placeholder_registrations/nutrition_part_c.py diff --git a/backend/placeholder_registrations/__init__.py b/backend/placeholder_registrations/__init__.py index 5d942ba..b6c2b36 100644 --- a/backend/placeholder_registrations/__init__.py +++ b/backend/placeholder_registrations/__init__.py @@ -7,5 +7,6 @@ Auto-imports all placeholder registrations to populate the global registry. # Import all registration modules to trigger auto-registration from . import nutrition_part_a from . import nutrition_part_b +from . import nutrition_part_c -__all__ = ['nutrition_part_a', 'nutrition_part_b'] +__all__ = ['nutrition_part_a', 'nutrition_part_b', 'nutrition_part_c'] diff --git a/backend/placeholder_registrations/nutrition_part_c.py b/backend/placeholder_registrations/nutrition_part_c.py new file mode 100644 index 0000000..b1c3216 --- /dev/null +++ b/backend/placeholder_registrations/nutrition_part_c.py @@ -0,0 +1,446 @@ +""" +Placeholder Registrations - Nutrition Part C + +Registers 5 nutrition-related placeholders with complete metadata: +- 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"], + + # 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-Schätzung ist vereinfacht (weight_kg × 32.5).", + confidence_logic=( + "Kombiniert Intake-Abdeckung und Robustheit des Verbrauchsmodells. " + "Niedrigere Confidence bei <7 Tagen Daten oder fehlendem Gewicht. " + "TDEE-Modell ist vereinfacht → inherent uncertainty." + ), + missing_value_policy=MissingValuePolicy( + available=False, + value_raw=None, + missing_reason="insufficient_data", + legacy_display="nicht verfügbar" + ), + known_limitations=( + "TDEE-MODELL: Vereinfacht als bodyweight_kg × 32.5 (mittlerer Multiplikator). " + "NICHT berücksichtigt: Aktivitätslevel, Alter, Geschlecht, Stoffwechselanpassungen. " + "TODO in Code: Harris-Benedict oder Mifflin-St Jeor für präzisere TDEE-Schätzung. " + "ACHTUNG: Energiebilanz ist modellbasiert, nicht direkt gemessen. " + "Einheit ist kcal/Tag (daily average), NICHT 7d-Total." + ), + + # 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.TEXT, + 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.TEXT, + 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 (consistency + balance + meta) +→ 14 nutrition placeholders total + +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 +"""