Skip to content
Recipe API

When an Ingredient Estimate Is Feasible but Still Wrong

Fresh Open Food Facts optimizer and evaluation changes show how food APIs should expose ingredient-percentage estimates as constrained hypotheses, with active assumptions, fallback paths, and category-level validation.

ingredientsnutritionfood-aiapi-designevaluation

A better score does not make an estimate a fact

On August 17, Open Food Facts merged an ingredient-percentage estimator change that adds useful constraints to a CVXPY optimization pipeline. Flavours and food additives are capped at 2 percent unless they are the first ingredient. Known high-salt, high-sugar, and high-fat ingredients contribute minimum amounts that cannot exceed the product's corresponding nutrition totals. A first optimization pass produces simple estimates; a second may use nutrient objectives when enough ingredient nutrition is known.

The pull request reports that average ingredient-weight difference improved from 23.71 to 23.38 for the simple algorithm and from 23.55 to 23.45 for CVXPY. Those results are encouraging, but a second fresh change explains why the aggregate is not enough. The Open Food Facts recipe-estimator metrics project merged a result-set comparison tool on August 17. It compares algorithms product by product and breaks wins and losses down by food category.

The thesis: ingredient-percentage inference should be returned as a constrained, versioned hypothesis with its active bounds and fallback path, because a lower average benchmark error can coexist with category regressions and a numerically feasible answer that is wrong for one product.

Source map and the angle this avoids

Fresh primary evidence from the last seven days:

Source Date Contribution
Open Food Facts CVXPY estimator change Opened August 14; merged August 17, 2026 Adds small-quantity and nutrient-derived constraints, a two-pass optimization path, an API option, and reported benchmark changes.
Recipe Estimator 0.4.1 release PR August 17, 2026 Packages the estimator change as version 0.4.1 rather than leaving it as an experiment on a branch.
Recipe Estimator Metrics comparison tool August 17, 2026 Adds paired product-level and category-level comparisons between two result sets.
Recipe Estimator Metrics API-wrapper fix Opened August 13; merged August 17, 2026 Updates multiple model wrappers when product input and output moved under a product envelope, showing that evaluation depends on the exact API contract.

This blog has already covered model provenance, extraction evals, nutrient validation, parser evidence, and source-backed nutrition. The repeated angle to avoid is simply “estimated fields need confidence.” The new problem is constraint observability: which evidence bounded this result, which solver path won, and where did a globally better model become worse?

Separate extraction, inference, and calculation

This estimator addresses a specific task: infer the proportions of ingredients in a packaged product from an ordered ingredient tree and nutrition facts. That is not the same as parsing 2 cups flour from a home recipe, nor is it the same as calculating nutrients from known recipe quantities.

A food API should preserve three layers:

  1. Observed evidence: ingredient-list text, declared percentages, nesting, order, and nutrition facts.
  2. Inferred composition: estimated percentage or quantity for ingredients whose amounts were not declared.
  3. Derived output: nutrition, environmental impact, processing analysis, or recipe suitability calculated from the inferred composition.

If the second layer is omitted, downstream numbers inherit false authority. A product may have a precise-looking palm-oil percentage or sugar contribution even though the amount came from one feasible solution among many. The API should never relabel that as declared composition.

The distinction also controls updates. Correcting OCR changes observed evidence. Releasing estimator 0.4.1 changes inference policy. Updating a nutrient reference changes derived output. Those events need different invalidation and explanation paths.

Constraints are evidence with scope

The fresh implementation combines several kinds of knowledge:

Constraint What it contributes Boundary to preserve
Ingredient order Relative upper and lower structure Order does not identify an exact percentage.
Additive or flavour cap A small-quantity prior encoded as a hard upper bound The implementation exempts a first ingredient because some products are the additive itself.
Salt, sugar, and fat totals Prevents selected ingredient estimates from implying more of a nutrient than the product total It depends on canonical identity and minimum-content assumptions.
Ingredient nutrient profiles Lets a second pass minimize disagreement with declared nutrition Coverage and reference-food quality vary by ingredient.
Evaporation term Allows incoming ingredient mass to differ from finished-product mass Processing behavior differs by product category.

These rules are not interchangeable. Ingredient order is direct label evidence. honey contributes at least 60 percent sugars is a model assumption in the current code. A 2 percent flavour cap is a policy boundary. Nutrient totals are observations only when their source and basis are valid.

An API that returns only estimatedPercent: 1.8 discards those distinctions. A more useful response records why the estimate is feasible:

{
  "ingredient": {"id": "ingredient:honey", "sourceSpan": "honey"},
  "compositionEstimate": {
    "value": 1.8,
    "unit": "percent",
    "status": "inferred",
    "method": "constrained_optimization",
    "modelVersion": "recipe-estimator-0.4.1",
    "solverStatus": "optimal",
    "activeConstraints": [
      {"type": "ingredient_order", "source": "package_label"},
      {"type": "minimum_sugar_fraction", "value": 0.6, "source": "model_policy"},
      {"type": "product_sugars_upper_bound", "source": "nutrition_facts"}
    ],
    "selection": {"path": "nutrient_pass", "fallbackUsed": false}
  }
}

The values are illustrative. The contract is not: direct evidence, assumptions, model version, and solver behavior should remain distinguishable.

Feasible does not mean identified

An optimizer can satisfy every constraint while the underlying problem remains underdetermined. Imagine a product listing tomatoes, water, oil, sugar, salt, and flavouring. Several combinations may preserve ingredient order, stay under the sugar and fat totals, and fit the available nutrient references nearly equally well.

Returning one point estimate hides that multiplicity. Where practical, an inference API should provide a range or sensitivity signal:

  • minimum and maximum feasible percentage under the current constraints;
  • whether the selected value sits on an active bound;
  • alternative solutions within a defined objective tolerance;
  • the change caused by removing one uncertain constraint;
  • the share of ingredient mass lacking a usable nutrition mapping.

Exact feasible ranges can require additional solves and increase latency. The estimator code itself notes the performance cost of rerunning optimization for ingredient minima and maxima. That creates a legitimate product trade-off. A synchronous lookup may return a point estimate plus diagnostics; an asynchronous audit endpoint can calculate intervals for high-impact products. The wrong compromise is to omit uncertainty because computing it is expensive.

Fallback is part of the result

The new CVXPY flow first solves against simple, order-derived objectives. It may then run a nutrient-driven pass when unknown ingredient coverage is low enough and nutrient information is available. A high nutrient-variance result can leave the simple solution as the final output. The API also gained a use_simple_estimates option.

Those branches can produce valid responses with different epistemic quality. Clients should not have to infer the path from missing debug fields. Return a stable state such as:

State Meaning Safe product use
declared Percentage came from source data Display and calculation with source provenance.
nutrient_constrained Nutrient optimization passed acceptance checks Estimation features with visible model metadata.
order_constrained_fallback Simple constrained solution was selected Broad analysis; avoid precise consumer claims.
insufficient_coverage Too much ingredient nutrition was unknown Return bounds or no estimate, depending on policy.
infeasible Evidence and constraints could not be satisfied together Surface a data-quality conflict; never substitute zero.
solver_error Optimization failed operationally Retry or degrade without presenting a composition claim.

Method controls should be explicit capabilities, not undocumented booleans. If a client can force the simple path, the response should echo the applied mode and model version. Caches must include those fields in their key.

Evaluate paired changes, then slice them

The reported average improvements show why benchmarking matters. The fresh comparison tool adds the more important operational view: for the same products present in both result sets, count where A wins, where B wins, and where they tie; then aggregate differences by category and retain a product-level comparison file.

That design catches a common model-release failure. A change can improve the overall mean by fixing many easy products while seriously regressing a smaller category such as concentrated sauces, confectionery, dehydrated foods, or products with nested sub-ingredients. Category slicing turns “better on average” into a review queue.

API teams should extend that framework with slices tied to failure mechanisms:

  • complete versus partial ingredient-to-nutrient mapping;
  • flat versus nested ingredient lists;
  • declared percentages present versus fully inferred products;
  • high versus low nutrition completeness;
  • products with evaporation or reconstitution;
  • locales and label grammars;
  • products where an additive or nutrient bound is active;
  • simple fallback versus accepted nutrient pass.

Also measure constraint violations separately from percentage error. A model can reduce absolute error while producing more impossible nutrient totals. Conversely, a stricter model may slightly worsen a point metric while eliminating outputs that violate source evidence. Product decisions need both measures.

Release checklist for composition inference

Before publishing ingredient-percentage estimates through a recipe, nutrition, or food-data API, verify that you can:

  • preserve declared percentages separately from inferred values;
  • identify every active hard bound, soft objective, and model assumption;
  • return solver, fallback, infeasible, and insufficient-coverage states;
  • pin outputs to estimator, taxonomy, and nutrient-dataset versions;
  • expose the nutrition basis used to constrain composition;
  • keep product-input mass separate from finished-product mass where processing matters;
  • compare candidate models on the same product set;
  • inspect regressions by category, locale, nesting, coverage, and active constraint;
  • report evidence violations as well as average percentage error;
  • invalidate derived nutrition and sustainability results when inference changes;
  • offer an audit path for feasible ranges or sensitivity analysis;
  • prevent a polished point estimate from being presented as a declared formulation.

The useful signal from this week's work is not that constrained optimization has solved hidden recipes. It is that ingredient estimation is becoming testable engineering infrastructure: versioned releases, explicit solver paths, paired result comparisons, and category slices. Recipe API builders should carry that discipline into the public contract. The customer needs the estimate, but they also need to know what made it possible—and what could still make it wrong.

Sources

Start Building

One consistent schema on every response. Get a free key and ship in minutes.