- SKILL.md: add egg-limit hard rule (max 4/meal, one egg-meal/day), cuisine-rotation section - scripts/pick_cuisine.py: seeded weekly world-cuisine picker (stable per week, no recent repeats) - scripts/verify_eggs.py: regression guard for the egg cap - README.md: full project documentation - .gitignore: exclude cuisine-rotation.json + python caches (live data stays local)
69 lines
2.3 KiB
Python
69 lines
2.3 KiB
Python
#!/usr/bin/env python3
|
|
"""Regression guard for the EGG LIMIT hard rule.
|
|
|
|
Run after any change to meal-history.json, inventory.json, or the daily job,
|
|
and before sending a regenerated day's email:
|
|
|
|
python3 scripts/verify_eggs.py
|
|
|
|
Checks the EGG LIMIT contract against the persisted rules in inventory.json:
|
|
- No single meal may exceed diet.egg_rules.max_per_meal (default 4).
|
|
- No day may have more than diet.egg_rules.max_meals_per_day_with_eggs
|
|
(default 1) meals containing eggs — i.e. the other meal must be egg-free.
|
|
|
|
Exits non-zero on violation so it can gate a send or a CI-style check.
|
|
"""
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
SKILL_DIR = os.path.dirname(HERE)
|
|
|
|
|
|
def load(name):
|
|
with open(os.path.join(SKILL_DIR, name)) as f:
|
|
return json.load(f)
|
|
|
|
|
|
def main():
|
|
inv = load("inventory.json")
|
|
hist = load("meal-history.json")
|
|
|
|
rules = inv.get("diet", {}).get("egg_rules", {})
|
|
max_per_meal = rules.get("max_per_meal", 4)
|
|
max_egg_meals = rules.get("max_meals_per_day_with_eggs", 1)
|
|
|
|
violations = []
|
|
by_date = {}
|
|
for e in hist.get("entries", []):
|
|
eggs = next((i["qty"] for i in e["items"] if i["name"].lower() == "eggs"), 0)
|
|
by_date.setdefault(e["date"], []).append((e["meal"], e.get("name", ""), eggs))
|
|
|
|
for date, meals in by_date.items():
|
|
for meal, name, eggs in meals:
|
|
if eggs > max_per_meal:
|
|
violations.append(
|
|
f"{date} {meal} ('{name}'): {eggs} eggs > max {max_per_meal}/meal")
|
|
egg_meal_count = sum(1 for _, _, eggs in meals if eggs > 0)
|
|
if egg_meal_count > max_egg_meals:
|
|
violations.append(
|
|
f"{date}: {egg_meal_count} egg-containing meals > max {max_egg_meals}/day "
|
|
f"(other meal must be egg-free)")
|
|
|
|
# Also confirm the inventory metadata carries the cap.
|
|
if not rules:
|
|
violations.append("inventory.json missing diet.egg_rules — egg cap not enforced at the data level")
|
|
|
|
if violations:
|
|
print("FAIL: egg-limit violations found:")
|
|
for v in violations:
|
|
print(f" - {v}")
|
|
sys.exit(1)
|
|
print(f"PASS: egg limit OK (max {max_per_meal}/meal, max {max_egg_meals} egg-meal/day) "
|
|
f"across {len(by_date)} day(s).")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|