Maestro task: 4c4570be-e0d2-43ad-90ea-0a4a9eeeb0b9 (Feature 10 - Recipe Grounding and Photos).
Done-condition
internal/recipes Extract(html, url) finds application/ld+json scripts and returns the Recipe node handling @graph, top-level arrays, @type string/array, image string/ImageObject/array (largest, absolute URL), recipeIngredient strings, recipeInstructions as string/HowToStep/HowToSection (flattened in order), ISO-8601 prep/cook/total -> minutes (total derived when absent), recipeYield, site name (publisher/og:site_name/host). testdata/ has >=6 trimmed real pages from different sites incl. HowToSection and @graph; table tests assert title/image/ingredients/steps/minutes and ErrNoRecipe. Go quality floor passes.
Evidence
internal/recipes extractor + fixtures; gofmt/vet/go test -race/build pass; no new dependency.
Note: some real fixtures (Allrecipes, Serious Eats) returned 403 when fetched; @type-array and relative-image shapes are covered by hand-written pages.
Maestro task: 4c4570be-e0d2-43ad-90ea-0a4a9eeeb0b9 (Feature 10 - Recipe Grounding and Photos).
## Done-condition
internal/recipes Extract(html, url) finds application/ld+json scripts and returns the Recipe node handling @graph, top-level arrays, @type string/array, image string/ImageObject/array (largest, absolute URL), recipeIngredient strings, recipeInstructions as string/HowToStep/HowToSection (flattened in order), ISO-8601 prep/cook/total -> minutes (total derived when absent), recipeYield, site name (publisher/og:site_name/host). testdata/ has >=6 trimmed real pages from different sites incl. HowToSection and @graph; table tests assert title/image/ingredients/steps/minutes and ErrNoRecipe. Go quality floor passes.
## Evidence
- internal/recipes extractor + fixtures; gofmt/vet/go test -race/build pass; no new dependency.
- Note: some real fixtures (Allrecipes, Serious Eats) returned 403 when fetched; @type-array and relative-image shapes are covered by hand-written pages.
recipes.Extract(page, url) scans a page's application/ld+json scripts and
og:site_name with a small targeted scanner (no new dependency) and returns
the single Recipe node: top level, top-level array or @graph, @type as a
string or array. It picks the largest image and resolves it against the
page URL, flattens HowToStep/HowToSection instructions in order, converts
ISO-8601 durations to minutes (total derived from prep + cook when absent),
and names the site from publisher, og:site_name or host. No Recipe is
ErrNoRecipe; two is ErrManyRecipes; shapes schema.org does not allow,
such as a "20 minutes" cookTime, are ErrMalformedRecipe.
testdata holds trimmed real pages from BBC Good Food, Budget Bytes,
RecipeTin Eats (HowToSection), King Arthur Baking, Delish (top-level
array), Food.com, Bon Appétit (non-ISO duration) and a Budget Bytes page
with no Recipe.
Maestro task 4c4570be-e0d2-43ad-90ea-0a4a9eeeb0b9.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
recipes.Extract(page, url) scans a page's application/ld+json scripts and
og:site_name with a small targeted scanner (no new dependency) and returns
the single Recipe node: top level, top-level array or @graph, @type as a
string or array. It picks the largest image and resolves it against the
page URL, flattens HowToStep/HowToSection instructions in order, converts
ISO-8601 durations to minutes (total derived from prep + cook when absent),
and names the site from publisher, og:site_name or host. No Recipe is
ErrNoRecipe; two is ErrManyRecipes; shapes schema.org does not allow,
such as a "20 minutes" cookTime, are ErrMalformedRecipe.
testdata holds trimmed real pages from BBC Good Food, Budget Bytes,
RecipeTin Eats (HowToSection), King Arthur Baking, Delish (top-level
array), Food.com, Bon Appétit (non-ISO duration) and a Budget Bytes page
with no Recipe.
Maestro task 4c4570be-e0d2-43ad-90ea-0a4a9eeeb0b9.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review findings on the Recipe extractor:
- An image or publisher given as an {"@id": ...} reference now resolves to
the node with that @id at a script's top level, in a top-level array or
in an @graph, in any of the page's scripts. An image reference no node
has, or one naming two nodes, is ErrMalformedRecipe; an unresolved
publisher falls through to og:site_name and the host as before.
- @type matches the term or the absolute https:// or http://schema.org IRI,
as a string or in an array, for Recipe, HowToStep and HowToSection.
- A present but empty or blank prepTime, cookTime or totalTime is an invalid
ISO-8601 duration (ErrMalformedRecipe); an absent or null one is still
nil.
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: 4c4570be-e0d2-43ad-90ea-0a4a9eeeb0b9 (Feature 10 - Recipe Grounding and Photos).
Done-condition
internal/recipes Extract(html, url) finds application/ld+json scripts and returns the Recipe node handling @graph, top-level arrays, @type string/array, image string/ImageObject/array (largest, absolute URL), recipeIngredient strings, recipeInstructions as string/HowToStep/HowToSection (flattened in order), ISO-8601 prep/cook/total -> minutes (total derived when absent), recipeYield, site name (publisher/og:site_name/host). testdata/ has >=6 trimmed real pages from different sites incl. HowToSection and @graph; table tests assert title/image/ingredients/steps/minutes and ErrNoRecipe. Go quality floor passes.
Evidence
Independent Codex gpt-6-sol review: CHANGES_REQUIRED for this exact commit.
Review findings on the Recipe extractor: - An image or publisher given as an {"@id": ...} reference now resolves to the node with that @id at a script's top level, in a top-level array or in an @graph, in any of the page's scripts. An image reference no node has, or one naming two nodes, is ErrMalformedRecipe; an unresolved publisher falls through to og:site_name and the host as before. - @type matches the term or the absolute https:// or http://schema.org IRI, as a string or in an array, for Recipe, HowToStep and HowToSection. - A present but empty or blank prepTime, cookTime or totalTime is an invalid ISO-8601 duration (ErrMalformedRecipe); an absent or null one is still nil. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>Independent Codex gpt-6-sol review: APPROVED for this exact commit.