Files
Meal-Planner/backend/app/services/planner/config.py
T
adminandClaude Sonnet 4.6 35f736a052 fix(planner): correct set_size to 3 dinners and switch cost filter to per-serving
- set_size 21→3, top_k 20→10: generate 3 weekly dinners not full 3×7 matrix
- All 3 items assigned MealType.DINNER on Mon/Wed/Fri
- RecipeCost gains servings field + cost_per_serving property
- compute_recipe_cost accepts servings param (default 4)
- filter.py gates on cost_per_serving instead of total_cost
- max_meal_cost 500→50 (now a meaningful $/serving threshold)
- Email displays ~$X/serving instead of inflated raw total
- select_set: candidate_pool uses max(top_k, set_size) to prevent
  combinations(n<set_size) returning empty iterator

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 07:20:17 -07:00

43 lines
1.6 KiB
Python

"""Planner constants. Tune here without touching algorithm code."""
from __future__ import annotations
from dataclasses import dataclass
@dataclass(frozen=True)
class PlannerConfig:
# Hard constraints
recency_weeks: int = 4 # constraint #3: no repeat within N weeks
calorie_tolerance_pct: int = 20 # constraint #4: ±X% of family.calorie_target
max_total_minutes: int = 45 # constraint #5: prep + cook
max_meal_cost: float = 50.00 # constraint #6: dollars per serving (dimensionless proxy — unit conversion not yet implemented)
# Scoring weights (must sum to 1.0)
w_savings: float = 0.30
w_coverage: float = 0.25
w_pantry: float = 0.10
w_time: float = 0.15
w_recency: float = 0.20
# Time bonus boundaries
time_ideal_minutes: int = 25 # full bonus at <= this
time_full_minutes: int = 45 # zero bonus at this; matches max_total_minutes
# Recency bonus boundary
recency_full_weeks: int = 12 # full bonus when last cooked >= this many weeks ago
# Set selection
top_k: int = 10 # how many feasible recipes to enumerate over
set_size: int = 3 # 3 dinners/week
p_protein: float = 0.15 # diversity penalty per shared-protein pair
p_cuisine: float = 0.10 # diversity penalty per shared-cuisine pair
def validate(self) -> None:
total = self.w_savings + self.w_coverage + self.w_pantry + self.w_time + self.w_recency
if abs(total - 1.0) > 1e-6:
raise ValueError(f"weights must sum to 1.0, got {total}")
DEFAULT = PlannerConfig()
DEFAULT.validate()