""" Nutrition Part B Placeholder Registrations Registers the 5 protein-specific metrics in the central placeholder registry: - protein_ziel_low - protein_ziel_high - protein_g_per_kg - protein_days_in_target - protein_adequacy_28d Evidence-based metadata with clear tagging of source. Includes documentation of open points (weight basis inconsistency, score logic). """ from placeholder_registry import ( PlaceholderMetadata, MissingValuePolicy, EvidenceType, OutputType, PlaceholderType, register_placeholder ) def register_nutrition_part_b(): """ Register Part B protein placeholders. Metadata sources: - code-derived: extracted from actual code - draft-derived: from canonical requirements draft - mixed: combination of code and draft - unresolved: not explicitly documented - to_verify: claimed but not verified """ # ── protein_ziel_low ────────────────────────────────────────────────────── low_metadata = PlaceholderMetadata( key="protein_ziel_low", category="Ernährung", description="Unteres Proteinziel (1.6 g/kg)", # Technical resolver_module="backend/placeholder_resolver.py", resolver_function="get_protein_ziel_low", data_layer_module="backend/data_layer/nutrition_metrics.py", data_layer_function="get_protein_targets_data", source_tables=["weight_log"], # Semantic semantic_contract=( "Liefert die untere Proteinziel-Grenze basierend auf aktuellem " "Körpergewicht (1.6 g/kg). Ziel für Muskelerhalt in Maintenance-Phasen." ), business_meaning="Maintenance-Ziel für Muskelerhalt", unit="g/day", time_window="snapshot", output_type=OutputType.NUMERIC, placeholder_type=PlaceholderType.INTERPRETED, format_hint="Ganzzahl", example_output="128", # Quality confidence_logic="Binary: weight vorhanden/nicht vorhanden", missing_value_policy=MissingValuePolicy( available=False, value_raw=None, missing_reason="no_data", legacy_display="nicht verfügbar" ), known_limitations=( "Basiert auf single-point weight (latest entry); " "anfällig für Gewichts-Outlier (z.B. nach Refeed-Tag)" ), # Architecture layer_1_decision="Data Layer (nutrition_metrics.get_protein_targets_data)", layer_2a_decision="Placeholder Resolver (formatting only)", layer_2b_reuse_possible=None, # to_verify architecture_alignment="Phase 0c Multi-Layer Architecture conform", issue_53_alignment="Layer separation established" ) # Evidence low_metadata.set_evidence("key", EvidenceType.CODE_DERIVED) low_metadata.set_evidence("category", EvidenceType.CODE_DERIVED) low_metadata.set_evidence("description", EvidenceType.MIXED) low_metadata.set_evidence("resolver_module", EvidenceType.CODE_DERIVED) low_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED) low_metadata.set_evidence("data_layer_module", EvidenceType.CODE_DERIVED) low_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED) low_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED) low_metadata.set_evidence("semantic_contract", EvidenceType.DRAFT_DERIVED) low_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED) low_metadata.set_evidence("unit", EvidenceType.MIXED) # implicit in code, confirmed by draft low_metadata.set_evidence("time_window", EvidenceType.CODE_DERIVED) low_metadata.set_evidence("output_type", EvidenceType.CODE_DERIVED) low_metadata.set_evidence("placeholder_type", EvidenceType.MIXED) low_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED) low_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED) low_metadata.set_evidence("confidence_logic", EvidenceType.CODE_DERIVED) low_metadata.set_evidence("missing_value_policy", EvidenceType.CODE_DERIVED) low_metadata.set_evidence("known_limitations", EvidenceType.MIXED) low_metadata.set_evidence("layer_1_decision", EvidenceType.CODE_DERIVED) low_metadata.set_evidence("layer_2a_decision", EvidenceType.CODE_DERIVED) low_metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.TO_VERIFY) low_metadata.set_evidence("architecture_alignment", EvidenceType.CODE_DERIVED) low_metadata.set_evidence("issue_53_alignment", EvidenceType.MIXED) register_placeholder(low_metadata) # ── protein_ziel_high ───────────────────────────────────────────────────── high_metadata = PlaceholderMetadata( key="protein_ziel_high", category="Ernährung", description="Oberes Proteinziel (2.2 g/kg)", # Technical (same as protein_ziel_low) resolver_module="backend/placeholder_resolver.py", resolver_function="get_protein_ziel_high", data_layer_module="backend/data_layer/nutrition_metrics.py", data_layer_function="get_protein_targets_data", source_tables=["weight_log"], # Semantic semantic_contract=( "Liefert die obere Proteinziel-Grenze basierend auf aktuellem " "Körpergewicht (2.2 g/kg). Ziel für Muskelaufbau in hypertrophen Phasen." ), business_meaning="Muskelaufbau-Ziel für hypertrophe Phasen", unit="g/day", time_window="snapshot", output_type=OutputType.NUMERIC, placeholder_type=PlaceholderType.INTERPRETED, format_hint="Ganzzahl", example_output="176", # Quality confidence_logic="Binary: weight vorhanden/nicht vorhanden", missing_value_policy=MissingValuePolicy( available=False, value_raw=None, missing_reason="no_data", legacy_display="nicht verfügbar" ), known_limitations=( "Basiert auf single-point weight (latest entry); " "anfällig für Gewichts-Outlier" ), # Architecture layer_1_decision="Data Layer (nutrition_metrics.get_protein_targets_data)", layer_2a_decision="Placeholder Resolver (formatting only)", layer_2b_reuse_possible=None, architecture_alignment="Phase 0c Multi-Layer Architecture conform", issue_53_alignment="Layer separation established" ) # Evidence (identical to protein_ziel_low) high_metadata.set_evidence("key", EvidenceType.CODE_DERIVED) high_metadata.set_evidence("category", EvidenceType.CODE_DERIVED) high_metadata.set_evidence("description", EvidenceType.MIXED) high_metadata.set_evidence("resolver_module", EvidenceType.CODE_DERIVED) high_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED) high_metadata.set_evidence("data_layer_module", EvidenceType.CODE_DERIVED) high_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED) high_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED) high_metadata.set_evidence("semantic_contract", EvidenceType.DRAFT_DERIVED) high_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED) high_metadata.set_evidence("unit", EvidenceType.MIXED) high_metadata.set_evidence("time_window", EvidenceType.CODE_DERIVED) high_metadata.set_evidence("output_type", EvidenceType.CODE_DERIVED) high_metadata.set_evidence("placeholder_type", EvidenceType.MIXED) high_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED) high_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED) high_metadata.set_evidence("confidence_logic", EvidenceType.CODE_DERIVED) high_metadata.set_evidence("missing_value_policy", EvidenceType.CODE_DERIVED) high_metadata.set_evidence("known_limitations", EvidenceType.MIXED) high_metadata.set_evidence("layer_1_decision", EvidenceType.CODE_DERIVED) high_metadata.set_evidence("layer_2a_decision", EvidenceType.CODE_DERIVED) high_metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.TO_VERIFY) high_metadata.set_evidence("architecture_alignment", EvidenceType.CODE_DERIVED) high_metadata.set_evidence("issue_53_alignment", EvidenceType.MIXED) register_placeholder(high_metadata) # ── protein_g_per_kg ────────────────────────────────────────────────────── gpk_metadata = PlaceholderMetadata( key="protein_g_per_kg", category="Ernährung", description="Protein g/kg Körpergewicht", # Technical resolver_module="backend/placeholder_resolver.py", resolver_function="_safe_float", data_layer_module="backend/data_layer/nutrition_metrics.py", data_layer_function="calculate_protein_g_per_kg", source_tables=["nutrition_log", "weight_log"], # Semantic semantic_contract=( "Liefert die durchschnittliche Proteinzufuhr relativ zum Körpergewicht. " "Berechnung: protein_7d_avg / latest_weight. " "WICHTIG: Protein ist geglättet (7d), Gewicht ist single-point." ), business_meaning="Zentraler Zielindikator für Muskelerhalt und Aufbau", unit="g/kg/day", time_window="7d", # dominante Komponente (protein); weight ist snapshot, aber secondary output_type=OutputType.NUMERIC, placeholder_type=PlaceholderType.INTERPRETED, format_hint="Dezimalzahl (1-2 Stellen)", example_output="1.95", # Quality confidence_logic="Minimum von protein_confidence und weight_availability", missing_value_policy=MissingValuePolicy( available=False, value_raw=None, missing_reason="insufficient_data", legacy_display="nicht verfügbar" ), known_limitations=( "KRITISCHE INKONSISTENZ: Protein ist geglättet (7d average), " "Gewicht ist single-point (latest). Anfällig für Gewichts-Outlier. " "Ein Refeed-Tag kann den Wert stark verfälschen, obwohl Protein-Intake stabil ist." ), # Architecture layer_1_decision="Data Layer (nutrition_metrics.calculate_protein_g_per_kg)", layer_2a_decision="Placeholder Resolver (_safe_float wrapper)", layer_2b_reuse_possible=None, architecture_alignment="Phase 0c Multi-Layer Architecture conform", issue_53_alignment="Layer separation established" ) # Evidence gpk_metadata.set_evidence("key", EvidenceType.CODE_DERIVED) gpk_metadata.set_evidence("category", EvidenceType.CODE_DERIVED) gpk_metadata.set_evidence("description", EvidenceType.CODE_DERIVED) gpk_metadata.set_evidence("resolver_module", EvidenceType.CODE_DERIVED) gpk_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED) gpk_metadata.set_evidence("data_layer_module", EvidenceType.CODE_DERIVED) gpk_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED) gpk_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED) gpk_metadata.set_evidence("semantic_contract", EvidenceType.MIXED) # code + explicit documentation gpk_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED) gpk_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED) gpk_metadata.set_evidence("time_window", EvidenceType.CODE_DERIVED) # explicitly documented as mixed gpk_metadata.set_evidence("output_type", EvidenceType.CODE_DERIVED) gpk_metadata.set_evidence("placeholder_type", EvidenceType.MIXED) gpk_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED) gpk_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED) gpk_metadata.set_evidence("confidence_logic", EvidenceType.UNRESOLVED) # not explicitly documented gpk_metadata.set_evidence("missing_value_policy", EvidenceType.CODE_DERIVED) gpk_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED) # identified from code analysis gpk_metadata.set_evidence("layer_1_decision", EvidenceType.CODE_DERIVED) gpk_metadata.set_evidence("layer_2a_decision", EvidenceType.CODE_DERIVED) gpk_metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.TO_VERIFY) gpk_metadata.set_evidence("architecture_alignment", EvidenceType.CODE_DERIVED) gpk_metadata.set_evidence("issue_53_alignment", EvidenceType.MIXED) register_placeholder(gpk_metadata) # ── protein_days_in_target ──────────────────────────────────────────────── days_metadata = PlaceholderMetadata( key="protein_days_in_target", category="Ernährung", description="Tage im Protein-Zielbereich (7d)", # Technical resolver_module="backend/placeholder_resolver.py", resolver_function="_safe_str", data_layer_module="backend/data_layer/nutrition_metrics.py", data_layer_function="calculate_protein_days_in_target", source_tables=["nutrition_log", "weight_log"], # Semantic semantic_contract=( "Liefert Anzahl Tage im Protein-Zielbereich relativ zu Gesamttagen. " "Target-Range: 1.6-2.2 g/kg (hardcoded). " "Format: 'X/Y' (z.B. '5/7' = 5 von 7 Tagen im Ziel)." ), business_meaning="Adhärenz-Indikator für Proteinversorgung", unit="days_ratio", time_window="7d", output_type=OutputType.STRING, placeholder_type=PlaceholderType.INTERPRETED, format_hint="String format 'X/Y' (e.g. '5/7')", example_output="5/7", # Quality confidence_logic="Abhängig von nutrition_log Datenabdeckung", missing_value_policy=MissingValuePolicy( available=False, value_raw=None, missing_reason="no_data", legacy_display="nicht verfügbar" ), known_limitations=( "Target-Range 1.6-2.2 g/kg fest kodiert (default parameters), " "nicht konfigurierbar. Keine Integration mit Goal-System." ), # Architecture layer_1_decision="Data Layer (nutrition_metrics.calculate_protein_days_in_target)", layer_2a_decision="Placeholder Resolver (_safe_str wrapper)", layer_2b_reuse_possible=None, architecture_alignment="Phase 0c Multi-Layer Architecture conform", issue_53_alignment="Layer separation established" ) # Evidence days_metadata.set_evidence("key", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("category", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("description", EvidenceType.MIXED) days_metadata.set_evidence("resolver_module", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("data_layer_module", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("semantic_contract", EvidenceType.MIXED) days_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED) days_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("time_window", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("output_type", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("placeholder_type", EvidenceType.MIXED) days_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("confidence_logic", EvidenceType.UNRESOLVED) days_metadata.set_evidence("missing_value_policy", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("known_limitations", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("layer_1_decision", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("layer_2a_decision", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.TO_VERIFY) days_metadata.set_evidence("architecture_alignment", EvidenceType.CODE_DERIVED) days_metadata.set_evidence("issue_53_alignment", EvidenceType.MIXED) register_placeholder(days_metadata) # ── protein_adequacy_28d ────────────────────────────────────────────────── adequacy_metadata = PlaceholderMetadata( key="protein_adequacy_28d", category="Ernährung", description="Protein Adequacy Score (0-100)", # Technical resolver_module="backend/placeholder_resolver.py", resolver_function="_safe_int", data_layer_module="backend/data_layer/nutrition_metrics.py", data_layer_function="calculate_protein_adequacy_28d", source_tables=["nutrition_log", "weight_log"], # Semantic semantic_contract=( "Liefert standardisierten Angemessenheitswert der Proteinversorgung " "über 28 Tage relativ zu definierten Protein-Zielbereichen (1.6-2.2 g/kg). " "Score-Logik: " "- Days in target [1.6-2.2]: 100 points; " "- Days slightly below [1.4-1.6]: partial points (linear interpolation); " "- Days far below (<1.4): 0 points; " "- Days above (>2.2): 100 points (no penalty). " "Final score: average over 28d." ), business_meaning="Verdichteter Zielerreichungsindikator für Proteinversorgung", unit="score (0-100)", time_window="28d", output_type=OutputType.NUMERIC, placeholder_type=PlaceholderType.SCORE, format_hint="Integer 0-100, höher = besser", example_output="82", # Quality confidence_logic="Abgeleitet aus Datenabdeckung über 28d", missing_value_policy=MissingValuePolicy( available=False, value_raw=None, missing_reason="insufficient_data", legacy_display="nicht verfügbar" ), known_limitations=( "Score muss transparent erklärt werden; ohne Skalen-Dokumentation " "interpretationsanfällig. Scoring-Schwellen [1.4, 1.6, 2.2] nicht explizit " "im Code dokumentiert, nur in Logik implementiert." ), # Architecture layer_1_decision="Data Layer (nutrition_metrics.calculate_protein_adequacy_28d)", layer_2a_decision="Placeholder Resolver (_safe_int wrapper)", layer_2b_reuse_possible=None, architecture_alignment="Phase 0c Multi-Layer Architecture conform", issue_53_alignment="Layer separation established" ) # Evidence adequacy_metadata.set_evidence("key", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("category", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("description", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("resolver_module", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("resolver_function", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("data_layer_module", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("data_layer_function", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("source_tables", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("semantic_contract", EvidenceType.MIXED) # code + explicit documentation adequacy_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED) adequacy_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("time_window", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("output_type", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("placeholder_type", EvidenceType.MIXED) adequacy_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("confidence_logic", EvidenceType.UNRESOLVED) adequacy_metadata.set_evidence("missing_value_policy", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("known_limitations", EvidenceType.MIXED) # code analysis + draft adequacy_metadata.set_evidence("layer_1_decision", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("layer_2a_decision", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("layer_2b_reuse_possible", EvidenceType.TO_VERIFY) adequacy_metadata.set_evidence("architecture_alignment", EvidenceType.CODE_DERIVED) adequacy_metadata.set_evidence("issue_53_alignment", EvidenceType.MIXED) register_placeholder(adequacy_metadata) # Auto-register on import register_nutrition_part_b()