#55 — Complexity rating on recipe cards:
- Derived from direction text via _classify_method_complexity()
- Badge displayed on every card: easy (green), moderate (amber), involved (red)
- Filterable via complexity filter chips in the results bar
#58 — Cooking time + difficulty as filter domains:
- estimated_time_min derived from step count + complexity
- Time hint (~Nm) shown on every card
- complexity_filter and max_time_min fields in RecipeRequest
- Both applied in the engine before suggestions are built
#53 — Surprise Me: picks a random suggestion from the filtered pool,
avoids repeating the last pick. Shown in a spotlight card.
#57 — Just Pick One: surfaces the top-matched suggestion in the same
spotlight card. One tap to commit to cooking it.
Closes#55, #58, #53, #57
Adds pantry_match_only flag to RecipeRequest. When enabled, any recipe
with one or more missing ingredients (after swaps) is excluded from
results. Swapped ingredients count as covered.
Frontend: toggle checkbox in recipe settings panel, disabled when
shopping mode is active (the two modes are mutually exclusive). Hides
the max-missing input when pantry-match-only is on (irrelevant there).
Closes#63
Hard Day Mode now prioritises results by effort tier before match_count:
Tier 0 (premade): frozen/instant title keywords, or ≤2 ingredients with
heat/microwave-only steps (frozen dinner, heat-and-eat, microwave meal)
Tier 1 (super simple): ≤3 ingredients + any easy method (quesadilla,
cheese toast, scrambled eggs)
Tier 2 (easy/moderate): everything else that passed the 'involved' filter
Assembly templates default to tier 1 (inherently simple). Normal mode sort
is unchanged — match_count only.
Add GroceryLink schema model and grocery_links field to RecipeResult.
Introduce GroceryLinkBuilder service (Amazon Fresh, Walmart, Instacart)
using env-var affiliate tags; no links emitted when tags are absent.
Wire link builder into RecipeEngine.suggest() for levels 1-2.
Add test_grocery_links_free_tier to verify structure contract.
35 tests passing.