- RecipeBrowserPanel: fix onTagSearchInput using '_all' domain slug
(backend validates domain — was silently returning empty results)
- RecipeDetailPanel: fetch and display accepted community category tags
on recipe open; accepted tags shown with accent chip + checkmark,
pending tags shown in muted style
- browserAPI.listRecipeTags() was already in api.ts but not consumed —
now wired into RecipeDetailPanel onMounted as a background fetch
Style classifier (kiwi#27):
- app/services/recipe/style_classifier.py: LLM prompt with curated vocab,
cf-orch/LLMRouter fallback, JSON + regex tag extraction
- POST /recipes/saved/{recipe_id}/classify-style: Paid/BYOK tier gate,
fetches recipe from corpus, returns {suggested_tags:[...]}
- SaveRecipeModal.vue: "Suggest tags" button with loading state; merges
LLM suggestions into existing tags without overwriting user's choices
- 403/empty list silently ignored — button is a no-op when tier not met
Cooked leftovers shelf-life (kiwi#112):
- app/services/leftovers_predictor.py: deterministic FDA/USDA lookup table
with shortest-component-wins for proteins and dish-type override for
assembled dishes; special entries for ceviche (2d, acid != heat),
fermented/cured (kimchi 14d, confit/lardo 7d), soups, rice, pasta, etc.
- POST /recipes/{recipe_id}/leftovers: free tier, no gate
- RecipeDetailPanel.vue: shelf-life section appears after "I cooked this"
with fridge/freeze days, freeze-by advice, per-instance dismiss; calm
framing per no-panic UX policy
- LeftoversResponse Pydantic schema added to recipe.py
- Bump version to 0.6.0 (visual label capture release)
- Remove unused TimeEffortProfile import in RecipeDetailPanel.vue
- Prefix unused value params with _ in SettingsView.vue sensory fns
- Remove cf-orch agent sidecar from compose.override.yml (Sif now has
its own dedicated systemd cf-orch-agent service)
- Cook/Exit toggle button in recipe detail header (hidden for recipes with no steps)
- Cook mode progress bar between header and body showing step N of M
- Single-step view replaces recipe body; shows Active/Wait badge and passive hint
from #50 time_effort data (null-safe — degrades gracefully without it)
- Prev/Next nav buttons; Next becomes green Done on last step
- ArrowLeft/ArrowRight keyboard navigation (preventDefault to suppress scroll)
- Touch swipe left/right (40px horizontal threshold, 80px vertical abort)
- Done triggers handleCook() then exitCookMode() so success banner appears instantly
- Add app/services/recipe/time_effort.py: parse_time_effort(), TimeEffortProfile,
StepAnalysis dataclasses; two-branch regex for time ranges and single values;
whole-word passive keyword detection; 480 min/step cap; 1825 day global cap
- Add directions to browse_recipes and _browse_by_match SELECT queries in store.py
- Enrich browse and detail endpoints with active_min/passive_min/time_effort fields
- Add StepAnalysis, TimeEffortProfile TS interfaces to api.ts
- RecipeBrowserPanel: split pill badge showing active/passive time
- RecipeDetailPanel: collapsible ingredients summary, effort cards (Active/Hands-off/Total),
equipment chips, annotated step list with Active/Wait badges and passive hints
- 45 new tests (40 unit + 5 API); 215 total passing
- Persist built recipes to recipes table on /build so they get real DB IDs
and can be bookmarked via saved_recipes (FK was pointing at negative IDs)
- Populate missing_ingredients in build_from_selection() from role_overrides
vs pantry diff -- backend now owns shopping list computation
- Remove client-side cartItems tracking; shopping list derived from
builtRecipe.missing_ingredients instead
- Fix saved_recipes 422: mount saved_recipes router before recipes router in
routes.py so /recipes/saved isn't captured by /recipes/{recipe_id}
- Bump SaveRecipeModal z-index to 500 (above detail-overlay at 400)
- Replace "Add to pantry" primary action with "Grocery list" clipboard copy;
"Add to pantry" demoted to compact secondary button