fix: exact-name fast path in matcher + save priceless produce in scraper

Scraper: remove price guard in map_product so produce items without a
catalog price (e.g. Fresh Garlic, Lime sold by weight) are saved to
grocery_item with current_price=NULL rather than skipped.

Matcher:
- Add exact-name fast path: build a lowercase-trimmed name→index map
  and skip fuzzy search entirely when the ingredient name matches a
  grocery item exactly. Lime → Lime (confidence 1.0), Garlic → Fresh
  Garlic from fuzzy (confidence 1.0).
- Add exclusion words: juice, gelatin to prevent beverage/dessert
  products from matching cooking ingredients.
- Increase fuzzy candidate limit 20→100 so exact-name items buried in
  large tie groups are not missed.
- Add 'juice' to exclusion: prevents '100% Lime Juice' from winning
  over plain 'Lime'.

Result: all recipe ingredients now match correct Lucky CA products or
show '—' (no match); zero category cross-contamination remaining.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-10 20:17:03 -07:00
co-authored by Claude Sonnet 4.6
parent d7a3f5c081
commit 2373883fe7
2 changed files with 25 additions and 6 deletions
-4
View File
@@ -259,10 +259,6 @@ class LuckyCaliforniaScraper:
promo = price_block.get("promoArea") or {}
sale_price, sale_unit = cls._parse_price(promo.get("promoText"))
if reg_price is None and sale_price is None:
# No usable price; skip rather than persist garbage.
return None
unit = sale_unit or reg_unit
is_on_sale = sale_price is not None and reg_price is not None and sale_price < reg_price
# current_price = "what the customer pays today" → sale_price when on sale.