From dcdb88595e7a1f695a714a162b214780d9512dfd Mon Sep 17 00:00:00 2001 From: Peter Woolery Date: Sun, 24 May 2026 15:34:16 -0700 Subject: [PATCH] docs: document unit conversion implementation - Update implementation-plan.md: mark unit conversion complete - Update HANDOFF.md: add session notes for 2026-05-24 unit conversion - Update README.md: list Unit Conversion as a feature --- README.md | 1 + docs/HANDOFF.md | 23 +++++++++++++++++++++++ docs/implementation-plan.md | 9 ++++++--- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index af9b1dd..10cb4e4 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ This project was born out of frustration with meal kit services (Blue Apron → - **Web UI**: Modern interface for the whole family - **Learning**: Feedback-based meal recommendations, with weekly auto-discovery of new recipes from external APIs when family preferences are signaled - **Recipe Images**: Scraped from public recipe sites, AI fallback available +- **Unit Conversion**: Converts recipe quantities (cups, tbsp, lb) to grocery units for accurate cost estimates ## Architecture diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index f37f327..4edf65a 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -293,6 +293,29 @@ Trust the tests. Trust the live runs. Don't trust prose claims that something is --- +## New session: 2026-05-24 + +### Unit conversion implementation +Completed implementation of recipe-to-grocery unit conversion to make cost estimates accurate. + +**Files added:** +- `backend/app/utils/units.py` — `UnitConverter` class + - Normalization: maps synonyms to canonical units (e.g. "TBS" → "tbsp", "pounds" → "lb") + - Within-family linear conversion: lb↔oz↔g, cup↔tbsp↔tsp, dozen↔ea + - Cross-family via density tables for ~30 canonical ingredients (e.g. rice cup→lb via 185g/cup / 453.592g/lb) + - Fallback to dimensionless qty when conversion is impossible (preserves monotonic ranking signal) + +**Files modified:** +- `backend/app/services/planner/cost.py` — multiplies `current_price` by `convert_qty(qty, recipe_unit, grocery_unit, ingredient_name)` +- `backend/app/services/planner/generate.py` — `_load_match_index` now joins `Ingredient` table and returns `ingredient_name` + `grocery_unit` for each match +- `backend/app/services/orchestrator/steps.py` — both email cost block and shopping-list total now use unit conversion +- `backend/tests/test_planner_cost.py` — updated fixture to include new fields +- `backend/tests/test_units.py` — 19 tests covering normalization, within-family, density, and fallback + +**Test results:** `test_units.py` 19/19 pass; planner cost/score/select 36 passed. + +--- + ## New session: 2026-05-23 ### Context diff --git a/docs/implementation-plan.md b/docs/implementation-plan.md index e9061a2..7bb71ea 100644 --- a/docs/implementation-plan.md +++ b/docs/implementation-plan.md @@ -178,9 +178,12 @@ Self-hosted meal planning system that integrates with Lucky California grocery s - [ ] Support pasting recipe URL for future scraping ### 5.3 Ingredient Mapping -- [ ] Create ingredient matching service -- [ ] Map recipe ingredients to `ingredient` table entries -- [ ] Handle unit conversions (cups → oz, etc.) +- [x] Create ingredient matching service +- [x] Map recipe ingredients to `ingredient` table entries +- [x] Handle unit conversions (cups → oz, lb → g, etc.) + - Implemented in `app/utils/units.py`: normalization, within-family (weight/volume/count), cross-family via density tables for ~30 canonical ingredients, fallback to dimensionless + - Integrated into `planner/cost.py` for accurate cost calculation + - Orchestrator email and shopping list use converted quantities **Verify**: Can add a recipe manually and retrieve it via API