← Files Fitness LedgerARCHIVED FILE

skills/nutrition-ledger/scripts/coverage.py

1.87 KB · Sep 30, 2026 · 23:15 UTC

↓ Download file

"""Coverage-aware nutrient aggregation and interpretation."""

from __future__ import annotations

from typing import Any, Iterable, Mapping


_TIER_WEIGHT = {"A": 1.0, "B": 0.9, "C": 0.5, "D": 0.0}


def nutrient_coverage(rows: Iterable[Mapping[str, Any]], nutrient: str) -> dict[str, float | int]:
    """Return item, calorie, and provenance-weighted coverage for a nutrient."""
    records = tuple(row for row in rows if not row.get("deleted_at"))
    if not records:
        return {"items_total": 0, "items_known": 0, "item_weighted": 0.0, "calorie_weighted": 0.0, "confidence_weighted": 0.0}
    known = [row for row in records if row.get(nutrient) is not None]
    item_weighted = len(known) / len(records)
    total_calories = sum(float(row.get("calories") or 0) for row in records)
    known_calories = sum(float(row.get("calories") or 0) for row in known)
    calorie_weighted = known_calories / total_calories if total_calories else item_weighted
    confidence_total = sum(_TIER_WEIGHT.get(str((row.get("nutrient_provenance") or {}).get(nutrient, {}).get("tier", "D")), 0.0) for row in records)
    return {
        "items_total": len(records),
        "items_known": len(known),
        "item_weighted": round(item_weighted, 4),
        "calorie_weighted": round(calorie_weighted, 4),
        "confidence_weighted": round(confidence_total / len(records), 4),
    }


def classify_with_coverage(total: float | None, target: float | None, coverage: Mapping[str, Any], *, minimum_coverage: float = 0.8) -> str:
    """Gate adequacy classifications when too much intake is unknown."""
    if target is None or total is None:
        return "insufficient data"
    if float(coverage.get("calorie_weighted", 0.0)) < minimum_coverage:
        return "insufficient data coverage to assess"
    return "intake appears low" if total < target else "intake appears adequate"

SHA-256: bef4374ab9a0bc0b388b3ae6a05b061b7dc5e11fddc2334febe76a0464dc7388