feat: per-portion nutrition and ratings through the shared views #22

Merged
TimCane merged 9 commits from feat/nutrition-ratings-views into main 2026-07-20 19:09:48 +01:00
TimCane commented 2026-07-20 18:36:56 +01:00 (Migrated from github.com)

Summary

  • v_recipe gains the nine-nutrient per-portion panel, ratings, serving size and website url; search_text gains ingredient names so free text finds recipes by what is in them
  • gousto stores seo.canonical as the website url - the plan's slug reconstruction guessed wrong (the path carries a category segment), so per the plan's contingency it is stored, with a migration that queues a re-normalise
  • Page replaces SearchResult; summaries carry the panel so agents pick recipes on macros without N get_recipe calls
  • search_recipes: nutrientFilters (whitelist enum-to-column map), minRating, sort name|rating|kcal|seeded random; maxKcal removed
  • get_recipe distinguishes unknown id from a wrong portion count, failing with the offered counts; detail adds offeredPortions, updatedAt, servingSizeGrams, websiteUrl
  • every tool is annotated read-only/idempotent/closed-world with structured output; server instructions ship at initialize
  • performance gate failed by an order of magnitude (live laterals cost seconds at ~75k rows), so v_recipe is materialized per the designed fallback: stored tsvector + GIN (~35ms full text), GiST trigram for the typo pass (now a fallback query, not an OR arm), refreshed at startup and after each normalise run

Test plan

  • projection tests pin the hellofresh pivot names and gousto basis selection verbatim against committed fixtures
  • integration covers nutrient/rating filters, sorts, seeded-random paging stability, portion-count errors, ingredient-word search
  • MCP round-trip test drives the real in-process host with the SDK client: instructions, annotations, schemas, one call per tool
  • multiplied-fixture benchmark asserts the representative search stays under the 300ms gate
  • full suite: 121 unit + 68 integration tests green
## Summary - v_recipe gains the nine-nutrient per-portion panel, ratings, serving size and website url; search_text gains ingredient names so free text finds recipes by what is in them - gousto stores seo.canonical as the website url - the plan's slug reconstruction guessed wrong (the path carries a category segment), so per the plan's contingency it is stored, with a migration that queues a re-normalise - Page<T> replaces SearchResult; summaries carry the panel so agents pick recipes on macros without N get_recipe calls - search_recipes: nutrientFilters (whitelist enum-to-column map), minRating, sort name|rating|kcal|seeded random; maxKcal removed - get_recipe distinguishes unknown id from a wrong portion count, failing with the offered counts; detail adds offeredPortions, updatedAt, servingSizeGrams, websiteUrl - every tool is annotated read-only/idempotent/closed-world with structured output; server instructions ship at initialize - performance gate failed by an order of magnitude (live laterals cost seconds at ~75k rows), so v_recipe is materialized per the designed fallback: stored tsvector + GIN (~35ms full text), GiST trigram for the typo pass (now a fallback query, not an OR arm), refreshed at startup and after each normalise run ## Test plan - projection tests pin the hellofresh pivot names and gousto basis selection verbatim against committed fixtures - integration covers nutrient/rating filters, sorts, seeded-random paging stability, portion-count errors, ingredient-word search - MCP round-trip test drives the real in-process host with the SDK client: instructions, annotations, schemas, one call per tool - multiplied-fixture benchmark asserts the representative search stays under the 300ms gate - full suite: 121 unit + 68 integration tests green
Sign in to join this conversation.
No description provided.