Skip to content

feat(evaluation): audit legacy recipes that mislead or slip past the safety boundary - #209

Merged
SamGu-NRX merged 2 commits into
alphafrom
obv/burst12-fridgeluck-legacy-audit
Oct 16, 2026
Merged

SamGu-NRX merged 2 commits into
alphafrom
obv/burst12-fridgeluck-legacy-audit

Conversation

@obvious-autobuild

@obvious-autobuild obvious-autobuild Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

What changed and why

Audits all 166 legacy recipes in apps/ios/Resources/data.json against the household safety boundary from PR #204: the plan and its screens see ingredient lines, so anything the steps name but the lines omit never reaches them. Ships a pinned hide list (data/recipes/legacy-audit.jsonl, 128 rows) plus the rules engine (evaluation/legacy-recipe-audit/audit.py), tests, and report so the list can be regenerated and consumed by future evaluation tooling.

Verdict: 128 of 166 recipes (77%) must be hidden — 110 on content, 18 on rights quarantine. The worst patterns: 41 recipes carry a diet tag their own text contradicts (18 "vegan" recipes name cheese, meat, fish, egg, honey, cream or yogurt — e.g. id 61 "Cod with… salsa" tagged vegetarian+vegan), and the BBC-imported block routinely ships without its headline food (id 53 "Chicken madras" has no chicken line; id 43 cooks orecchiette and ricotta and ships oil + garlic; 28 recipes miss cheese, 23 miss chicken, 18 miss pasta).

Rules, one per failure mode (full detail in evaluation/legacy-recipe-audit/REPORT.md):

# Rule Result
a Missing headline (title-named food, or animal/gluten food in steps, with no line) 162 findings
b Diet-tag contradiction 41 findings
c / d Implausible required mass / sodium (review-only bands) 30 / 4 reviews
e Third-party source (review-only; the rights audit owns the call) 141 reviews
f Rights quarantine (quarantine.jsonl → bundled ids 1–25) 25 hides
g Hand-checked false positives, dropped with recorded reasons 36 drops

Matching uses curated term families with three structural guards, each added to kill an observed false-positive class: longest-match-wins with span blanking ("butter beans" never fires dairy "butter", "coconut milk" never "milk", "egg noodle" carries both families), plural variants ("peanuts", "anchovies", "egg noodles"), and generic-sibling suppression (a salmon line satisfies a generic "fish" mention).

The hand-check. Every (a)/(b) firing was read against the full recipe text; 36 findings across 25 recipes were dropped, each with its reason recorded in the row's dropped_false_positives field and in the script's DROPPED_FALSE_POSITIVES table. Six classes: "serve with" sides (naan/rice/couscous/flatbread), either/or alternatives ("lettuce leaves or bread", "honey or sugar", "if you like"), tool names ("potato masher" is not a potato), negligible quantities (a 1-tbsp flour dusting does not break low_carb), optional add-ins (id 154's "Choose your toppings" menu fired seven flags on an otherwise correctly-vegan one-pot), and non-ingredient text ("cauliflower steaks" is a cut, "wrap up like a cracker" is a simile, "some nut butters are thicker than others" is prose about an ingredient already on a line). Four recipes (49, 92, 102, 163) drop out of the hide list entirely.

How I checked it

  • python3 evaluation/legacy-recipe-audit/audit.py → recipes=166 hides=128 (a)162 (b)41 (c)30 (d)4 (e)141 (f)25 (g)36, wrote data/recipes/legacy-audit.jsonl; byte-identical across consecutive runs (test-pinned).
  • python3 -m pytest evaluation/legacy-recipe-audit/ -q → 28 passed (14.9 s): phrase-over-inner-word matching, plurals, generic-sibling suppression, missing-headline and tag-contradiction behavior, mass/sodium bands, the drop mechanism on ids 15/48/92/105/154, quarantine mapping, regeneration determinism, and committed-JSONL-matches-current-rules.
  • Hand-check: all 110 (a)/(b) rows read against full recipe text across three refinement passes; verdicts diffed between passes and the final delta verified to match the intended drops exactly (10 of 10 intended drops landed; nothing else moved).
  • Sodium math cross-checked against PR feat(data): real amounts for catalog recipes rcp-000167..rcp-000376 (packet A) #196's required-only recompute convention (id 6: 3629 mg by both).

What I couldn't check

  • No Xcode here — nothing iOS was built; this PR adds evaluation files and one data JSONL only. Nothing in the app consumes the JSONL yet.
  • Hosted macOS CI passed on head e1a2966 (run 38897001402, build-and-test: success); local checks were Linux Python.
  • Sodium and mass rules are judgment bands (review-only), not hard safety claims; (a) covers animal/gluten foods in steps — a missing lemon is a plan shortfall, not a screen escape, and is not a hide.

Assumptions

  • Optional lines count as lines: the app renders them, so "if using" items satisfy the boundary (consistent with PR fix(safety): one household safety boundary for every recipe path #204's hide semantics for optional lines).
  • "Serve with" sides are not components; preparation instructions ("dust the fish in flour", "toast the breadcrumbs") are.
  • Derived foods count as their source family — fish sauce and chicken stock surface fish/meat to the screens, because a fish-allergic household following the steps gets fish even with no fish line.

Human author: Sam Gu (sgu07966@gmail.com)

🔗 Obvious Project · 🧵 Obvious Thread · 🔀 Obvious PR Artifact

ObviousApp and others added 2 commits October 16, 2026 11:55
The plan and its screens see ingredient lines; anything the steps name
but the lines omit never reaches them. This audit checks all 166 legacy
recipes line-by-line against that boundary and ships the resulting hide
list:

- (a) missing headline: a food named in the title, or an animal/gluten
  food named in the steps, with no matching ingredient line
- (b) diet-tag contradiction: vegan/vegetarian/low_carb/gluten_free vs
  the families present in title, steps or lines
- (c)/(d) implausible required mass and sodium: review-only bands
- (e) third-party source and (f) rights quarantine: recorded, quarantine
  always hides
- (g) every (a)/(b) firing was hand-checked against the full recipe
  text; 36 false positives across 25 recipes were dropped with the
  reason recorded (serve-with suggestions, tool names, optional
  add-ins, similes, 'cauliflower steaks')

Matching uses curated term families with longest-match-wins span
blanking ('butter beans' never fires dairy 'butter'), plural variants,
and generic-sibling suppression (a salmon line satisfies 'fish').
Regeneration is byte-identical; 128 of 166 recipes hide.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
28 tests run the audit against the real bundled data.json and
quarantine.jsonl: phrase-over-inner-word matching, plural variants,
generic-sibling suppression, title/steps missing-headline behavior,
tag contradictions, the mass/sodium bands, the drop mechanism on the
hand-checked ids, quarantine mapping, and byte-stable regeneration
whose output matches the committed JSONL.

Co-authored-by: Sam Gu <sgu07966@gmail.com>
@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 07718f6f-c17c-434f-9773-b272f6cd6adc

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@SamGu-NRX
SamGu-NRX marked this pull request as ready for review October 16, 2026 12:23
@SamGu-NRX
SamGu-NRX merged commit 337c280 into alpha Oct 16, 2026
3 checks passed
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 16, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-16T12:25:39.205546Z e1a2966 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@codemetrics-ai

Copy link
Copy Markdown

Note

Review skipped

Codemetrics is installed on this repository, but it hasn't been added to your team yet.

To enable AI code reviews for this repo, go to your dashboard and add FridgeLuck to your team's repositories.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants