""" 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.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 (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 """