Part A Implementation (Nutrition Basis Metrics): - Registry-based metadata system (flexible, not hardcoded) - 4 placeholders registered: kcal_avg, protein_avg, carb_avg, fat_avg - Evidence-based tagging (code-derived, draft-derived, unresolved, to_verify) - Single source of truth for all consumers (Prompt, GUI, Export, Validation) Technical: - backend/placeholder_registry.py: Core registry framework - backend/placeholder_registrations/nutrition_part_a.py: Part A registrations - backend/placeholder_registry_export.py: Export integration - backend/routers/prompts.py: /placeholders/export-values-extended integration Metadata completeness: - 22 metadata fields per placeholder - Evidence tracking for all fields - Architecture alignment (Layer 1/2a/2b) NO LOGIC CHANGE: - Data Layer unchanged (nutrition_metrics.py) - Resolver unchanged (placeholder_resolver.py) - Values identical (only metadata/export enhanced) Breaking Change Risk: NONE Deploy Risk: VERY LOW (only export enhancement) Plan: .claude/task/rework_0b_placeholder/NUTRITION_PART_A_CHANGE_PLAN.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
217 lines
9.8 KiB
Python
217 lines
9.8 KiB
Python
"""
|
|
Nutrition Part A Placeholder Registrations
|
|
|
|
Registers the 4 basis nutrition metrics in the central placeholder registry:
|
|
- kcal_avg
|
|
- protein_avg
|
|
- carb_avg
|
|
- fat_avg
|
|
|
|
Evidence-based metadata with clear tagging of source.
|
|
"""
|
|
|
|
from placeholder_registry import (
|
|
PlaceholderMetadata,
|
|
MissingValuePolicy,
|
|
EvidenceType,
|
|
OutputType,
|
|
PlaceholderType,
|
|
register_placeholder
|
|
)
|
|
|
|
|
|
def register_nutrition_part_a():
|
|
"""
|
|
Register Part A nutrition 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
|
|
"""
|
|
|
|
# Common metadata for all 4 placeholders
|
|
common_metadata = {
|
|
"category": "Ernährung",
|
|
"resolver_module": "backend/placeholder_resolver.py",
|
|
"resolver_function": "get_nutrition_avg",
|
|
"data_layer_module": "backend/data_layer/nutrition_metrics.py",
|
|
"data_layer_function": "get_nutrition_average_data",
|
|
"source_tables": ["nutrition_log"],
|
|
"time_window": "30d",
|
|
"output_type": OutputType.NUMERIC,
|
|
"placeholder_type": PlaceholderType.INTERPRETED,
|
|
"confidence_logic": "datenpunktbasierte Coverage-Logik (calculate_confidence)",
|
|
"missing_value_policy": MissingValuePolicy(
|
|
available=False,
|
|
value_raw=None,
|
|
missing_reason="insufficient_data",
|
|
legacy_display="nicht genug Daten"
|
|
),
|
|
"layer_1_decision": "Data Layer (nutrition_metrics.get_nutrition_average_data)",
|
|
"layer_2a_decision": "Placeholder Resolver (formatting only)",
|
|
"architecture_alignment": "Phase 0c Multi-Layer Architecture conform",
|
|
}
|
|
|
|
# Common evidence for shared fields
|
|
common_evidence = {
|
|
"category": EvidenceType.CODE_DERIVED, # from placeholder_resolver.py:1380
|
|
"resolver_module": EvidenceType.CODE_DERIVED,
|
|
"resolver_function": EvidenceType.CODE_DERIVED,
|
|
"data_layer_module": EvidenceType.CODE_DERIVED, # from import statement
|
|
"data_layer_function": EvidenceType.CODE_DERIVED, # from resolver code
|
|
"source_tables": EvidenceType.CODE_DERIVED, # from SQL query
|
|
"time_window": EvidenceType.CODE_DERIVED, # from PLACEHOLDER_MAP lambda
|
|
"output_type": EvidenceType.CODE_DERIVED, # from resolver return type
|
|
"placeholder_type": EvidenceType.MIXED, # draft classification + code shows aggregation
|
|
"confidence_logic": EvidenceType.CODE_DERIVED, # from data layer
|
|
"missing_value_policy": EvidenceType.CODE_DERIVED, # from resolver code
|
|
"layer_1_decision": EvidenceType.CODE_DERIVED,
|
|
"layer_2a_decision": EvidenceType.CODE_DERIVED,
|
|
"layer_2b_reuse_possible": EvidenceType.TO_VERIFY, # not verified in charts
|
|
"architecture_alignment": EvidenceType.CODE_DERIVED, # imports from data_layer
|
|
"issue_53_alignment": EvidenceType.MIXED, # layer separation visible, issue conformity derived
|
|
"minimum_data_requirements": EvidenceType.UNRESOLVED, # not explicit in code
|
|
"quality_filter_policy": EvidenceType.UNRESOLVED, # not implemented
|
|
}
|
|
|
|
# ── kcal_avg ──────────────────────────────────────────────────────────────
|
|
|
|
kcal_metadata = PlaceholderMetadata(
|
|
key="kcal_avg",
|
|
description="Durchschn. Kalorien (30d)",
|
|
semantic_contract=(
|
|
"Liefert den Durchschnitt der dokumentierten täglichen Kalorienaufnahme "
|
|
"über das definierte Auswertungsfenster. Der Wert ist als Intake-Mittelwert "
|
|
"zu interpretieren, nicht als Energiebedarf oder Energiebilanz."
|
|
),
|
|
business_meaning="Kernwert für Ernährungsstatus, Defizit-/Überschussbewertung und Zielabgleich",
|
|
unit="kcal/day",
|
|
format_hint="Ganzzahl",
|
|
example_output="2140",
|
|
known_limitations="nur Intake, kein Bedarf; sagt allein nichts über Zielpassung",
|
|
layer_2b_reuse_possible=None, # to_verify - not checked in chart code
|
|
issue_53_alignment="Layer separation established",
|
|
minimum_data_requirements=None, # unresolved
|
|
quality_filter_policy=None, # unresolved
|
|
**common_metadata
|
|
)
|
|
|
|
kcal_metadata.evidence.update(common_evidence)
|
|
kcal_metadata.set_evidence("semantic_contract", EvidenceType.DRAFT_DERIVED)
|
|
kcal_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
|
kcal_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED) # from resolver: no " g" suffix
|
|
kcal_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED) # int(value)
|
|
kcal_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED) # runtime testable
|
|
kcal_metadata.set_evidence("known_limitations", EvidenceType.DRAFT_DERIVED)
|
|
|
|
register_placeholder(kcal_metadata)
|
|
|
|
# ── protein_avg ───────────────────────────────────────────────────────────
|
|
|
|
protein_metadata = PlaceholderMetadata(
|
|
key="protein_avg",
|
|
description="Durchschn. Protein in g (30d)",
|
|
semantic_contract=(
|
|
"Liefert den Durchschnitt der dokumentierten täglichen Proteinzufuhr "
|
|
"über das definierte Auswertungsfenster."
|
|
),
|
|
business_meaning=(
|
|
"Zentraler Placeholder für Muskelerhalt, Muskelaufbau, Recomposition "
|
|
"und Absicherung im Defizit"
|
|
),
|
|
unit="g/day",
|
|
format_hint="Ganzzahl in g/day",
|
|
example_output="156",
|
|
known_limitations=(
|
|
"absoluter Wert allein reicht nicht immer; sollte oft relativ zum "
|
|
"Körpergewicht interpretiert werden"
|
|
),
|
|
layer_2b_reuse_possible=None,
|
|
issue_53_alignment="Layer separation established",
|
|
minimum_data_requirements=None,
|
|
quality_filter_policy=None,
|
|
**common_metadata
|
|
)
|
|
|
|
protein_metadata.evidence.update(common_evidence)
|
|
protein_metadata.set_evidence("semantic_contract", EvidenceType.DRAFT_DERIVED)
|
|
protein_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
|
protein_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED) # from resolver: " g" suffix
|
|
protein_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
|
protein_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
|
protein_metadata.set_evidence("known_limitations", EvidenceType.DRAFT_DERIVED)
|
|
|
|
register_placeholder(protein_metadata)
|
|
|
|
# ── carb_avg ──────────────────────────────────────────────────────────────
|
|
|
|
carb_metadata = PlaceholderMetadata(
|
|
key="carb_avg",
|
|
description="Durchschn. Kohlenhydrate in g (30d)",
|
|
semantic_contract=(
|
|
"Liefert den Durchschnitt der dokumentierten täglichen Kohlenhydratzufuhr "
|
|
"über das definierte Auswertungsfenster."
|
|
),
|
|
business_meaning="Relevanter Makroindikator für Leistungs-, Energie- und Belastungskontext",
|
|
unit="g/day",
|
|
format_hint="Ganzzahl in g/day",
|
|
example_output="210",
|
|
known_limitations=(
|
|
"allein selten aussagekräftig; meist im Kontext von Ziel, Energie und "
|
|
"Belastung relevant"
|
|
),
|
|
layer_2b_reuse_possible=None,
|
|
issue_53_alignment="Layer separation established",
|
|
minimum_data_requirements=None,
|
|
quality_filter_policy=None,
|
|
**common_metadata
|
|
)
|
|
|
|
carb_metadata.evidence.update(common_evidence)
|
|
carb_metadata.set_evidence("semantic_contract", EvidenceType.DRAFT_DERIVED)
|
|
carb_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
|
carb_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
|
|
carb_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
|
carb_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
|
carb_metadata.set_evidence("known_limitations", EvidenceType.DRAFT_DERIVED)
|
|
|
|
register_placeholder(carb_metadata)
|
|
|
|
# ── fat_avg ───────────────────────────────────────────────────────────────
|
|
|
|
fat_metadata = PlaceholderMetadata(
|
|
key="fat_avg",
|
|
description="Durchschn. Fett in g (30d)",
|
|
semantic_contract=(
|
|
"Liefert den Durchschnitt der dokumentierten täglichen Fettzufuhr "
|
|
"über das definierte Auswertungsfenster."
|
|
),
|
|
business_meaning="Relevanter Makroindikator für Ernährungsstruktur und Zielpassung",
|
|
unit="g/day",
|
|
format_hint="Ganzzahl in g/day",
|
|
example_output="72",
|
|
known_limitations="meist im Gesamtkontext der Makroverteilung relevant",
|
|
layer_2b_reuse_possible=None,
|
|
issue_53_alignment="Layer separation established",
|
|
minimum_data_requirements=None,
|
|
quality_filter_policy=None,
|
|
**common_metadata
|
|
)
|
|
|
|
fat_metadata.evidence.update(common_evidence)
|
|
fat_metadata.set_evidence("semantic_contract", EvidenceType.DRAFT_DERIVED)
|
|
fat_metadata.set_evidence("business_meaning", EvidenceType.DRAFT_DERIVED)
|
|
fat_metadata.set_evidence("unit", EvidenceType.CODE_DERIVED)
|
|
fat_metadata.set_evidence("format_hint", EvidenceType.CODE_DERIVED)
|
|
fat_metadata.set_evidence("example_output", EvidenceType.CODE_DERIVED)
|
|
fat_metadata.set_evidence("known_limitations", EvidenceType.DRAFT_DERIVED)
|
|
|
|
register_placeholder(fat_metadata)
|
|
|
|
|
|
# Auto-register on import
|
|
register_nutrition_part_a()
|