feat: Update placeholder metadata and nutrition metrics
- 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.
This commit is contained in:
parent
2ea5f905c4
commit
052ba195cc
|
|
@ -92,16 +92,10 @@ registry = get_registry()
|
|||
|
||||
**Package:** `backend/placeholder_registrations/`
|
||||
|
||||
**Struktur:**
|
||||
```
|
||||
placeholder_registrations/
|
||||
├── __init__.py # Auto-Import aller Registrations
|
||||
├── nutrition_part_a.py # Nutrition Basis-Metriken (4 Placeholder)
|
||||
├── nutrition_part_b.py # Protein-Ziele (5 Placeholder) - TODO
|
||||
├── body_metrics.py # Körper-Metriken - TODO
|
||||
├── activity_metrics.py # Aktivitäts-Metriken - TODO
|
||||
└── ... # Weitere Cluster
|
||||
```
|
||||
**Struktur:** Vollständige Cluster-Module (u. a. Ernährung, Körper, Aktivität, Schlaf,
|
||||
Vitalwerte, Profil/Zeitraum, Phase-0b-Ziele, Korrelationen); siehe `__init__.py` für die
|
||||
Import-Liste. **Anzahl:** 114 Platzhalter, identisch zu `PLACEHOLDER_MAP` in
|
||||
`placeholder_resolver.py`.
|
||||
|
||||
**Auto-Registration:**
|
||||
- Import des Package triggert automatische Registrierung aller Placeholder
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
## Gesamt-Übersicht
|
||||
|
||||
**Aktuelle Platzhalter:** 116
|
||||
**Aktuelle Platzhalter:** 114 (PLACEHOLDER_MAP / Registry)
|
||||
**Nach Phase 0c Migration:**
|
||||
- ✅ **Bleiben einfach (kein Data Layer):** 8 Platzhalter
|
||||
- 🔄 **Gehen zu Data Layer:** 108 Platzhalter
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ frontend/src/
|
|||
|
||||
### Updates (11.04.2026 - Placeholder Phase A)
|
||||
|
||||
- **`main.py`:** `import placeholder_registrations` beim Start, damit die Registry (48 Keys) und `get_placeholder_catalog()` ohne vorherigen Export-Request konsistent sind.
|
||||
- **`main.py`:** `import placeholder_registrations` beim Start, damit die Registry (**114 Keys**, deckungsgleich `PLACEHOLDER_MAP`) und `get_placeholder_catalog()` ohne vorherigen Export-Request konsistent sind.
|
||||
- **`placeholder_resolver.py`:** `{{top_goal_progress_pct}}` nutzt `_safe_int` statt `_safe_str` (Verdrahtung zu `scores.get_top_priority_goal` korrigiert).
|
||||
|
||||
### Updates (11.04.2026 - Gitea #75, nutrition_score Registry)
|
||||
|
|
@ -115,10 +115,11 @@ frontend/src/
|
|||
- **Gitea #75** (offen): Zucker/Ballaststoffe/Lebensmittelqualität, automatisches Lebensmittelprofil, später Mahlzeiten-Timing/Abgleich mit Training — http://192.168.2.144:3000/Lars/mitai-jinkendo/issues/75
|
||||
- **`nutrition_score`:** Registry in `backend/placeholder_registrations/nutrition_score.py`, Import in `placeholder_registrations/__init__.py`; Legacy-Duplikat unter „Scores“ im Platzhalter-Katalog entfernt.
|
||||
|
||||
### Updates (11.04.2026 - Ernährung: eine TDEE-/Tageslogik)
|
||||
### Updates (11.04.2026 - Ernährung: TDEE, Bilanz, Kalorien-Score)
|
||||
|
||||
- **`data_layer/nutrition_metrics.py`:** TDEE für Bilanz = **aktuelles Gewicht × 32,5 kcal/kg** (`estimate_tdee_kcal_from_latest_weight`); `get_energy_balance_data` und `calculate_energy_balance_7d` nutzen **tägliche kcal-Summen** (nicht Rohzeilen). Makro-Durchschnitte über **Tagesmittel**; `protein_adequacy_28d`, `macro_consistency_score`, `get_protein_adequacy_data`, `get_macro_consistency_data` auf **Kalendertag** umgestellt. Entfernt: festes **2500 kcal** in `get_energy_balance_data`.
|
||||
- **`data_layer/nutrition_metrics.py`:** TDEE für Bilanz: primär **Mifflin–St Jeor BMR × PAL 1,55**, wenn Profil (Größe, Geschlecht, DOB) und Gewicht vorhanden; sonst Fallback **kg × 32,5** (`estimate_tdee_kcal_from_latest_weight`). `get_energy_balance_data` / `calculate_energy_balance_7d` nutzen **tägliche kcal-Summen**. **`_score_calorie_adherence`** (Komponente von `calculate_nutrition_score`) wertet die 7-Tage-Bilanz nach **`profiles.goal_mode`** aus (weight_loss vs. strength/recomposition vs. maintenance/health/endurance).
|
||||
- **`routers/charts.py`:** `/charts/energy-balance` und Protein-Timeline nutzen dieselbe TDEE-/Tageslogik; ohne `weight_log` liefert Energiebilanz-Chart eine klare Fehlermeldung. Adherence-Endpoint: Kcal-CV über **Tages-Summen**.
|
||||
- **Doku:** Normative Platzhalter-Zahl **114** (`docs/PLACEHOLDER_*.md`); `placeholder_metadata_complete.py` als **Legacy** gekennzeichnet — maßgeblich `placeholder_registrations/` + `PLACEHOLDER_REGISTRY_FRAMEWORK.md`.
|
||||
|
||||
### GUI / Informationsarchitektur (Abnahme dieser Iteration, 2026-04-05)
|
||||
|
||||
|
|
|
|||
|
|
@ -25,14 +25,43 @@ from datetime import datetime, timedelta, date
|
|||
from db import get_db, get_cursor, r2d
|
||||
from data_layer.utils import calculate_confidence, safe_float, safe_int
|
||||
|
||||
# Single TDEE rule for placeholders, charts, and warnings (kcal/day = kg * factor).
|
||||
# Replaces legacy fixed 2500 kcal so all consumers stay aligned.
|
||||
# Fallback TDEE (kcal/day) when demographics for Mifflin–St Jeor are incomplete.
|
||||
TDEE_KCAL_PER_KG_BODYWEIGHT = 32.5
|
||||
# PAL applied to MSJ BMR when height, sex, dob and weight are available (moderate activity).
|
||||
TDEE_PAL_MODERATE = 1.55
|
||||
|
||||
|
||||
def _age_years_from_dob(dob) -> Optional[int]:
|
||||
if dob is None:
|
||||
return None
|
||||
try:
|
||||
if isinstance(dob, str):
|
||||
birth = datetime.strptime(dob[:10], "%Y-%m-%d").date()
|
||||
else:
|
||||
birth = dob
|
||||
today = date.today()
|
||||
return today.year - birth.year - ((today.month, today.day) < (birth.month, birth.day))
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _mifflin_st_jeor_bmr_kcal(
|
||||
weight_kg: float, height_cm: float, age_years: int, sex_is_male: bool
|
||||
) -> float:
|
||||
if sex_is_male:
|
||||
return 10.0 * weight_kg + 6.25 * height_cm - 5.0 * age_years + 5.0
|
||||
return 10.0 * weight_kg + 6.25 * height_cm - 5.0 * age_years - 161.0
|
||||
|
||||
|
||||
def estimate_tdee_kcal_from_latest_weight(profile_id: str) -> Optional[float]:
|
||||
"""
|
||||
Estimated TDEE (kcal/day) from latest body weight.
|
||||
Estimated TDEE (kcal/day).
|
||||
|
||||
Primary: Mifflin–St Jeor BMR × TDEE_PAL_MODERATE when latest weight plus
|
||||
profiles.height, profiles.sex, profiles.dob are usable.
|
||||
|
||||
Fallback: latest weight (kg) × TDEE_KCAL_PER_KG_BODYWEIGHT (legacy heuristic).
|
||||
|
||||
Returns None if no weight on record.
|
||||
"""
|
||||
with get_db() as conn:
|
||||
|
|
@ -42,10 +71,41 @@ def estimate_tdee_kcal_from_latest_weight(profile_id: str) -> Optional[float]:
|
|||
WHERE profile_id=%s ORDER BY date DESC LIMIT 1""",
|
||||
(profile_id,),
|
||||
)
|
||||
row = cur.fetchone()
|
||||
if not row or row["weight"] is None:
|
||||
wrow = cur.fetchone()
|
||||
if not wrow or wrow["weight"] is None:
|
||||
return None
|
||||
return float(row["weight"]) * TDEE_KCAL_PER_KG_BODYWEIGHT
|
||||
weight_kg = float(wrow["weight"])
|
||||
|
||||
cur.execute(
|
||||
"SELECT height, sex, dob FROM profiles WHERE id=%s",
|
||||
(profile_id,),
|
||||
)
|
||||
prow = cur.fetchone()
|
||||
|
||||
if prow and prow.get("height") and prow.get("sex") is not None and prow.get("dob"):
|
||||
height_cm = float(prow["height"])
|
||||
age = _age_years_from_dob(prow["dob"])
|
||||
if age is not None and 10 < age < 120 and height_cm > 50:
|
||||
sex_raw = str(prow["sex"]).strip().lower()
|
||||
sex_is_male = sex_raw in ("m", "male", "männlich", "mann")
|
||||
bmr = _mifflin_st_jeor_bmr_kcal(weight_kg, height_cm, age, sex_is_male)
|
||||
if bmr > 400:
|
||||
return bmr * TDEE_PAL_MODERATE
|
||||
|
||||
return weight_kg * TDEE_KCAL_PER_KG_BODYWEIGHT
|
||||
|
||||
|
||||
def _get_profile_goal_mode(profile_id: str) -> str:
|
||||
"""Strategic goal_mode from profiles (Phase 0a); defaults to health."""
|
||||
with get_db() as conn:
|
||||
cur = get_cursor(conn)
|
||||
cur.execute("SELECT goal_mode FROM profiles WHERE id=%s", (profile_id,))
|
||||
row = cur.fetchone()
|
||||
if row and row.get("goal_mode"):
|
||||
g = str(row["goal_mode"]).strip().lower()
|
||||
if g:
|
||||
return g
|
||||
return "health"
|
||||
|
||||
|
||||
def get_nutrition_average_data(
|
||||
|
|
@ -224,7 +284,7 @@ def get_energy_balance_data(
|
|||
Energy balance (intake - estimated expenditure), kcal/day.
|
||||
|
||||
Intake: mean of daily total kcal (sum per calendar day).
|
||||
TDEE: latest weight (kg) * TDEE_KCAL_PER_KG_BODYWEIGHT (same rule as placeholders).
|
||||
TDEE: estimate_tdee_kcal_from_latest_weight (MSJ × PAL oder kg-Fallback).
|
||||
"""
|
||||
with get_db() as conn:
|
||||
cur = get_cursor(conn)
|
||||
|
|
@ -834,32 +894,58 @@ def calculate_nutrition_score(profile_id: str, focus_weights: Optional[Dict] = N
|
|||
|
||||
|
||||
def _score_calorie_adherence(profile_id: str) -> Optional[int]:
|
||||
"""Score calorie target adherence (0-100)"""
|
||||
# Check for energy balance goal
|
||||
# For now, use energy balance calculation
|
||||
"""Score calorie target adherence (0–100) using 7d balance vs profiles.goal_mode."""
|
||||
balance = calculate_energy_balance_7d(profile_id)
|
||||
|
||||
if balance is None:
|
||||
return None
|
||||
|
||||
# Score based on whether deficit/surplus aligns with goal
|
||||
# Simplified: assume weight loss goal = deficit is good
|
||||
# TODO: Check actual goal type
|
||||
mode = _get_profile_goal_mode(profile_id)
|
||||
b = float(balance)
|
||||
|
||||
abs_balance = abs(balance)
|
||||
|
||||
# Moderate deficit/surplus = good
|
||||
if 200 <= abs_balance <= 500:
|
||||
def _weight_loss(x: float) -> int:
|
||||
if -550 <= x <= -250:
|
||||
return 100
|
||||
elif 100 <= abs_balance <= 700:
|
||||
return 85
|
||||
elif abs_balance <= 900:
|
||||
if x > 450:
|
||||
return 38
|
||||
if -750 <= x < -550 or -250 < x <= 120:
|
||||
return 82
|
||||
if x < -1200:
|
||||
return 52
|
||||
if -950 <= x < -750 or 120 < x <= 350:
|
||||
return 68
|
||||
return 58
|
||||
|
||||
def _surplus_friendly(x: float) -> int:
|
||||
if 80 <= x <= 480:
|
||||
return 100
|
||||
if -120 <= x < 80 or 480 < x <= 700:
|
||||
return 86
|
||||
if -380 <= x < -120:
|
||||
return 68
|
||||
if x > 850:
|
||||
return 54
|
||||
if x < -650:
|
||||
return 44
|
||||
return 72
|
||||
|
||||
def _maintenance(x: float) -> int:
|
||||
a = abs(x)
|
||||
if a <= 200:
|
||||
return 100
|
||||
if a <= 400:
|
||||
return 84
|
||||
if a <= 650:
|
||||
return 70
|
||||
elif abs_balance <= 1200:
|
||||
if a <= 900:
|
||||
return 55
|
||||
else:
|
||||
return 40
|
||||
|
||||
if mode == "weight_loss":
|
||||
return _weight_loss(b)
|
||||
if mode in ("strength", "recomposition"):
|
||||
return _surplus_friendly(b)
|
||||
return _maintenance(b)
|
||||
|
||||
|
||||
def _score_macro_balance(profile_id: str) -> Optional[int]:
|
||||
"""Score macro balance (0-100)"""
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
"""
|
||||
Complete Placeholder Metadata Definitions
|
||||
Complete Placeholder Metadata Definitions (Legacy / Normativ v1)
|
||||
|
||||
This module contains manually curated, complete metadata for all 116 placeholders.
|
||||
It combines automatic extraction with manual annotation to ensure 100% normative compliance.
|
||||
|
||||
IMPORTANT: This is the authoritative source for placeholder metadata.
|
||||
All new placeholders MUST be added here with complete metadata.
|
||||
Hinweis (2026-04): **Verbindliche Metadaten-Pflege** erfolgt über
|
||||
`backend/placeholder_registrations/` + `placeholder_registry.py` (114 Keys, deckungsgleich
|
||||
mit `PLACEHOLDER_MAP`). Dieses Modul bleibt für ältere Generator-/Export-Pfade und
|
||||
Tests; neue Platzhalter hier nicht mehr duplizieren.
|
||||
"""
|
||||
from placeholder_metadata import (
|
||||
PlaceholderMetadata,
|
||||
|
|
@ -28,7 +27,7 @@ from typing import List
|
|||
|
||||
def get_all_placeholder_metadata() -> List[PlaceholderMetadata]:
|
||||
"""
|
||||
Returns complete metadata for all 116 placeholders.
|
||||
Returns complete metadata for all 114 placeholders (Registry ist maßgeblich).
|
||||
|
||||
This is the authoritative, manually curated source.
|
||||
"""
|
||||
|
|
@ -476,7 +475,7 @@ def get_all_placeholder_metadata() -> List[PlaceholderMetadata]:
|
|||
notes=["Quadrant-Logik basiert auf FM/LBM Delta-Vorzeichen"],
|
||||
),
|
||||
|
||||
# NOTE: Continuing with all 116 placeholders would make this file very long.
|
||||
# NOTE: Continuing with all 114 placeholders would make this file very long.
|
||||
# For brevity, I'll create a separate generator that fills all remaining placeholders.
|
||||
# The pattern is established above - each placeholder gets full metadata.
|
||||
]
|
||||
|
|
|
|||
|
|
@ -53,6 +53,13 @@ def register_nutrition_part_a():
|
|||
"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",
|
||||
"minimum_data_requirements": (
|
||||
"Mind. ein Kalendertag mit nutrition_log im Fenster; Mittelwerte aus täglicher Aggregation. "
|
||||
"Confidence über calculate_confidence(day_count, days) in get_nutrition_average_data."
|
||||
),
|
||||
"quality_filter_policy": (
|
||||
"Kein Outlier-Filter auf Tagesaggregaten; leere Tage fehlen in der Aggregation (kein Imputing)."
|
||||
),
|
||||
}
|
||||
|
||||
# Common evidence for shared fields
|
||||
|
|
@ -73,8 +80,8 @@ def register_nutrition_part_a():
|
|||
"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
|
||||
"minimum_data_requirements": EvidenceType.CODE_DERIVED,
|
||||
"quality_filter_policy": EvidenceType.CODE_DERIVED,
|
||||
}
|
||||
|
||||
# ── kcal_avg ──────────────────────────────────────────────────────────────
|
||||
|
|
@ -94,8 +101,6 @@ def register_nutrition_part_a():
|
|||
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
|
||||
)
|
||||
|
||||
|
|
@ -131,8 +136,6 @@ def register_nutrition_part_a():
|
|||
),
|
||||
layer_2b_reuse_possible=None,
|
||||
issue_53_alignment="Layer separation established",
|
||||
minimum_data_requirements=None,
|
||||
quality_filter_policy=None,
|
||||
**common_metadata
|
||||
)
|
||||
|
||||
|
|
@ -165,8 +168,6 @@ def register_nutrition_part_a():
|
|||
),
|
||||
layer_2b_reuse_possible=None,
|
||||
issue_53_alignment="Layer separation established",
|
||||
minimum_data_requirements=None,
|
||||
quality_filter_policy=None,
|
||||
**common_metadata
|
||||
)
|
||||
|
||||
|
|
@ -196,8 +197,6 @@ def register_nutrition_part_a():
|
|||
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
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ energy_balance_metadata = PlaceholderMetadata(
|
|||
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"],
|
||||
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.",
|
||||
|
|
@ -127,11 +127,14 @@ energy_balance_metadata = PlaceholderMetadata(
|
|||
|
||||
# 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).",
|
||||
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. "
|
||||
"TDEE-Modell ist vereinfacht → inherent uncertainty."
|
||||
"PAL=1.55 ist ein Festwert (moderate Aktivität), kein individuelles Aktivitätslogging."
|
||||
),
|
||||
missing_value_policy=MissingValuePolicy(
|
||||
available=False,
|
||||
|
|
@ -140,11 +143,10 @@ energy_balance_metadata = PlaceholderMetadata(
|
|||
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."
|
||||
"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
|
||||
|
|
|
|||
|
|
@ -60,8 +60,9 @@ nutrition_score_metadata = PlaceholderMetadata(
|
|||
),
|
||||
known_limitations=(
|
||||
"Abhängig von user_focus_area_weights; ohne Ernährungs-Fokus liefert die "
|
||||
"Funktion None. Kalorien-Adhärenz nutzt vereinfachte Heuristik (goal_type-TODO). "
|
||||
"_score_macro_balance nutzt noch zeilenbasierte 28d-Abfrage (langfristig an "
|
||||
"Funktion None. Kalorien-Adhärenz nutzt 7d-Energiebilanz vs. profiles.goal_mode "
|
||||
"(weight_loss / strength+recomposition / sonst maintenance). "
|
||||
"_score_macro_balance nutzt zeilenbasierte 28d-Abfrage (langfristig an "
|
||||
"Tagesaggregation angleichen)."
|
||||
),
|
||||
layer_1_decision="Data Layer (nutrition_metrics.calculate_nutrition_score)",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ This document establishes **mandatory governance rules** for placeholder managem
|
|||
## 2. Scope
|
||||
|
||||
These guidelines apply to:
|
||||
- All 116 existing placeholders
|
||||
- All 114 existing placeholders (canonical: `PLACEHOLDER_MAP`)
|
||||
- All new placeholders
|
||||
- All modifications to existing placeholders
|
||||
- All placeholder deprecations
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ curl -s -H "X-Auth-Token: $TOKEN" \
|
|||
**Expected response:**
|
||||
```json
|
||||
{
|
||||
"total_placeholders": 116,
|
||||
"total_placeholders": 114,
|
||||
"available": 98,
|
||||
"missing": 18,
|
||||
"by_type": {
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@
|
|||
|
||||
## Executive Summary
|
||||
|
||||
This document summarizes the complete implementation of the normative placeholder metadata system for Mitai Jinkendo. The system provides a comprehensive, standardized framework for managing, documenting, and validating all 116 placeholders in the system.
|
||||
This document summarizes the complete implementation of the normative placeholder metadata system for Mitai Jinkendo. The system provides a comprehensive, standardized framework for managing, documenting, and validating all 114 placeholders in the system.
|
||||
|
||||
**Key Achievements:**
|
||||
- ✅ Complete metadata schema (normative compliant)
|
||||
- ✅ Automatic metadata extraction
|
||||
- ✅ Manual curation for 116 placeholders
|
||||
- ✅ Manual curation for 114 placeholders
|
||||
- ✅ Extended export API (non-breaking)
|
||||
- ✅ Catalog generator (4 documentation files)
|
||||
- ✅ Validation & testing framework
|
||||
|
|
@ -75,7 +75,7 @@ This document summarizes the complete implementation of the normative placeholde
|
|||
|
||||
### 1.3 Complete Metadata Definitions
|
||||
|
||||
#### `backend/placeholder_metadata_complete.py` (220 lines, expandable to all 116)
|
||||
#### `backend/placeholder_metadata_complete.py` (220 lines, expandable to all 114)
|
||||
|
||||
**Purpose:** Manually curated, authoritative metadata for all placeholders
|
||||
|
||||
|
|
@ -106,7 +106,7 @@ PlaceholderMetadata(
|
|||
|
||||
**Key Features:**
|
||||
- Hand-curated for accuracy
|
||||
- Complete for all 116 placeholders
|
||||
- Complete for all 114 placeholders
|
||||
- Serves as authoritative source
|
||||
- Normative compliant
|
||||
|
||||
|
|
@ -285,7 +285,7 @@ pytest backend/tests/test_placeholder_metadata.py -v
|
|||
v
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Complete Registry │
|
||||
│ (116 placeholders with full metadata) │
|
||||
│ (114 placeholders with full metadata) │
|
||||
└──────────┬──────────────────────────────────────────────────┘
|
||||
│
|
||||
├──> Generation Scripts (generate_*.py)
|
||||
|
|
@ -309,7 +309,7 @@ pytest backend/tests/test_placeholder_metadata.py -v
|
|||
### 3.1 Metadata Extraction Flow
|
||||
|
||||
```
|
||||
1. PLACEHOLDER_MAP (116 entries)
|
||||
1. PLACEHOLDER_MAP (114 entries)
|
||||
└─> extract_resolver_name()
|
||||
└─> analyze_data_layer_usage()
|
||||
└─> infer_type/time_window/output_type()
|
||||
|
|
@ -468,7 +468,7 @@ curl -H "X-Auth-Token: <token>" \
|
|||
|
||||
# Output:
|
||||
{
|
||||
"total_placeholders": 116,
|
||||
"total_placeholders": 114,
|
||||
"available": 98,
|
||||
"missing": 18,
|
||||
"by_type": {
|
||||
|
|
@ -599,7 +599,7 @@ The system is designed for extensibility:
|
|||
## 8. Compliance Checklist
|
||||
|
||||
✅ **Normative Standard Compliance:**
|
||||
- All 116 placeholders inventoried
|
||||
- All 114 placeholders inventoried
|
||||
- Complete metadata schema implemented
|
||||
- Validation framework in place
|
||||
- Non-breaking export API
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user