Maestro task: 10c25cb5-3774-419c-87e1-3f87a3d1391d (Feature 10 - Recipe Grounding and Photos).
Done-condition
internal/recipes defines SearchProvider.Search(ctx, query, n) -> []Candidate{url,title,snippet}; a SearXNG implementation calls {MEALQUEST_SEARXNG_URL}/search?q=...&format=json&categories=general (internal URL allowed for this configured endpoint only); a Brave implementation calls the Brave Web Search API with the decrypted key; queries get ' recipe' appended when absent; ranking fetches/extracts top candidates and scores by title token similarity to the dish name plus completeness (ingredients, image, steps, minutes), rejecting candidates missing ingredients or image. httptest tests cover both providers' parsing, error mapping and ranking order. Go quality floor passes.
Evidence
internal/recipes search providers + ranking; gofmt/vet/go test -race/build pass; no new dependency.
Reuses the fetcher and JSON-LD extractor and the harness Normalize/Similar.
Maestro task: 10c25cb5-3774-419c-87e1-3f87a3d1391d (Feature 10 - Recipe Grounding and Photos).
## Done-condition
internal/recipes defines SearchProvider.Search(ctx, query, n) -> []Candidate{url,title,snippet}; a SearXNG implementation calls {MEALQUEST_SEARXNG_URL}/search?q=...&format=json&categories=general (internal URL allowed for this configured endpoint only); a Brave implementation calls the Brave Web Search API with the decrypted key; queries get ' recipe' appended when absent; ranking fetches/extracts top candidates and scores by title token similarity to the dish name plus completeness (ingredients, image, steps, minutes), rejecting candidates missing ingredients or image. httptest tests cover both providers' parsing, error mapping and ranking order. Go quality floor passes.
## Evidence
- internal/recipes search providers + ranking; gofmt/vet/go test -race/build pass; no new dependency.
- Reuses the fetcher and JSON-LD extractor and the harness Normalize/Similar.
recipes.SearchProvider.Search(ctx, query, n) returns []Candidate{URL,
Title, Snippet}, appending " recipe" when the query lacks the word.
SearXNG calls {MEALQUEST_SEARXNG_URL}/search?q=…&format=json&categories=general
directly (the configured endpoint may be internal); Brave calls the Web
Search API with the key decrypted from recipe_search_settings. Redirects
are not followed; 401/403, 429, other non-2xx and malformed bodies map to
distinct errors.
recipes.Rank fetches and extracts the top 5 candidates, rejects those
without ingredients or an image, and scores the rest by
harness.Similarity of the recipe title to the dish name plus
completeness (ingredients, image, steps, minutes). harness.Similarity
exposes the existing Jaccard score used by Similar.
Maestro task 10c25cb5-3774-419c-87e1-3f87a3d1391d.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
recipes.SearchProvider.Search(ctx, query, n) returns []Candidate{URL,
Title, Snippet}, appending " recipe" when the query lacks the word.
SearXNG calls {MEALQUEST_SEARXNG_URL}/search?q=…&format=json&categories=general
directly (the configured endpoint may be internal); Brave calls the Web
Search API with the key decrypted from recipe_search_settings. Redirects
are not followed; 401/403, 429, other non-2xx and malformed bodies map to
distinct errors.
recipes.Rank fetches and extracts the top 5 candidates, rejects those
without ingredients or an image, and scores the rest by
harness.Similarity of the recipe title to the dish name plus
completeness (ingredients, image, steps, minutes). harness.Similarity
exposes the existing Jaccard score used by Similar.
Maestro task 10c25cb5-3774-419c-87e1-3f87a3d1391d.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SearXNG now requires a results array and Brave requires "type": "search"
with a results array in any web object, so `{}` is ErrSearchResponse
instead of an empty search. Rank no longer drops failed candidates: it
returns the ranked ones with ErrCandidatesUnranked joined with each
unranked candidate's URL and reason, or ErrNoUsableRecipe when none rank.
Adds an HTTPS ranking test through the SSRF-safe Fetcher.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Maestro task: 10c25cb5-3774-419c-87e1-3f87a3d1391d (Feature 10 - Recipe Grounding and Photos).
Done-condition
internal/recipes defines SearchProvider.Search(ctx, query, n) -> []Candidate{url,title,snippet}; a SearXNG implementation calls {MEALQUEST_SEARXNG_URL}/search?q=...&format=json&categories=general (internal URL allowed for this configured endpoint only); a Brave implementation calls the Brave Web Search API with the decrypted key; queries get ' recipe' appended when absent; ranking fetches/extracts top candidates and scores by title token similarity to the dish name plus completeness (ingredients, image, steps, minutes), rejecting candidates missing ingredients or image. httptest tests cover both providers' parsing, error mapping and ranking order. Go quality floor passes.
Evidence
recipes.SearchProvider.Search(ctx, query, n) returns []Candidate{URL, Title, Snippet}, appending " recipe" when the query lacks the word. SearXNG calls {MEALQUEST_SEARXNG_URL}/search?q=…&format=json&categories=general directly (the configured endpoint may be internal); Brave calls the Web Search API with the key decrypted from recipe_search_settings. Redirects are not followed; 401/403, 429, other non-2xx and malformed bodies map to distinct errors. recipes.Rank fetches and extracts the top 5 candidates, rejects those without ingredients or an image, and scores the rest by harness.Similarity of the recipe title to the dish name plus completeness (ingredients, image, steps, minutes). harness.Similarity exposes the existing Jaccard score used by Similar. Maestro task 10c25cb5-3774-419c-87e1-3f87a3d1391d. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>recipes.SearchProvider.Search(ctx, query, n) returns []Candidate{URL, Title, Snippet}, appending " recipe" when the query lacks the word. SearXNG calls {MEALQUEST_SEARXNG_URL}/search?q=…&format=json&categories=general directly (the configured endpoint may be internal); Brave calls the Web Search API with the key decrypted from recipe_search_settings. Redirects are not followed; 401/403, 429, other non-2xx and malformed bodies map to distinct errors. recipes.Rank fetches and extracts the top 5 candidates, rejects those without ingredients or an image, and scores the rest by harness.Similarity of the recipe title to the dish name plus completeness (ingredients, image, steps, minutes). harness.Similarity exposes the existing Jaccard score used by Similar. Maestro task 10c25cb5-3774-419c-87e1-3f87a3d1391d. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>Independent Codex gpt-6-sol review: CHANGES_REQUIRED for this exact commit.
SearXNG now requires a results array and Brave requires "type": "search" with a results array in any web object, so `{}` is ErrSearchResponse instead of an empty search. Rank no longer drops failed candidates: it returns the ranked ones with ErrCandidatesUnranked joined with each unranked candidate's URL and reason, or ErrNoUsableRecipe when none rank. Adds an HTTPS ranking test through the SSRF-safe Fetcher. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>Independent Codex gpt-6-sol review: APPROVED for this exact commit.