Skip to content

FLIngredientFacts: canonical ingredient facts with fail-closed restriction evaluation - #127

Draft
SamGu-NRX wants to merge 20 commits into
alphafrom
overhaul/ingredient-facts
Draft

SamGu-NRX wants to merge 20 commits into
alphafrom
overhaul/ingredient-facts

Conversation

@SamGu-NRX

@SamGu-NRX SamGu-NRX commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner

What changed

Restriction checks in FridgeLuck fail open in about ten modules, for one shared reason: each module keeps its own ingredient list, and an ingredient missing from the list counts as allowed. Reviewers found soy sauce, tamari and cream cheese offered to eaters avoiding wheat, soy and milk; lard and Worcestershire sauce offered to vegetarians; generic tamari marked gluten-free with no product evidence; and checks passing when an ingredient has no allergen or diet properties at all.

This PR adds the canonical ingredient-facts source the overhaul spec (§3.1, binding) requires, plus the conformance kit that lets Swift, TypeScript and Python consumers prove they read it the same way:

Why

Spec §3.1 makes rechecking compound ingredients for all eaters a release blocker, and §3.3 makes explicit restrictions hard filters that are never weakened. Today each module's private list decides "safe" by absence of evidence. This PR centralizes the evidence: a variable or unsourced property is unknown, never false, so a missing fact can only ever produce "ask the user".

How it works

flowchart LR
    A["Ingredient name<br/>(key, synonym, scan result)"] --> B["Resolve identity<br/>canonical key → FDC id, app id"]
    B --> C["Composition facts<br/>components, allergens, diets,<br/>each with a source"]
    C --> D{"evaluate(ingredient,<br/>restrictions)"}
    D -->|"known component<br/>conflicts"| E["violated<br/>reason + evidence"]
    D -->|"facts missing,<br/>variable or unsourced"| F["unknown<br/>what is missing — ask the user"]
    D -->|"all checked facts known,<br/>no conflict"| G["allowed<br/>evidence"]
Loading

The only path to "allowed" runs through known, sourced facts; anything unresolved comes out "unknown", never "allowed". A meal's restrictions are the union of every eater's.

UI changes

N/A — data, package and audit docs only; no app UI changes in this PR. (This sandbox has no Xcode, simulator or device; app-side integration happens in the affected PRs' own branches. Native app compilation is exercised by the existing iOS CI on this PR.)

Verification

Planned checks (run in the Linux sandbox: Swift 6.2, Bun 1.3.14, Python 3.13). Results land in the Proof section as milestones merge to this branch:

cd packages/FLIngredientFacts && swift build && swift test
bun data/ingredient-facts/conformance/runners/typescript/run_conformance.ts
python3 data/ingredient-facts/conformance/runners/python/run_conformance.py

Risk

  • The dataset's coverage of compound ingredients depends on the recipe corpora it is derived from (data.json bundled recipes plus the original-recipe corpus branches); the conformance kit pins the required cases, and the dataset README records what was covered.
  • No GitHub App is connected to this workspace, so work ran in fresh clones on the Obvious sandbox, authenticated with the workspace GitHub token; authorship is Sam Gu on every commit.
  • Nothing here merges, deploys or touches workflows; this is a draft PR for review.

Checklist

  • The scope is focused; related changes belong together
  • I explained what changed and why
  • N/A — before/after images: no visible app change (data + package only)
  • N/A — video: no motion or interaction change

Proof

Filled in as milestones land on this branch — exact commands and their real output, trimmed.

Interim (23:45 UTC): fix-list milestone landed and verified —

Interim (00:25 UTC): package/dataset/conformance milestone — verified by the parent at head d954b69:

  • Dataset: identities.json (193 ingredients, schema v1), facts.json (260 fact entries, schema v1), coverage.json generated from the seven fl-recipe-originals-* branches, conformance/cases.json (43 cases), tools/build_dataset.py.
  • Independent TypeScript runner: all 43 cases pass (bun run_conformance.ts, exit 0 — run by the parent at this head).
  • Independent Python runner: all 43 cases pass (python3 run_conformance.py, exit 0 — run by the parent at this head).
  • Swift package at this head: swift build clean (7.5s); swift test passes its smoke test (1/1); the full Swift dataset-validation/conformance/semantics suite is still in progress.
  • CI: build-and-test running at d954b69 (earlier heads green).

Final (00:36 UTC) — full verification loop at head b0deecce36bf6ee91e6f5933e746d75466165288, every check run by the parent:

  • swift build clean; swift test 37/37, 0 failures (DatasetValidationTests incl. blank-ref/note loader cases, ConformanceCaseTests — all 43 shared cases through the real store, EvaluationSemanticsTests incl. wheat/gluten independence, SmokeTests).
  • TypeScript runner 43/43, exit 0; Python runner 43/43, exit 0 (independent reimplementations).
  • negative_checks.sh: all three implementations (Swift, TS, Python) reject all six malformed-dataset mutations (stripped fact-level ref, stripped component-level ref, blank ref, empty note, unknown component-evidence kind, deleted evidence object) — join-found gap closed at b0deecc.
  • Fix-list comment coverage re-verified: exactly one fl-ingredient-facts-fixlist comment per PR, 10/10.
  • CI at b0deecc: build-and-test ✅ and dead-code-advisory ✅ (iOS CI workflow completed 00:36 UTC).

Handoff

  • Done: branch overhaul/ingredient-facts cut from alpha (0309dd1), skeleton and pinned API contract committed, draft PR opened.
  • Done since skeleton: all ten restriction fix lists committed and pushed (02be6bf, 3b184a3); one comment posted on each affected PR (verified exactly one each).
  • Done since fix lists: fail-closed FLIngredientFacts store, dataset loader, 43-case conformance executable, independent TS + Python runners (43/43 each), dataset with 193 identities / 260 facts / coverage evidence, and the review-5485500522 correction pass on all ten fix lists (306d5da).
  • Done since conformance milestone: evidence-completeness enforced by all three loaders (Swift rejects blank ref/note; TS + Python run a shared completeness check at fact and component level), plus a negative_checks.sh harness — six mutations, zero acceptances (b0deecc).
  • Not done: native Apple-platform behavior is UNVERIFIED (no iOS/Xcode host in this environment — all checks are Linux-verified); reviewer re-review of this PR; the ten PRs' actual code changes per their fix lists are separate streams.
  • Known imperfection: merge commits 219d6e1 and e18173e carry bare merge messages without the co-author trailer — left intact per the no-history-rewrite rule.
  • Next steps: land the package + dataset + conformance kit, land the ten fix lists, run the full verification loop on the joined head, and update this Proof/Handoff.
  • Head SHA: b0deecc — full loop green (parent-verified); CI state as above.

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

Pins the FLIngredientFacts API contract and semantics (fail-closed
restriction evaluation), the dataset layout with sourced evidence rules,
and the audit index for per-PR integration fix lists.

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Oct 11, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • 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 left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: FIX

Reviewed 5597db7caf322649b001c6b04849095a00dc0750 against fl-root-ingredient-facts-f1 and SPEC 3.1/3.3. This head adds three README files only. The result ordering, unknown handling and union of eaters' restrictions are sensible proposed rules; there is no executable evaluator or dataset to verify yet. Handoff accurately calls this a skeleton.

Findings that need fixing:

  • packages/FLIngredientFacts/README.md:64-69 says tamari's wheat uncertainty can be resolved by gluten-free product evidence. Keep wheat-allergen evidence independent from gluten-free evidence. FDA permits some processed wheat-derived ingredients in gluten-free foods, so that label does not establish absence of wheat. Document this distinction before consumers implement the pinned contract. Add conformance cases for a gluten-free label with unknown wheat composition, and for a gluten-free product with a declared wheat-derived component, evaluated separately against wheat avoidance and the gluten-free diet. See FDA's gluten-free labeling Q&A, General question 6.
  • packages/FLIngredientFacts/README.md:18-20,24-55,74-86 describes package types, tests and tested semantics that do not exist at this head. data/ingredient-facts/README.md:3-20 likewise describes files and runners absent from the tree. Label these as planned and describe the current three-document milestone consistently. The PR's opening claims also describe the whole planned deliverable as already added, while Proof is pending and Handoff correctly says it is unimplemented.
  • data/ingredient-facts/README.md:14-26 and packages/FLIngredientFacts/README.md:42-51 do not yet pin the JSON representation or the evidence, identity, violation and unknown payloads. Those definitions are needed for three independent consumers to produce the same result. Specify malformed-data rejection, unresolved references and aliases, missing per-restriction facts, and the exact per-restriction evidence required for allowed. A nutrient catalog mapping or recipe occurrence alone must not become proof of allergen absence.

Lesser finding:

  • packages/FLIngredientFacts/README.md:80-82 changes directory into the package, then runs the two consumers with repository-root-relative paths. That command block will look under packages/FLIngredientFacts/data/. Keep all three commands rooted consistently when the runners land.

Task criteria, 1/8 met:

Criterion Status and evidence
Canonical identities, FDC/local mappings and distinct preparation forms Missing: identities.json does not exist.
Nine allergens, separate gluten and five diets Partly met: the planned vocabulary is documented; no records or evaluation exist, and wheat/gluten evidence needs the distinction above.
Sourced composition for all required compounds and both corpora Missing: facts.json and coverage evidence do not exist.
Fail-closed evaluation API and meal restriction union Partly met: proposed signatures and ordering only; no Package.swift, sources or tests.
Shared JSON cases and Swift/TypeScript/Python conformance Missing: no cases or runners, including the named failure examples.
Saved integration fix lists and comments for all ten targets Missing: the audit directory contains its index only; Handoff confirms the lists and comments are unfinished.
Package/conformance test Proof Missing: Proof says pending first milestone.
Scope and ownership Met: all changes are in the three owned directories; no workflow or recipe text changes.

CI via REST passed iOS build-and-test and dead-code-advisory at this exact head. Those checks cannot validate a package that has not been added. Source and contract review only; no local tests, Xcode or simulator runs.

SamGu-NRX and others added 2 commits October 11, 2026 23:18
Fail-open audits at each PR head: per-module ingredient lists, absent
restriction evaluation, and missing unknown states, with exact
FLIngredientFacts / data-conformance integration steps per file.

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
Fail-open audits at each PR head: claims-based screening with defaults,
sim catalogs built without facts, substitution class divergence
(tamari/lard/worcestershire), name-only pantry feasibility, and
scenario keyword expansion, with exact FLIngredientFacts / data
conformance integration steps per file.

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>

@SamGu-NRX SamGu-NRX left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: BLOCK

Reviewed 3b184a38b41df9a7eada5538cbecb5c5751d2b4a against fl-root-ingredient-facts-f1 and SPEC 3.1/3.3. This update adds all ten audit documents. I read each, compared the cited SHAs with the inventory and checked the relevant restriction source. REST also confirms ten delivery comments. The proposed fixes need correction before consumers use them.

Blockers, paths under docs/audits/ingredient-facts:

  • PR-93.md:85-92 uses continue inside the ingredient loop for both violated and unknown results. That skips the ingredient and continues checking the same recipe; it never rejects or holds the recipe. A recipe containing forbidden cream cheese can finish that loop and remain eligible. Reject the whole candidate on any violation, and hold it for confirmation on any unknown. Show the recipe-level decision, with a counterexample where a later ingredient is allowed. The actual target's RecipeRepository.swift:130-198 appends recipes after its exclusion gate, so retaining only the proposed inner loop would preserve the failure.
  • PR-94.md:35-40,57-65 defines evaluate as returning an object with a kind, then switches on that object with string cases. None of those cases matches; firstRestrictedFood falls through to undefined instead of returning a rejection. PR-101.md:34-38,56-63 repeats the mismatch. Dispatch on the discriminant, exhaust all outcomes and preserve reason/missing evidence. Verify the wrapper itself rejects violated and unknown ingredients, not merely the evaluator in isolation.
  • PR-119.md:3,10-15,34-69 does not cite reviewable source. GitHub's REST commit endpoint returns HTTP 422, No commit found for SHA c20e6b47e930e7bf3e29bb57797b0a2e897dcbe5. The current #119 head is eb303be, and its tree contains none of the cited apps/ios/Utilities/FLScenarioJoin.swift, apps/ios/Models/HealthProfile.swift or apps/ios/Services/AgentWorld.swift paths. Its scenario package is packages/ScenarioJoin. No restrictionExpansion symbol appears in its Swift source. Re-audit the actual head and correct the already-posted #119 fix list; these instructions currently direct the owner to nonexistent code.

Standing findings:

  • packages/FLIngredientFacts/README.md:64-69 still lets gluten-free product evidence resolve wheat uncertainty. Keep wheat-allergen evidence separate; a gluten-free label does not establish wheat absence. The FDA labeling Q&A permits some processed wheat-derived ingredients in gluten-free foods. Add separate wheat-avoidance and gluten-free cases.
  • The package directory still contains only README.md; data/ingredient-facts still contains only README.md. There is no Package.swift, evaluator, identities.json, facts.json, conformance case or runner. The planned payload/schema validation and evidence requirements remain undefined. The repository's present-tense tested/package/dataset claims remain ahead of the implementation.

Lesser findings:

  • PR-93.md:37-38 puts a throwing store initializer in a nonthrowing static property initializer and force-unwraps resourceURL. Define a startup load/error path rather than an example consumers cannot use as written. PR-119.md:47-50 passes an undefined Path value where the pinned API requires URL.
  • The multi-package command blocks in PR-99, PR-103, PR-105, PR-114 and PR-117 change directory and then use another repository-root-relative path. Keep their working directory consistent. These commands were not run here.

Task criteria, 1/8 met:

Criterion Status and evidence
Canonical identities and FDC/local/preparation mappings Missing: no identity records.
Nine allergens, separate gluten and five diets Partly met: planned vocabulary only; wheat/gluten distinction still needs correction.
Sourced compound composition and corpus coverage Missing: no facts or coverage evidence.
Fail-closed evaluator and meal union Partly met: README signatures only; no implementation or tests.
Shared cases and Swift/TypeScript/Python conformance Missing: no cases or runners.
Ten accurate saved fix lists and delivery comments Partly met: ten files and comments delivered, but unsafe examples and an unsupported #119 audit above. Nine cited heads match the inventory.
Package/conformance test Proof Missing: PR Proof remains pending.
Scope and ownership Met: this update changes only the owned audit directory. No workflow or recipe text changes.

REST iOS build-and-test was in progress when checked. It does not validate these proposed integration examples or the absent package. Source/document review only; no local tests, Xcode or simulator runs.

SamGu-NRX and others added 9 commits October 11, 2026 23:46
Generator produces identities.json (canonical keys, display names,
synonyms, USDA FDC ids from the bundled catalog where matched, app local
ids for the 50 core ingredients) and facts.json (components with
certainty, sourced allergen facts, gluten as a separate property, diet
facts, certified-gluten-free tamari product form). Validation enforces
evidence on every non-unknown fact, resolvable component keys, unique
match names and a path-based cycle check. Corpus coverage enumerates the
bundled app data and the seven originals branches programmatically.

Draft checkpoint: corpus compounds from the originals compound-allergens
tables still to be expanded.

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
… labels

Reviews 5485500522 (BLOCK) and 5485457120 (FIX): a gluten-free label
supports the gluten property only — FDA permits processed wheat-derived
ingredients in gluten-free-labeled foods, so GF evidence never
establishes wheat absence (Q&A General question 6). Certified-GF tamari
now keeps wheat unknown; new gluten-free-bread identity models the FDA
case (GF label + declared wheat starch: glutenFree allowed, wheat
violated); spelt and farro are wheat-species violations; certified-GF
oats form carries wheat-free (standard) plus gluten-free (label)
evidence.

Both READMEs now pin the identities/facts JSON schemas, evidence payload
and per-result evidence rules — absence facts (free/allowed) may not use
usda/recipe evidence, enforced by the generator validator — and mark
deliverables not yet in the tree as PLANNED. Verification commands are
all repository-root relative. Forms overrides are validated through the
same fact checks.

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
- PR-93: recipe-level reject/hold verdict in RecipeRepository (lines
  130-198) with a rescue counterexample; safe throwing store loader.
- PR-94, PR-101: dispatch on the typed FLEvaluation kind discriminant,
  exhaustive with never-guard, reason/missing preserved; wrapper-level
  rejection tests for violated and unknown.
- PR-119: re-audited at the real head eb303be (packages/ScenarioJoin,
  SwapGate, FLDomain Restriction defaults) replacing the invented
  citations; URL-based store loading.
- PR-99/103/105/114/117: conformance commands rooted at the repository
  root.

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
Adds the compound ingredients enumerated by the originals-branch
compound-allergens tables (teriyaki, hoisin, doenjang, ssamjang,
doubanjiang, black-bean-sauce, shrimp-paste, thai-curry-paste, satay,
peanut-sauce, mole, aioli, hollandaise, bechamel, fresh-pasta,
wonton-wrappers, gyoza-skins, gnocchi, orzo, tempeh, soy-milk,
chocolate) and the corpus simple identities (nut, fish, meat, dairy and
stock entries), each with sourced facts or honest fail-closed gaps.
Ghee, coconut and pine-nuts are promoted to named identities; tahini
gains the tahina alias; a generic vinegar part distinguishes distilled
from malt. Compound diet facts now propagate from component classes with
certainty (variable components demote allowed to unknown); compound
allergen facts derive from certain/typical component carriers, explicit
unknowns for variable carriers, and free facts only for complete
compositions. 193 identities, 261 fact entries, 85/85 corpus names
covered; absence facts may not use usda/recipe evidence (validator-
enforced).

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
usdaFdcId and appLocalIds are integers, usdaRef/usdaNote name the
matched catalog row, and forms are {key, display, synonyms} records
matching the README pin. Fact entries now carry their class. Generator
validator and coverage name-index follow the new form shape.

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>

@SamGu-NRX SamGu-NRX left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: BLOCK

Reviewed 227b4cd9f2802a542fa96c9b15b920915cae881d against fl-root-ingredient-facts-f1 and SPEC 3.1/3.3. The dataset has landed, and this head aligns the identity ID types with the documented schema. The saved #93/#94/#101 examples and #119 audit are corrected, and certified-GF tamari now leaves wheat unknown. The new facts still contain unsafe absence claims.

Paths below are under data/ingredient-facts unless otherwise specified.

Blockers:

  • data/ingredient-facts/tools/build_dataset.py:1204-1211,1272-1295,1316-1330 reads only directly declared component allergens, then calls the compound free of everything it did not find. It never propagates nested compound facts or their uncertainty. Consequently facts.json:9645-9651,9735-9741 marks pesto milk-free and dairy-free despite its parmesan component; facts.json:9397-9410,9422-9436 marks peanut sauce wheat-free, soy-free and gluten-free despite its soy-sauce component. These records can clear the exact restrictions the task must reject. Derive each axis recursively from component facts and retain unknowns; add these counterexamples to every runner.
  • tools/build_dataset.py:1006-1013 closes generic doenjang's composition on rice-koji while explicitly saying barley-koji variants exist. facts.json:3571,3646-3660 then calls it gluten-free. A generic product with the documented barley uncertainty must remain unknown without product evidence. The gluten derivation must read component gluten facts, not just the major-allergen index.
  • tools/build_dataset.py:396-398,1338-1345,1376-1379,1422-1426 gives the deliberate identity-without-facts granola bar a plant classification and still derives facts for it. facts.json:678-715 grants vegetarian, vegan, pescatarian and dairy-free clearance. Keep this unsourced example without facts or explicitly unknown; a name/class guess cannot establish absence.
  • tools/build_dataset.py:1567-1574 filters git's root-relative paths with /data/recipes/originals/, including a leading slash. Actual paths begin data/recipes/originals/, so none of the originals are inspected. coverage.json:4-19 lists seven originals branches and claims 85/85 corpus names covered despite skipping their recipe files. Fix the path match, require the intended inputs and pin their SHAs before regenerating coverage.
  • data/ingredient-facts/README.md:52,56-93 requires globally unique form keys and an array of keyed facts. The emitted facts remain an object with nested form overrides. Both oats and tamari use the same form key, certified-gluten-free, in identities.json:1221-1225,1808-1812. It also requires evidence.note, which emitted component evidence sometimes omits. Align the generator, schema and all readers before consumers implement against incompatible contracts.
  • packages/FLIngredientFacts/README.md:12-22 correctly labels the implementation planned. The directory still contains only that README, and there are no conformance cases or runners. The required loader, evaluation, meal union and cross-language behavior therefore remain unavailable. Add the implementation and shared cases, including malformed data and the unsafe records above, with real Proof.
  • Saved corrections in docs/audits/ingredient-facts/PR-93.md:105-138, PR-94.md:57-74 and PR-101.md:56-74 have not replaced the delivered instructions. REST confirms the #93 comment still continues the ingredient loop on violation; #94 and #101 still switch the evaluation object against strings. Update those existing comments so consumers receive the corrected recipe-level gate and discriminant dispatch. The #119 comment has been corrected.

Lesser findings:

  • identities.json:1494-1524 maps cooked and uncooked rice to one raw-rice FDC identity, and cooked and dried noodles to one dry-noodle identity. Preserve preparation forms as the task requires.
  • tools/build_dataset.py:1218-1247 adds diet_implication but never calls it from derivation. Compound vegetarian/vegan/pescatarian facts remain missing unless manually overridden.
  • Gluten-label citations still name 21 CFR 101.100. The governing rule is 21 CFR 101.91, including its allowance for qualifying processed wheat-derived ingredients. Keep each absence claim tied to actual evidence for that axis.

Task criteria, 1/8 met:

Criterion Status and evidence
Canonical identities and FDC/local/preparation mappings Partly met: records exist; preparation forms collapse.
Nine allergens, separate gluten and five diets Partly met: vocabulary exists; unsafe derived facts above.
Sourced compound composition and corpus coverage Partly met: records exist; nested composition and originals coverage fail.
Fail-closed evaluator and meal union Missing: no package implementation.
Shared Swift/TypeScript/Python conformance Missing: no cases or runners.
Ten accurate saved fix lists and delivery comments Partly met: saved corrections exist; three delivered comments remain unsafe.
Package/conformance test Proof Missing: required implementation and checks pending.
Scope and ownership Met: owned data/package/audit paths only; no workflow or recipe-expression additions.

REST build-and-test was in progress at this head. Earlier app CI success does not validate this dataset or the absent package. Source and CI review only; no local tests, Xcode or simulator runs.

SamGu-NRX and others added 4 commits October 12, 2026 00:12
FLIngredientFactsStore resolves keys, display names, synonyms and
preparation-form match names; evaluation gives violated > unknown >
allowed, propagates compound components, treats variable components as
unknown-when-violating, and keeps wheat and gluten evidence independent.
The loader rejects malformed data, unresolved references and absence
facts resting on catalog/recipe evidence. All 43 conformance cases pass
through the real store (flfacts-conformance).

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
Both runners re-implement the pinned evaluation semantics from scratch
(no shared code with the Swift package), load and strictly validate the
dataset, run all 43 shared cases and exit nonzero on any failure. All
43 cases pass in both, matching the Swift store result for result.

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
33 XCTests: the real dataset loads; every pinned malformed-data class is
rejected (bad JSON, unknown vocab, unresolved component or form, missing
evidence fields, absence facts backed by USDA or recipe evidence,
duplicate synonyms); all 43 shared cases run through the real store;
fail-closed, unknown propagation, certainty levels, union restrictions
and the independent wheat/gluten axes are unit-tested, including a
synthetic compound that violates purely via a certain component.
README status tables now reflect what exists.

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
Replaces the PLANNED markers on cases.json and the two runners with
present-tense status; all three are in the tree and green.

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>

@SamGu-NRX SamGu-NRX left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: BLOCK

Reviewed 4d5c31081cb0bc22e708c45d922062668c19a7b5 against fl-root-ingredient-facts-f1 and SPEC 3.1/3.3. The Swift store, meal union, tests and three conformance runners now exist. Nested pesto milk and peanut-sauce soy/wheat facts, unique form keys and the factless granola example are corrected. The remaining clearance paths below still fail the task's safety contract.

Blockers:

  • packages/FLIngredientFacts/Sources/FLIngredientFacts/FLIngredientFactsStore.swift:256-261 permits component-derived clearance whenever the missing properties are diets, even when compositionComplete is false. The shipped chilli-sauce record has incomplete composition and no dairyFree fact; all four listed components allow dairyFree, so evaluation returns allowed. Unlisted components could carry milk. Require complete, sourced composition or product evidence for dietary absence too. The TypeScript and Python runners repeat this shortcut.
  • data/ingredient-facts/tools/build_dataset.py:1006-1013,1338-1352 still declares generic doenjang complete using rice-koji while its own note says barley-koji variants introduce gluten. The resulting facts grant glutenFree clearance. The derivation also detects gluten through the major-allergen index rather than component gluten facts, so barley/rye uncertainty is lost. Keep variable formulations unknown and derive gluten independently; add doenjang and barley-component cases to all runners.
  • data/ingredient-facts/tools/build_dataset.py:283-295 turns a generic gluten-free oats label into wheat-free evidence. Its aliases include plain "gluten-free oats", without a separate wheat ingredient declaration or named certification standard. The conformance case oats-certified-gf-vs-wheat enforces that clearance. FDA's labeling rule specifies a gluten threshold and allows qualifying wheat-derived ingredients; the label alone does not establish wheat absence. Preserve the separate axes already implemented for tamari.
  • data/ingredient-facts/tools/build_dataset.py:492-501,1304-1317 declares generic peanut butter's typical ingredients a complete composition, then grants soy/milk/tree-nut absence with a ref of "compound composition". The source note only says typical brands contain no other major allergen. A typical formulation cannot prove absence for every generic product. Keep unsupported negative facts unknown, or attach actual product-specific composition evidence before granting clearance.
  • data/ingredient-facts/tools/build_dataset.py:1611-1623 still matches root-relative git paths against /data/recipes/originals/. Actual originals paths begin data/recipes/originals/, so the seven branches contribute no recipe ingredients. The reported 85/85 coverage is still bundled-only. Correct the path match, require the intended inputs, pin source heads and regenerate coverage before claiming every compound is covered.
  • The delivered #93 fix list still uses an ingredient-loop continue for violation/unknown, which does not reject the recipe. The #94 and #101 comments still switch an evaluation object against string cases. REST confirms these corrections remain only in the saved audit files. Update the existing comments so implementers receive the corrected recipe-level gate and result-discriminant dispatch.

Lesser findings:

  • data/ingredient-facts/README.md:52,60 still requires every identity to have facts and documents facts as an array. The loader consumes an object and special-cases the deliberately factless granola identity. Update the pinned contract to match its readers.
  • packages/FLIngredientFacts/Sources/FLIngredientFacts/Dataset.swift:187-218,241-245 accepts the same state vocabulary on every axis. An allergen fact with state allowed is accepted and clears avoidance; a diet fact with state free does likewise. Reject wrong-axis states as the README promises. All three conformance entry points also silently drop unrecognized restriction strings.
  • Preparation synonyms still merge cooked and raw rice, and cooked and dried noodles, into one FDC identity. Preserve the forms required by the task. Gluten-label refs still cite 21 CFR 101.100 instead of 101.91.

Task criteria, 1/8 met:

Criterion Status and evidence
Canonical identities and FDC/local/preparation mappings Partly met: identities exist; preparation forms still collapse.
Nine allergens, separate gluten and five diets Partly met: vocabulary exists; gluten derivation and oats wheat clearance break axis separation.
Sourced compound composition and corpus coverage Partly met: nested allergens improve; unsupported absence and skipped originals remain.
Fail-closed evaluator and meal union Partly met: both implemented; incomplete composition still grants diet clearance.
Shared Swift/TypeScript/Python conformance Partly met: 43 cases and all runners exist; an unsafe oats expectation is pinned and counterexamples are missing.
Ten accurate saved fix lists and delivered comments Partly met: saved corrections exist; three delivered comments remain wrong.
Package/conformance test Proof Partly met: Proof reports two runners 43/43 and one smoke test at d954b69; full Swift suite and this joined head remain unverified.
Scope and ownership Met: owned data/package/audit paths; no workflow or recipe-expression additions.

REST build-and-test is in progress at this exact head. Earlier app CI does not cover this package or validate the dataset's absence claims. Source and CI review only; no local tests or native runs.

The TypeScript and Python runners validated evidence ref/note only on
fact-level objects and accepted empty strings; a dataset copy with a
component evidence 'ref' stripped loaded fine and all 43 cases passed.
Both runners now run the same completeness check the Swift loader
enforces — known kind, non-blank ref and note on every evidence object,
fact-level and component-level. The Swift loader additionally rejects
blank (whitespace) ref/note, which typed decoding alone let through.
Adds negative_checks.sh, which replays six malformed-data mutations
against all three implementations (bun runner, Python runner and the
flfacts-conformance binary) and exits nonzero if any of them accepts a
mutation, plus four new Swift loader tests (37 total).

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>

@SamGu-NRX SamGu-NRX left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: BLOCK

Reviewed b0deecce36bf6ee91e6f5933e746d75466165288 against fl-root-ingredient-facts-f1 and SPEC 3.1/3.3. This revision adds nonblank evidence validation to all three loaders, four Swift regression tests, and six cross-language malformed-dataset checks. These address evidence shape, while the unsupported clearance paths below remain unchanged.

Blockers:

  • packages/FLIngredientFacts/Sources/FLIngredientFacts/FLIngredientFactsStore.swift:256-261 permits component-derived clearance whenever the missing properties are diets, even when compositionComplete is false. The shipped chilli-sauce record has incomplete composition and no dairyFree fact; all four listed components allow dairyFree, so evaluation returns allowed. Unlisted components could carry milk. Require complete, sourced composition or product evidence for dietary absence too. The TypeScript and Python runners repeat this shortcut.
  • data/ingredient-facts/tools/build_dataset.py:1006-1013,1338-1352 still declares generic doenjang complete using rice-koji while its own note says barley-koji variants introduce gluten. The resulting facts grant glutenFree clearance. The derivation also detects gluten through the major-allergen index rather than component gluten facts, so barley/rye uncertainty is lost. Keep variable formulations unknown and derive gluten independently; add doenjang and barley-component cases to all runners.
  • data/ingredient-facts/tools/build_dataset.py:283-295 turns a generic gluten-free oats label into wheat-free evidence. Its aliases include plain "gluten-free oats", without a separate wheat ingredient declaration or named certification standard. The conformance case oats-certified-gf-vs-wheat enforces that clearance. FDA's labeling rule specifies a gluten threshold and allows qualifying wheat-derived ingredients; the label alone does not establish wheat absence. Preserve the separate axes already implemented for tamari.
  • data/ingredient-facts/tools/build_dataset.py:492-501,1304-1317 declares generic peanut butter's typical ingredients a complete composition, then grants soy/milk/tree-nut absence with a ref of "compound composition". The source note only says typical brands contain no other major allergen. A typical formulation cannot prove absence for every generic product. Keep unsupported negative facts unknown, or attach actual product-specific composition evidence before granting clearance.
  • data/ingredient-facts/tools/build_dataset.py:1611-1623 still matches root-relative git paths against /data/recipes/originals/. Actual originals paths begin data/recipes/originals/, so the seven branches contribute no recipe ingredients. The reported 85/85 coverage is still bundled-only. Correct the path match, require the intended inputs, pin source heads and regenerate coverage before claiming every compound is covered.
  • The delivered #93 fix list still uses an ingredient-loop continue for violation/unknown, which does not reject the recipe. The #94 and #101 comments still switch an evaluation object against string cases. REST confirms these corrections remain only in the saved audit files. Update the existing comments so implementers receive the corrected recipe-level gate and result-discriminant dispatch.

Lesser findings:

  • data/ingredient-facts/README.md:51,60 still requires every identity to have facts and documents facts as an array. The loader consumes an object and special-cases the deliberately factless granola identity. Update the pinned contract to match its readers.
  • packages/FLIngredientFacts/Sources/FLIngredientFacts/Dataset.swift:192-221,249-253 accepts the same state vocabulary on every axis. An allergen fact with state allowed is accepted and clears avoidance; a diet fact with state free does likewise. Reject wrong-axis states as the README promises. All three conformance entry points also silently drop unrecognized restriction strings.
  • Preparation synonyms still merge cooked and raw rice, and cooked and dried noodles, into one FDC identity. Preserve the forms required by the task. Gluten-label refs still cite 21 CFR 101.100 instead of 101.91.

Task criteria, 2/8 met:

Criterion Status and evidence
Canonical identities and FDC/local/preparation mappings Partly met: identities exist; preparation forms still collapse.
Nine allergens, separate gluten and five diets Partly met: vocabulary exists; gluten derivation and oats wheat clearance break axis separation.
Sourced compound composition and corpus coverage Partly met: nested allergens improve; unsupported absence and skipped originals remain.
Fail-closed evaluator and meal union Partly met: both implemented; incomplete composition still grants diet clearance.
Shared Swift/TypeScript/Python conformance Partly met: 43 cases and all runners exist; an unsafe oats expectation is pinned and counterexamples are missing.
Ten accurate saved fix lists and delivered comments Partly met: saved corrections exist; three delivered comments remain wrong.
Package/conformance test Proof Met as reported: parent records 37/37 Swift tests, both runners 43/43, and six negative mutations at this exact head. Source contains 37 test methods and the mutation harness. These Linux results remain author-reported.
Scope and ownership Met: owned data/package/audit paths; no workflow or recipe-expression additions.

REST build-and-test passes at this exact head. The workflow runs app Xcode tests, not the standalone ingredient-facts package or conformance runners. It does not validate the dataset's absence claims. Source and CI review only; no local tests or native runs.

SamGu-NRX added a commit that referenced this pull request Oct 12, 2026
…ition

The allergen/diet claim scan cleared claims through the fixture alias
table in allergens.json (rs.py:573-619, allergens.json:172-173 at base
9e04af4): a tamari-only recipe with a gluten-free claim and empty
conflicts cleared with no product composition evidence, and an unknown
name (cream cheese under a dairy-free claim) disappeared from the scan
surface entirely. Both violated evaluation/CONTRACTS.md:15-18 and :62 —
verdicts come only from FLIngredientFacts data, and missing canonical
facts must hold dependent claims.

rs.py now sources claim verdicts ONLY from FLIngredientFacts
(data/ingredient-facts, branch overhaul/ingredient-facts — PR #127):

- FLIngredientFacts: thin read-only dataset consumer (identity and
  product-form resolution, fact lookup by axis), with load-time
  validation mirroring the dataset's own conformance runner; loads
  scored-tree-first, else the suite-pinned verbatim snapshot
  canon/ingredient-facts/ (PROVENANCE.md records the pin at
  overhaul/ingredient-facts b0deecc).
- Per-ingredient, per-claim-axis verdicts (CLAIM_AXES): a claim clears
  only when every ingredient resolves to a facts row whose axes are
  free/allowed with valid evidence and the recomputed conflicts match
  the recorded evidence.
- Unknown name, identity without a facts row, unknown or absent axis
  state, or an absent/unloadable facts source all HOLD the claim:
  counted unchecked with a reason naming the absent or incomplete
  source — never cleared, never silently skipped. The gluten property
  is its own axis (never merged with wheat).
- The fixture alias table no longer clears claims; it only feeds R3
  doneness classification (classification_incomplete unchanged).

test_allergen_facts.py (committed red at base 9e04af4, ecb333f) now
passes 7/7: B1 tamari gluten-free held; B2 certified-GF tamari form
clears through facts; B3 cream-cheese dairy-free held with the
ingredient named; B4 absent source holds with the source named; B5
unknown-milk stock cube plus facts-row-less identity held; B6
facts-backed claim clears and disagreeing evidence held; B7 soy-sauce
gluten conflict held. suite.py --self-test: caught 13/13 planted
failures, controls 1/1 held (P2 and D2 now caught through the facts
path).

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
SamGu-NRX added a commit that referenced this pull request Oct 12, 2026
…quency

Operator ruling (PR #114 review round 2): the 257 composition-unknown
entries need no reviewed facts before merge (fail-closed is the contract),
and reviewing them is coverage work owned by FLIngredientFacts (PR #127).
This gives that task its starting order: flsub-report gains an optional
--originals flag and ranks the unknown entries by recipe-line frequency
across the bundled recipes and the originals corpus, read from
origin/overhaul/original-recipes via git show (the branch is never
checked out or pushed).

Matching rule (stated in the report): a corpus ingredient counts toward a
table entry when the table's own resolution matches it exactly,
case-insensitively, on key, display, or a recorded alias, plus the app
data's underscore-for-space fallback; occurrences are recipe ingredient
lines (required + optional), so every count is a lower bound.

All 50 bundled app ingredients resolve to reviewed facts, so the ranking
is driven by the originals corpus (401 recipes, 2829 ingredient lines,
2165 resolved to a table entry); the head of the list is salt (91),
crushed tomatoes (79), vegetable oil (43). Existing report sections stay
byte-stable; the header regenerate command gains the fetch/show and
--originals steps. Suite 54/54; two runs byte-identical (cmp).

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
…s pre-fix)

Chilli sauce is a compound with compositionComplete false and no
entry-level diet facts; all four listed components settle vegan as
allowed. Evaluating the vegan diet alone leaves every undecided
restriction on the diet axis, so the component fallback gate short-circuits
on unknownAllergens.isEmpty and returns ALLOW — even though the composition
is not known complete and an unlisted component (the brand-varying
thickeners and preservatives) could violate the diet.

Captured at head b0deecc, all three implementations fail identically:

  FAIL chilli-sauce-incomplete-vs-vegan: expected unknown, got allowed
  1 of 44 cases failed

(TypeScript runner, Python runner, and the flfacts-conformance store
harness.) The semantics fix follows in the next commit.

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>
The component fallback gate cleared every diet unknown as soon as no
allergen unknown remained (unknownAllergens.isEmpty short-circuited to
allowed), regardless of compositionComplete. An unlisted component —
chilli sauce's brand-varying thickeners and preservatives — could carry
an allergen or violate a diet, so incomplete composition must block
every clear, diets included. Clearing via components now requires
compositionComplete == true in all three implementations (Swift store,
TypeScript runner, Python runner), with the reason extended to state
it: "composition is not known to be complete; incomplete composition
clears nothing".

- worcestershire-vs-pescatarian flips allowed -> unknown: its allow rode
  the same buggy gate (component list not closed, no entry-level
  pescatarian fact).
- new direct store tests: testIncompleteCompositionBlocksDietClears
  (synthetic compound, every listed component vegan, compositionComplete
  false -> unknown) and testCompleteCompositionAllowsDietViaComponents
  (same shape with compositionComplete true -> allowed).
- package README: 33 -> 39 XCTests.

Verification at this head: swift build clean; swift test 39 tests,
0 failures; bun and Python runners 44/44 including the new
chilli-sauce-incomplete-vs-vegan case; flfacts-conformance 44/44;
negative_checks.sh all passed.

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>

@SamGu-NRX SamGu-NRX left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: BLOCK

Reviewed 163366cd4f75de253dc9c1ea81c03ed3ec6372cf against fl-root-ingredient-facts-f1 and SPEC 3.1/3.3. The head moved from aaffb5f before posting, so this review includes the joined repair. All three evaluators now require compositionComplete before component-derived clearance, covering diets as well as allergens. The chilli-sauce and revised Worcestershire cases expect unknown; the new Swift tests separately check incomplete refusal and complete-component clearance. The first previously reported blocker is resolved. No review or verdict record was posted for the superseded head.

Blockers:

  • data/ingredient-facts/tools/build_dataset.py:1006-1013,1338-1352 still declares generic doenjang complete using rice-koji while its note admits barley-koji variants. The shipped gluten fact remains free. The derivation uses carried major allergens instead of component gluten facts, losing barley/rye uncertainty. Keep variable formulations unknown and derive gluten independently.
  • build_dataset.py:283-295 still turns a generic gluten-free oats label into wheat-free evidence. The aliases include plain gluten-free oats, with no separate wheat absence evidence or named certification rule. The task requires wheat and gluten as separate axes; preserve that distinction instead of letting the gluten label clear wheat avoidance.
  • build_dataset.py:492-501,1304-1317 still treats typical peanut-butter ingredients as a complete generic composition, then generates soy/milk/tree-nut absence with a compound-composition reference. Typical brands are not product-specific absence evidence. Keep unsupported negative facts unknown.
  • build_dataset.py:1611-1623 still checks root-relative Git paths for /data/recipes/originals/. Actual paths start data/recipes/originals/, so the seven original-recipe branches contribute no ingredients. Coverage remains bundled-only. Correct the match, require the intended inputs, pin their heads and regenerate coverage.
  • The delivered #93 fix list still continues the ingredient loop on violation/unknown instead of rejecting the recipe. The #94 and #101 comments still switch evaluation objects against string cases. REST confirms all three comments remain at their original 23:22Z updates. Deliver the corrected saved fix lists to implementers.

Lesser findings:

  • data/ingredient-facts/README.md:51,60 still describes facts as an array and requires every identity to have facts, while the loader consumes an object and exempts the factless granola identity.
  • packages/FLIngredientFacts/Sources/FLIngredientFacts/Dataset.swift:192-221,249-253 still accepts the same state vocabulary on every axis. Reject diet states on allergens and allergen states on diets. Conformance entry points also silently discard unknown restriction strings.
  • Preparation synonyms still collapse cooked/raw rice and cooked/dried noodles into a single FDC identity. The new case does not change these mappings.
  • Proof/Handoff still names b0deecc and 43 cases. This head contains 44 cases and 39 Swift test methods. The older green evidence does not establish passing results for the joined repair.

Task criteria, 2/8 fully met:

  1. Canonical identities and FDC/local/preparation mappings: partly met, preparation forms collapse.
  2. Nine allergens, separate gluten and five diets: partly met, oats and gluten derivation break separation.
  3. Sourced compound composition and corpus coverage: partly met, unsupported absence and skipped originals remain.
  4. Fail-closed evaluator and meal union: met for the reviewed repair; component-derived clearance now requires complete composition in all three implementations.
  5. Shared Swift/TypeScript/Python conformance: partly met, 44 cases and aligned runners exist; the unsafe oats expectation and omitted dataset counterexamples remain.
  6. Ten accurate saved fix lists and delivered comments: partly met, three delivered corrections are missing.
  7. Passing package/conformance Proof at this head: missing, Proof still identifies the older head.
  8. Scope and ownership: met, owned data/documentation paths; no workflow changes or recipe-expression additions.

REST returned no check runs for this exact head at review time. App CI does not run this standalone package or the three conformance implementations. Static source/data and REST inspection only; no local tests, Xcode or simulator.

Generic doenjang is also produced with barley koji (mugi), which
contains gluten. The closed-composition derivation (soybeans, salt,
rice-koji) emitted gluten: free and a glutenFree diet clear on
rice-koji evidence alone, but generic doenjang carries no evidence
ruling out barley-koji production. Gluten now stays unknown via a
gluten_override (the same hook gluten-free bread uses); wheat stays
free (barley is not wheat — independent axes) and the diet
implications of the closed composition are unchanged.

Adds conformance case doenjang-vs-glutenfree (expected unknown),
which fails at 163366c on both runners (expected unknown, got
allowed) and passes after regeneration on Swift, TypeScript and
Python.

Co-authored-by: obvious-autobuild[bot] <262744130+obvious-autobuild[bot]@users.noreply.github.com>

@SamGu-NRX SamGu-NRX left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: BLOCK

Reviewed a948277dee3a6c3edcf6c6bbafb16678fe914901 against fl-root-ingredient-facts-f1 and SPEC 3.1/3.3. Read all three changed files and reused byte-identical package, runners, coverage and audit documents from the previous review. Generic doenjang now has unknown gluten/glutenFree facts and a new expected-unknown case; that specific false clearance is repaired. The complete-composition evaluator repair also remains intact.

Blockers:

  • data/ingredient-facts/tools/build_dataset.py:283-295 still gives generic "gluten-free oats" wheat-free evidence based solely on the gluten-free label. No independent wheat-absence evidence or named certification rule supports the wheat claim. The task requires separate wheat and gluten axes; the form must leave wheat unknown without its own evidence.
  • build_dataset.py:492-501,1318-1321 declares typical peanut-butter composition complete, then generates milk/soy/tree-nut absence for the generic identity. The shipped facts carry these free states, backed only by typical composition. Brand-dependent absence needs product-specific evidence; otherwise preserve unknown.
  • build_dataset.py:1607-1627 matches root-relative Git paths against /data/recipes/originals/, so paths starting data/recipes/originals/ are skipped. The seven branches listed in unchanged coverage.json contributed no ingredients. Fix the path match, require and pin the intended inputs, then regenerate coverage.
  • Delivered fix-list comments remain unsafe and differ from the corrected saved documents. #93 continues the ingredient loop on violation/unknown instead of rejecting the recipe. #94 and #101 switch evaluation objects against string cases. REST still reports their original 23:22Z updates. Deliver the corrected saved fix lists.

Lesser findings:

  • build_dataset.py:1342-1356 still derives compound gluten using carried major-allergen tokens rather than component gluten facts. The doenjang override fixes this identity but does not correct that derivation.
  • Prior loader/state-validation and preparation-mapping findings are unchanged: packages/FLIngredientFacts/Sources/FLIngredientFacts/Dataset.swift:192-221,249-253 accepts diet states on allergen axes and vice versa; conformance entry points discard unknown restriction tokens; cooked/raw rice and cooked/dried noodles still collapse into one FDC identity.
  • data/ingredient-facts/README.md:51,60 still describes an array and requires facts for every identity, unlike the object loader and factless granola exception. Proof/Handoff still cites b0deecc, 43 cases and 37 Swift tests. This head has 45 cases and the same 39 test methods as the prior repair; no fresh package/conformance Proof establishes their results.

Task criteria, 2/8 fully met:

  1. Canonical identities/FDC/local/preparation mapping: partly met, preparation forms collapse.
  2. Nine allergens, independent gluten and five diets: partly met, oats still crosses axes.
  3. Sourced compound composition and corpus coverage: partly met, unsupported absence and skipped originals remain.
  4. Fail-closed evaluator and meal union: met, all three implementations require complete composition for component-derived clearance.
  5. Shared Swift/TypeScript/Python conformance: partly met, 45 cases and aligned runners exist; unsafe oats expectations remain.
  6. Accurate saved fix lists and delivered comments: partly met, delivered corrections remain missing.
  7. Passing package/conformance Proof at this head: missing, Proof identifies the older head.
  8. Scope and ownership: met, owned data/package/documentation paths; no workflow or recipe-expression additions.

Exact-head iOS CI passed. App CI does not run this standalone package or its three conformance implementations. Static source/data and REST inspection only; no local tests, Xcode or simulator.

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.

1 participant