# Grocery Optimizer Release & Real-Bon UAT v3

Use this reference when releasing or validating the FinanceManager Grocery Optimizer with real Migros receipt data. It captures durable lessons from the v0.3.2 release/UAT and should be applied before any future provider or health-analysis expansion.

## Scope boundaries

- Do not start Health/Histamin/Behçet analysis during Grocery Optimizer stabilization.
- Do not auto-order, login-scrape, mass-scrape, or call providers on page render.
- Do not commit runtime DBs, real receipts, generated reports, product details, prices, API keys, or frontend-embedded secrets.
- Do not quote real product names/prices in chat summaries; report only aggregate counts/statuses unless the user explicitly asks for details.
- Web/provider search must be explicit-click, low-volume, cache-aware, and source-stamped.

## Release sequence

1. Preflight on the accepted feature branch:
   - fetch remote with the repo credential pattern
   - verify branch/head/remote hashes
   - verify working tree clean
   - compare with `main` and probe merge conflicts
   - run compile, full pytest, full frontend tests, build, secret scans, Git-safety, `git diff --check`
2. Back up the runtime DB and perform a restore/readability probe before merge. In this project, the active DB may live under `~/jarvis_runtime/finance-system/data/finance.sqlite3`, not directly under the runtime root.
3. Merge to `main` with `--no-ff`; no force-pushes.
4. Tag only after green gates. If a later UAT hotfix is needed after a tag has been pushed, do **not** force-retag; push a normal follow-up commit on `main` and report that the tag points to the pre-hotfix release commit.
5. Restart backend/frontend from `main`, then verify local and Tailscale health.

## Real-Bon UAT pattern

- Prefer an existing real Migros receipt already normalized into `grocery_product_items`.
- If none exists, create a **runtime-only** UAT subset from `budget_import_line_items`/candidate data:
  - choose one Migros receipt
  - limit to 5–10 products
  - insert into `grocery_product_items` using the grocery receipt helper
  - never write this fixture to Git
- Run provider search only after the explicit action, with bounded products/retailers.
- Perform at least 2–3 review actions (accept/reject/later), but preserve semantics:
  - no-price/no-unit-price matches are `needs_review`, not safe savings
  - accepted no-price candidates should remain reviewable/auditable, not treated as sourced price matches
  - rejected mappings suppress only that exact target match, not all alternatives for the source product
- Generate the shopping list and runtime report; verify the report path is outside the repo.

## Mapping-quality summary shape

For chat/report summaries, aggregate without real prices/product details:

- tested product count
- matches found: yes/no
- retailer counts
- match-type/status counts (`exact_match`, `close_match`, `cheaper_private_label`, `needs_review`)
- price present count
- unit-price present count
- package-size comparable count
- accepted / rejected / needs_review / later counts
- shopping-list store count
- whether report is runtime-only and outside repo

## Provider assessment pattern

Report each provider with these fields:

- live search stable: yes/no
- product detail stable: yes/no
- price parseable: yes/no
- unit price parseable: yes/no
- package size parseable: yes/no
- scraping/ToS risk: low/medium/high
- recommendation: `produktiver Einsatz`, `nur manuell`, or `deaktiviert/Skeleton lassen`

Durable v3 finding: Coop and Migros public search may return reviewable/no-price candidates in real UAT; Denner/Aldi/Lidl/Otto's should remain skeleton/manual-first unless separately proven stable. Treat missing prices as a provider-quality limitation, not as savings.

## UAT-discovered pitfall

Accepting a provider candidate whose quality flags are only `needs_review`/`no_price` must not feed those flags directly into `grocery_product_mappings.match_type`. Normalize its match type to `manual_match` (or another allowed type) and keep status `needs_review` unless there is a true sourced price. Add/regress a test for this edge case.
