- Add exclusion words: soda, rotisserie, tuna/tonno/salmon/sardine/anchovy
to prevent beverages, prepared poultry, and seafood-in-oil from matching
raw cooking ingredients
- Add min precision floor (0.45): grocery sig-word count must be ≤ 2× the
ingredient's sig-word count, catching long branded products that pass
the word-overlap recall check but are clearly wrong category matches
(e.g. "Garlic Herb Rotisserie Chicken" precision=0.25 now rejected)
Result: all previously wrong matches now show '—' (no match) rather than
a wrong product; correct matches unchanged
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Flip matching direction: iterate ingredients, search grocery items
(previously: iterate grocery items → false positives from partial word
overlap, e.g. Pampers Wipes matched Ginger Fresh via the word "Fresh")
- Score = partial_token_sort_ratio × (ingredient_sig / grocery_sig_words)
— precision term penalises long branded products where the ingredient
word appears incidentally ("Vermicelli, Garlic & Olive Oil" now scores
lower than a pure olive oil SKU)
- 100% recall guard: every significant ingredient word must appear in the
grocery name (eliminates cross-category noise completely)
- Stop-word list strips generic qualifiers so "boneless skinless" in an
ingredient name doesn't block "Chicken Thighs Boneless" in the grocery
- ON CONFLICT DO NOTHING preserves manual matches on re-run
Benchmark on today's Lucky CA weekly ad (10,965 items):
Before: ~25% correct (Pampers→Ginger, Red Wine→Bell Pepper, etc.)
After: ~80% correct; remaining misses are data gaps (Lucky has no
standalone garlic or olive oil in this week's ad)
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>