emealia docs · internal · concept 2026-09-09

Barcode input and AI-assisted nutrition research

A concept for identifying packaged foods in emealia without owning a product database

Working paper · Version 1.1 · 2026-08-31 · Status: proposal for founder decision — nothing built, nothing planned in the tracker

Changes in v1.1. Version 1.0 recommended photographing the nutrition panel as the primary source of nutrition data. The founder rejected this on the grounds that it adds user effort. That objection is accepted and the recommendation is withdrawn; §5.2 now records the decision, including a correction to two supporting premises that do not survive checking. The load-bearing elements consequently shift to pre-seeding (§7) and the curator gate (§6), and §10 notes which risks grow as a result.

Abstract

emealia estimates nutrition from free text. For packaged, branded food this is the weakest case: the product has an exact, printed, legally mandated nutrition panel, and the app answers with a wide estimated range derived from a category average. A barcode scan promises to close that gap. This paper examines whether it can, and at what cost.

The central finding is that a barcode is only an identifier. It carries no nutrition data whatsoever. Nutrition appears only if that identifier is resolved against a product database, and the databases with adequate German coverage are either share-alike licensed (Open Food Facts, ODbL), commercially restricted from permanent storage, or absent. The founder has ruled out any construction that would place emealia's own database under a share-alike obligation. That constraint, rather than any technical difficulty, defines the design space.

We examine whether a large language model with web search can substitute for a product database. Our assessment is that it cannot resolve identity — search engines index product names, not barcodes — but can reliably complete a nutrition panel once identity is known, subject to a verification layer that emealia must build and must not delegate to the model. We separate what AI demonstrably does well here (reading a photographed label, triaging sources, extracting structured panels, classifying to a category) from what it does not (knowing which regional or reformulated variant a barcode refers to, and signalling its own uncertainty on numeric output in a calibrated way).

The recommended architecture places no additional burden on the user beyond the scan itself. A resolved scan costs nothing and asks nothing; an unresolved one triggers a one-time, cached research call whose result is verified by a human before it reaches anyone. Photographing the nutrition panel — reliable and cheap, and recommended in version 1.0 of this paper — is withdrawn as a user-facing step because it violates the ease promise, and is relocated to the curator's toolkit (§5.2). A deterministic validator — Atwater consistency, mass closure, serving arithmetic, category plausibility, and multi-source agreement — is the actual source of reliability. Automatic promotion of nutrient values into emealia's own catalogue is rejected outright; a human verification gate is retained, with AI research repositioned to make that gate roughly an order of magnitude faster rather than to bypass it.

Finally we address cold start. Branded consumption is strongly head-concentrated, so the catalogue should be pre-seeded before launch rather than discovered by early users. We assess the founder's proposal to perform this pre-seeding through a paid AI chat interface instead of the API, conclude that it is sound for the first several hundred products and materially cheaper, and specify the reproducibility discipline it requires — a discipline this project has already been burned by omitting once.

Contents

1Motivation and scope

1.1 The specific failure this addresses

emealia's honesty promise is that estimates are ranges, not numbers, because the underlying uncertainty is real. For a home-cooked meal described in free text, this is not merely defensible but correct: nobody knows how much oil went into the pan.

Packaged food is different in kind. The manufacturer has measured the product and is legally obliged to print the result. When a user logs "a Milka bar" and emealia returns a range derived from a generic milk-chocolate composite, the app is being less precise than the information physically present in the user's hand. That is not honest uncertainty; it is avoidable ignorance, and users perceive the difference.

The scope of this paper is therefore narrow: identifying a specific packaged product and obtaining its declared nutrition panel. It does not address photo-based meal recognition, restaurant dishes, or any change to how free-text meals are estimated.

1.2 The constraint that shapes everything

Non-negotiable #4 states that AI free-text logging is the only primary input, and that a barcode scanner may not be the primary input. This paper accepts that constraint without argument. Everything below describes a secondary affordance located inside the add-meal screen, alongside the existing "From history" chips — a shortcut for a specific case, never the main path, never a navigation-level entry point.

This is not a formality. Barcode scanning is the interaction that most strongly pulls a nutrition app back toward being a calorie counter, because it makes exactness feel available and therefore expected. The design rules in §8.4 exist to hold that line.

2What a barcode actually is

2.1 The payload

A barcode on food packaging encodes a GTIN (Global Trade Item Number): thirteen digits in Europe (EAN-13), twelve in North America (UPC-A). That is the entire payload. It is an identifier allocated through GS1 to a brand owner. It contains no nutritional, ingredient, or portion information, and no structured description of the product.

Client-side decoding is a solved, free problem:

ToolLicenceNotes
BarcodeDetector Web APInativeChromium-based browsers on Android and desktop. Not Safari, not Firefox.
@zxing/library (ZXing-js)MITWebAssembly fallback for Safari and Firefox. Roughly 150–250 KB added to the bundle.
html5-qrcode, quagga2Apache-2.0 / MITEquivalent alternatives.

None of these read the printed nutrition table. That is optical character recognition, a separate capability discussed in §5.

2.2 What a database lookup returns

Because the barcode carries nothing, nutrition comes from resolving the GTIN against a product database. What such a database holds is, at best, the legally mandated declaration — because that is what the manufacturer was required to publish.

European Union, Regulation (EU) No 1169/2011: energy (in both kJ and kcal), fat, of which saturates, carbohydrate, of which sugars, protein, and salt — expressed per 100 g or 100 ml. Fibre is voluntary. Vitamins and minerals appear only where the manufacturer makes a nutrition or health claim.

United States, FDA Nutrition Facts panel: calories, total fat, saturated fat, trans fat, cholesterol, sodium, total carbohydrate, dietary fibre, total sugars, added sugars, protein, and four micronutrients — vitamin D, calcium, iron, potassium.

Two consequences follow, both material:

  1. A European label yields roughly eight values and no micronutrients. emealia tracks approximately thirty-two. The gap is not marginal; for EU products it is most of the profile.
  2. The two regimes are not directly comparable. EU "carbohydrate" is declared excluding fibre; US "total carbohydrate" includes it. Mixing sources without normalising this silently corrupts both the carbohydrate value and any energy cross-check computed from it. This is, in our assessment, the single most likely source of systematic error in any multi-source pipeline.

2.3 Candidate resolvers

SourceCostCoverageConstraint
Open Food FactsFree API; full dump self-hostable~3M products, strong DE/FR, improving USODbL share-alike (§4). Crowd-sourced; completeness and accuracy vary.
USDA FoodData Central, Branded FoodsFree with API key~1.5M items, US onlyPublic domain. Already used in this codebase (integrations/ingredient_sources/fdc.py).
Nutritionix, Edamam, FatSecret, Chomp, Barcode Lookup~$100–500/month tiers, or ~$0.008–0.02 per lookupGood US branded coverage, normalised panels, SLATerms typically prohibit permanent local storage or redistribution — structurally incompatible with building an owned catalogue.
GS1 GEPIRFreeGlobalReturns the brand owner only. No product name, no nutrition.

The commercial options are usable as a live display fallback but cannot feed a permanent catalogue, which is the stated goal. The public-domain option is US-only. The one source with genuine German coverage is the one whose licence the founder has excluded. §4 addresses this directly.

3What AI can and cannot do here

This section is deliberately blunt, because the entire proposal depends on being right about it.

3.1 What it does well

Reading a photographed nutrition panel. Current vision models transcribe printed tabular text with high accuracy. A nutrition panel is a small, high-contrast, highly structured table with a fixed vocabulary and predictable units. This is close to the easiest case in document understanding. The capability is real and cheap (§5.2), but for product reasons it is not used in the logging flow.

Formulating search queries and triaging sources. Given a brand and product name, a model reliably constructs sensible queries, recognises a manufacturer's own product page as more authoritative than an aggregator, and notices when a page describes a different pack size or variant.

Extracting a structured panel from an unstructured page. Given a retrieved page containing a nutrition table in prose, HTML, or a PDF, extraction into a schema is reliable.

Classifying a product to a category. Mapping "Milka Alpenmilch" to a milk-chocolate composite is straightforward and directly reusable against the taxonomy composites already built in Epic 29.

3.2 What it cannot do

Resolve a barcode to a product. This is the structural limitation, and it is not a capability gap that improves with a better model. Search engines index product names, not GTINs. A query consisting of a bare thirteen-digit number returns either nothing useful or barcode-aggregator sites, many of which are themselves scraped mirrors of Open Food Facts and retailer pages. Identity requires a registry. AI research does not remove the resolver dependency; it removes only the requirement that the resolver be nutritionally complete.

Distinguish regional and temporal variants. The same brand and product name denotes materially different recipes across markets, and recipes are reformulated over time. A retrieved page may describe the US formulation, or the 2021 formulation, with no textual signal distinguishing it. The GTIN would disambiguate — but the GTIN-to-variant mapping is precisely what the open web does not carry. In our assessment this is the dominant residual error class after all other mitigations, and it cannot be fully eliminated by web research.

Signal its own uncertainty on numeric output in a calibrated way. Asked for a nutrition panel it cannot find, a model will generally produce a plausible one. The output is structurally indistinguishable from a correct one: no syntax error, no internal contradiction, no refusal. Nutrition values are an unusually adverse target for this failure mode, because the user cannot verify them — the inability to verify is the entire reason the feature exists — and because the domain is health-adjacent. There is no compiler here.

Perform arithmetic reliably enough to be its own auditor. A model asked to check its own energy-versus-macronutrient consistency will often do so correctly and occasionally will not. Consistency checks must be executed in code.

3.3 The design principle that follows

The model proposes; deterministic code disposes.

Every numeric value the model produces is a candidate. Whether it is admitted is decided by validators written in Python, running against arithmetic and physical constraints that do not depend on the model being right. This is the same separation of concerns the codebase already applies elsewhere: generate generically, judge by explicit rule.

4The Open Food Facts problem

4.1 The obligation

Open Food Facts is licensed under the Open Database License (ODbL) v1.0; record contents fall under the Database Contents License, and images under CC-BY-SA. The obligations relevant here, stated by name rather than by section number (exact subsection references should be confirmed by counsel before being relied upon):

Serving data to end users through an application constitutes public use.

The distinction that matters is between a fact and a database. A human reading a value and typing it elsewhere is using a fact; facts are not protected by copyright. Systematically accumulating many records into a store that is then served to users is building and publicly using a derivative database, which triggers share-alike. In the European Union this is reinforced by the sui generis database right under Directive 96/9/EC, which protects substantial investment in obtaining, verifying, and presenting a database's contents against extraction or reutilisation of a substantial part.

4.2 The laundering trap

It must be stated explicitly, because it is the most likely way this constraint gets violated by accident:

Routing Open Food Facts data through a language model does not remove the licence. If web search retrieves an openfoodfacts.org page and the model transcribes its values into emealia's catalogue, the result is a derivative database assembled by a different mechanism. "An AI read it" is not a laundering step, and systematic extraction is exactly what the sui generis right addresses.

4.3 Three options

Option A — runtime dual database (collective-database construction). Open Food Facts derived rows live in a physically separate store, kept under ODbL, attributed, and made available; emealia's own catalogue is queried first, the ODbL compartment only on a miss, and rows never cross between them. Legally arguable but grey — "merged" is not exhaustively defined, and the ODbL compartment is still being publicly used and so must itself be published. Operationally it means a second store: either a live external dependency on the request path, with its latency and availability risk, or a self-hosted dump measured in tens of gigabytes with a recurring refresh job. Cost falls only on the cache-miss path, but it is real infrastructure. Requires counsel sign-off.

Option B — curator-only reference. Open Food Facts never appears on the request path. It is a reference source a human curator may consult while verifying a product; what is written into emealia's catalogue is transcribed from the packaging and recorded as packaging-sourced. No derivative database is created, no share-alike obligation arises, and runtime cost is zero. The limit is human throughput.

Option C — exclusion. Open Food Facts is not used at all. US coverage comes from FoodData Central; everything else from curator-verified research (§5.3, §6.2).

4.4 Enforcing the decision technically

Whichever option is chosen, the exclusion should be mechanically enforced and auditable, not left to reviewer discipline. The web search tool accepts either an allowed_domains allowlist or a blocked_domains blocklist (supplying both is rejected). Two complementary controls:

  1. Per request — an allowed_domains allowlist of manufacturer and retailer domains for any research call whose output is eligible for promotion. An allowlist proves exclusion rather than merely attempting it, and simultaneously raises source quality. Its cost is reduced coverage of long-tail brands, so a wider blocklist-based call may serve the display-only path.
  2. Organisation-wide — the Claude Console permits an administrator to restrict which domains web search may reach for Messages API requests. Setting the exclusion there places it above the application code, where a single careless change cannot undo it.

Note that store brands (Ja!, Beste Wahl, Great Value) have essentially no web presence outside the retailer's own product page. For these, the retailer is the authoritative source, which is an argument for including major retailers in the allowlist.

5The proposed architecture

5.1 Separating identity from nutrition

The two questions a scan raises are independent and should be answered by different mechanisms:

QuestionBest mechanismFallback
Which product is this?emealia's own catalogue (GTIN hit)FoodData Central (US); user confirms a name; user types it
What is in it?emealia's own catalogue (verified row)Public-domain dataset; one-time web research; labelled category composite
How much was eaten?The user— (no automated answer exists)

Recognising that identity and nutrition are separable is what makes the licensing constraint tractable: the sources with clean licences are adequate for identity plus a starting point, and the nutrition values are then obtained, once per product, by a path emealia controls.

Note what this implies. Because every nutrition answer now comes from emealia's own side of the system rather than from anything the user supplies, the quality of the catalogue is the quality of the feature. Pre-seeding (§7) and the curator gate (§6) carry the weight that version 1.0 of this paper distributed onto the user.

5.2 Packaging capture: assessed and rejected as a user-facing step

Version 1.0 of this paper recommended asking the user for a second frame — a photograph of the nutrition panel — whenever an unknown product was scanned. That recommendation is withdrawn. Because the reasoning matters more than the conclusion, and because two of the supporting premises do not survive checking, the decision is recorded here in full rather than silently removed.

The objection that decides it. emealia's first promise is easy: one sentence, no weighing, no database hunting. A second capture step, however well framed, is additional user effort in the primary path — and for an empty catalogue it would be effectively mandatory rather than optional, because declining would mean a visibly worse result. An app whose stated philosophy is that it does the work silently cannot ask its users to photograph packaging so that it can learn. This objection is sufficient on its own, and it is accepted.

Premise that does not hold: cost. Photographing a panel is cheaper than researching it on the web, by roughly an order of magnitude. A nutrition-panel image consumes on the order of 1,000–1,500 input tokens; with prompt and structured output the whole call is approximately $0.02. A web research call is 3–5 searches at $10 per 1,000 plus 20–30k input tokens of retrieved page content, approximately $0.10–0.25 (§9). The relevant comparison is not photo-versus-barcode — a barcode decode is free but yields no nutrition at all — but photo-versus-research, and vision wins it. Withdrawing the recommendation therefore costs slightly more per unknown product, not less. This does not change the decision; it changes what the decision is being traded for.

Premise that holds only in part: error-proneness. Two different things are being compared, and they separate cleanly.

Capture reliability — the user's point is correct, and stronger than it may appear. EAN-13 and UPC-A carry a check digit, so a successful decode is not merely usually right but arithmetically self-verifying; a misread fails to decode rather than decoding wrongly. Photography has no such property and fails often in ordinary conditions: glare on foil, curvature on bottles and cans, low kitchen light, blur, and cropped columns.

Accuracy of the resulting values — here the ranking inverts. A successfully captured panel is the product's own declaration, and any transcription error is detectable: a decimal slip from 29.5 to 295 fails the Atwater and mass-closure checks immediately (§5.4). Web research produces the opposite failure mode — internally consistent values belonging to the wrong regional or reformulated variant, which pass every arithmetic check and are therefore invisible. Photography fails loudly; research fails silently.

Where packaging capture survives. Not in the logging flow, but in two places where it burdens nobody:

  1. As the curator's primary tool. The curator verifying a candidate row is holding the package, by design. Photographing the panel is exactly what that role does, and it remains the highest-accuracy, lowest-legal-exposure way to establish a value (§6.2). This preserves the entire benefit for the catalogue while removing it from the user's path.
  2. As a dead-end escape hatch, never prompted. Where identity resolution has already failed and the user is being offered the free-text fallback anyway, an unobtrusive "or show us the label" costs nothing to display and is chosen only by users who want to. It must never appear on the happy path, never block, and never be framed as expected. Whether it appears at all is left open (§12, decision 9).

Consequence. With no user-side disambiguator, variant ambiguity — already identified as the dominant residual error class (§3.2) — loses its cleanest mitigation. The compensating controls are market-scoped research (locale hint, market-specific retailer allowlist, page_age filtering), and, decisively, the human gate: the curator becomes the disambiguator. This makes §6 and §7 more load-bearing than in version 1.0, not less, and raises rather than lowers the importance of the calibration gate in §10.2.

5.3 Web research as a declarative call

No agent framework is required. Web search is an Anthropic-hosted server tool: it is declared in the request, searches execute server-side within a single call, and results return as content blocks with citations. In BCE terms this is one method behind one boundary.

tools=[{
    "type": "web_search_20260318",
    "name": "web_search",
    "max_uses": 5,
    "allowed_domains": [...],          # or blocked_domains — never both
    "user_location": {"type": "approximate", "country": "DE"},
}]

Practical notes, all verified against current API documentation:

Model choice. This is a once-per-product, cached-permanently, off-the-critical-path call. Per-meal economics do not apply, so the usual argument for a smaller model dissolves; and the work — query formulation, source triage, variant scepticism — is exactly where capability differences appear. A frontier model with adaptive thinking is appropriate.

Privacy. The query leaves emealia's infrastructure. It must therefore be constructed only from product-derived fields — brand, product name, GTIN, net weight — and never from meal free text or any user or session identifier. Research jobs should be queued by GTIN rather than by user, which enforces this structurally and provides free deduplication when many users scan the same product.

5.4 The validation layer

Reliability comes from here, not from the model. Every candidate panel, whatever its source, passes deterministic checks before it may be stored or promoted:

CheckRule
Energy consistency (Atwater)Declared energy must agree within a tolerance (~10%) with the value computed from macronutrients using the regulated conversion factors — protein 4, carbohydrate 4, fat 9, fibre 2, alcohol 7, polyols 2.4 kcal/g. Fibre convention must be normalised first (§2.2).
kJ/kcal coherenceWhere both are declared, their ratio must approximate 4.184. A free integrity test on any source giving both.
Mass closureFat + carbohydrate + protein + fibre + salt must not exceed 100 g per 100 g.
Serving arithmeticPer-serving values × servings per container must approximate per-100 g values × net weight ÷ 100.
Category plausibilityValues must fall within a tolerance band of the matching Epic 29 taxonomy composite. Over 280 real composites already exist; this is a direct reuse.
Source quorumAt least two independent domains must agree within tolerance before a value is eligible for promotion.

The last row deserves comment, because it resolves an earlier dead end. An initial sketch of this feature proposed promoting products after N user confirmations. That mechanism does not work: a user tapping Save has confirmed that they ate the product, not that they checked its numbers against the package. Silence is not agreement, and stacking three silent saves does not make one unverified value three times more trustworthy. Worse, pre-filling a second user's form with the first user's values builds confirmation bias into the mechanism, while leaving it blank means the gate effectively never opens.

The quorum idea survives; the electorate changes. Replacing uninformed users with independent published sources makes the vote informed, immediate, and cheap.

6Promotion and the human gate

6.1 Automatic promotion is rejected

No crowd or model signal identified in this analysis is strong enough to justify writing a nutrient value into emealia's shared catalogue without human verification. A promoted row is emealia asserting a health-adjacent fact to every future user who scans that product; the blast radius of a wrong row is the entire user base, indefinitely.

6.2 What replaces it

A prioritised curator queue. Unknown and low-confidence products accumulate as candidates, ranked by scan volume and by correction rate. Volume is a prioritisation signal — it tells the curator where their minutes are worth most — not an authorisation signal.

Human verification, sufficient at one occurrence. An administrative view presents the decoded GTIN, the resolved identity, the researched candidate panel, its cited sources, and any validator warnings. The curator checks against the physical package — photographing the panel is the curator's own tool here (§5.2) — and promotes. One occurrence suffices because a human read a label. The row records who verified it and from what.

AI research repositioned. Its purpose is not to bypass the gate but to make it fast. Without it, the curator researches a product from scratch — roughly ten minutes. With it, they verify a pre-filled panel against three cited sources and a validator report — roughly thirty seconds. That is the actual value proposition: not automation of the judgement, but automation of the legwork.

Bulk import as curator work. Importing the public-domain FoodData Central branded dataset is the same act performed in batch: human-initiated, provenanced, reproducible, and not dependent on per-product vote counting.

6.3 Provenance is mandatory

Every catalogue row records its source class (packaging, public-domain dataset, research, composite), who verified it, when, and against what evidence. This is not bureaucratic. This project has already been bitten by its absence: the Epic 29 taxonomy composites were produced in a session whose working files were not committed, and are consequently unreproducible. That lesson applies directly here and is the reason §7.4 is written as strictly as it is.

7Cold start and pre-seeding

7.1 The problem, stated fairly

The concern is legitimate and should not be minimised: the first user to scan any given product gets whatever the system can produce with no catalogue entry, while every later user gets a verified value. If most early scans are of unknown products — which they will be, since the catalogue starts empty — then early users systematically receive the worst experience, at exactly the moment when trust is being established.

7.2 The structural answer: do not wait for users

Branded consumption is strongly head-concentrated. A few hundred products account for a large share of everyday scans in any given market. The catalogue should therefore be populated before launch, converting cold start from a user-facing problem into a one-off preparation task.

A pre-seed of roughly 500 German and 500 US products, verified and promoted, would plausibly cover the substantial majority of early scans. The remaining tail is then low-volume, which is precisely the regime where per-product research cost and curator time are affordable.

7.3 Pre-seeding through a chat interface rather than the API

The founder's proposal is to perform this pre-seeding through a paid AI chat subscription rather than paid API calls. This is sound, and we recommend it for the head of the catalogue — with specific caveats.

Why it works. The underlying capability is the same; web search in the chat product retrieves the same web. What differs is orchestration and guarantees, not intelligence. Under a flat-rate subscription the marginal cost of a product is zero, against roughly $0.10–0.25 per product via the API. For several hundred products the saving is real. More importantly, the pre-seed is exactly the phase where a human should be reading every row anyway — and a chat interface puts the human in the loop by construction, where an API pipeline would place them at the end of it. The prompt can be corrected mid-session when a systematic error appears; an API batch surfaces the same error only after it has been made five hundred times.

Honest limitations.

7.4 The reproducibility discipline (non-optional)

A chat session is ephemeral. If the dataset exists only as its output, the project acquires another unreproducible artefact of exactly the kind it already regrets. The mitigation is to make the artefacts reproducible even though the generation is not:

  1. The prompt is a committed file, versioned like any other prompt in prompts/.
  2. The output is a committed data file — JSONL or CSV, one row per product, with an explicit schema including source URLs per value.
  3. The importer is a committed script that reads that file, runs the validators, and writes to the database. Re-running it must reproduce the same database state from the same file.
  4. The validation report is committed alongside, recording what passed, what failed, and what was overridden by hand.
  5. Every row carries provenance — source class, source URLs, curator, date.

With these five artefacts, the dataset is reproducible from the repository even though the chat session that produced it is gone. Without them, it is not, and it should not be merged.

7.5 The hybrid recommendation

8How this fits — and slightly alters — the current flow

8.1 What does not change

The draft-to-save lifecycle, the asynchronous contract, the estimate representation, and the entire daily view are untouched. POST /meals still returns 202 with a draft; clients still poll; POST /meals/{id}/save still commits. Bands still describe a day and numbers still describe a meal. Nothing about a scan appears on the daily view.

8.2 What changes

A secondary affordance on the add-meal screen. A scan entry point sits alongside the existing "From history" chips — a shortcut within the add-meal flow, not a replacement for the text field and not a navigation-level destination.

An existing status value finally gets used. The meal status enum already contains needs_user_confirmation alongside pending, completed, and failed. A scan produces exactly this state: this appears to be Milka Alpenmilch — is that right, and how much did you have? No contract change is required.

Scanned products become structured meal metadata. The meals.products JSONB column and meals.portion_size, both added by the existing portion/products migration, already hold an ingredient-shaped breakdown. A scanned entry is one more item in that list, distinguished by provenance:

{
  "source": "barcode",
  "gtin": "4008400202037",
  "brand": "Milka",
  "name_de": "Milka Alpenmilch",
  "amount": { "value": 25, "unit": "g" },
  "per_100g": { "energy_kcal": 530, "fat": 29.5, "carbs": 59, "protein": 6.6, "salt": 0.28 },
  "nutrient_source": "catalogue",
  "micro_fill": "composite:milk-chocolate-bar",
  "sources": ["https://www.milka.de/..."]
}

nutrient_source is one of catalogue (a verified row), public_dataset, research (unverified, pending curation), or composite (labelled category fallback). It drives the provenance line below.

Free text remains, and remains optional. The text field is not the carrier of a scanned product's nutrition. It may be pre-filled with the product name as a convenience so the user can extend it — "Milka Alpenmilch, 25 g" → "…and a coffee with oat milk" — and the meal's estimate is then composed of the scanned segment (a narrow range) and the AI-estimated remainder, with uncertainties aggregating quadratically as they already do.

A pure-scan meal makes no AI estimation call. Where every segment resolves to a known product, no estimate is needed.

Research runs inside the draft window. A research job takes tens of seconds — incompatible with a synchronous flow, but the draft is explicitly a pre-save preview in which nothing is committed. A scan therefore creates a draft with a provisional estimate, research completes, and the draft is upgraded in place before the user taps Save. A barcode scan is also the one interaction where a brief lookup indicator matches user expectation rather than violating it.

If research completes after the meal is saved, the logged meal is not silently rewritten. The result benefits future users only. Quietly altering a value a user has already accepted would trade a small accuracy gain for a large trust loss.

A provenance line appears on the meal detail. "Verified product", "Researched — 2 sources", "Typical for this kind of product". This is technical status, shown transparently, and it is what makes a composite fallback honest rather than misleading.

Nothing else is asked of the user. The complete interaction is: point the camera, confirm the product, say how much. No second capture, no correction prompt, no request to help improve the database. Where emealia does not know a product, that is emealia's problem to solve between sessions (§6, §7) — not a task delegated to the person trying to log lunch.

8.3 A dissent on the composite fallback

The founder's position has been that emealia should not fall back to a category composite for an explicitly branded or scanned food. We suggest a narrower rule:

Never present composite data as if it were the branded product's own data.

Labelled honestly — "We don't know this exact product yet. This is a typical milk chocolate bar." — a composite is more useful than an error and sits squarely inside non-negotiable #6, which explicitly permits transparent technical status. An outright error state is a failure state, which that non-negotiable forbids.

The genuine exception is identity failure. If the GTIN cannot be resolved to any product at all, then "We couldn't identify this one — want to type it instead?" is correct, because that is a recoverable identity problem the user can immediately solve, not a nutrition verdict rendered upon their meal.

8.4 Compliance with the six non-negotiables

#RequirementAssessment
1No red in nutrition feedbackProvenance chips use muted and accent tokens only. No new colours; no state rendered as warning. Holds.
2No numbers on the daily viewScanning changes nothing about the daily view. Holds.
3Free trial, core loop never gatedScanning is not separately gated. A pure-scan meal invokes no AI estimation and should therefore not consume a trial credit, since credits are defined as free AI estimates. Open decision, §12.
4AI free text is the only primary inputUnder genuine pressure. Held only by explicit design rule: secondary affordance inside add-meal, never a primary CTA, never a navigation destination, never the default focus.
5Value before registrationScanning requires registration; the pre-signup demo is untouched. Holds.
6No state may look like a failureProvenance labelling is transparent technical status, which this non-negotiable expressly permits. Holds, and §8.3 depends on it.

9Cost

Per product researched via the API, at current published rates ($10 per 1,000 web searches; frontier-model tokens at $5/M input and $25/M output):

ComponentEstimate
5 searches$0.05
~20–30k input tokens (retrieved content)$0.10–0.15
~2k output tokens$0.05
Total per new product≈ $0.10–0.25

Dynamic filtering — available on current search tool versions with current models — reduces the input side by filtering results in code before they enter the context window.

For comparison, and because the point is counter-intuitive (§5.2), extracting a panel from a photograph is roughly an order of magnitude cheaper: a nutrition-panel image is on the order of 1,000–1,500 input tokens, so prompt, image, and structured output together come to approximately $0.02. Withdrawing user-side capture therefore raises the marginal cost per unknown product. Curator-side capture recovers this saving for every product a curator handles physically.

Costs of the paths that are not research: a catalogue hit, a cached lookup, and a labelled composite fallback are all $0.00 and involve no external call. Since the catalogue is intended to serve the substantial majority of scans (§7.2), the expected cost per scan in steady state approaches zero.

Pre-seeding 1,000 products via API would therefore cost roughly $100–250, halved on token cost via the Batch API (searches are billed identically in batch, and batches containing many searches are throttled, so they must be run days ahead). Via the chat subscription the marginal cost is zero against roughly eight hours of founder time, which is the recommended path for the head.

Build effort, as a rough order of magnitude, assuming stories of five points or fewer:

ComponentEstimate
Product lookup boundary, FoodData Central adapter, lookup cache, migration~5 SP
Frontend scanner (camera, permissions, decoder + fallback, i18n, accessibility)~5 SP
Curator-side panel capture (photo → panel extraction → confirmation), admin-only~3 SP
Scanned product as meal metadata; estimate composition; zero-AI scan path~5 SP
Research boundary + adapter + validators~5 SP
Catalogue and candidate tables, curator verification view, importer~5 SP
Rate limiting, abuse guard, consent copy, processor documentation~3 SP
Total~33 SP — a small epic

Ongoing: FoodData Central is free; research cost scales with genuinely new products and decays as the catalogue fills; storage is negligible relative to meal data. Legal review of the chosen sourcing option, and processor documentation for any new external dependency, are one-off but non-trivial.

10Limitations and a proposed calibration gate

10.1 What this does not solve

10.2 The gate

This proposal should not be adopted on the strength of argument. It should be measured, using the pattern this project has already applied successfully: the production-evaluation harness that ran 162 real tester meals and surfaced six defects.

Proposed calibration exercise. Take fifty real German packaged products — physically present, spanning national brands, store brands, and known regional variants. For each, run the research path and compare the result against the actual printed panel. Report:

  1. accuracy per source class (national brand / store brand / variant-ambiguous);
  2. the validator false-pass rate — candidates that were wrong and passed anyway;
  3. the validator false-fail rate — candidates that were right and were rejected;
  4. the proportion for which no acceptable source was found at all.

This yields a defensible number rather than an intuition, and it doubles as the first tranche of the pre-seed (§7.5).

Our prior, stated so it can be falsified: high accuracy on nationally advertised brands with genuine product pages; sharply degrading accuracy on store brands and reformulated items; and a validator that catches gross unit errors reliably while catching plausible-but-wrong variant substitutions poorly. We would not ship on that prior, and neither should this project.

11Recommendation

  1. Confirm the framing. A secondary affordance inside add-meal; structured metadata on the meal; ranges and bands unchanged; the design rules of §8.4 written down before any UI work begins.
  2. Ask nothing of the user beyond the scan. Nutrition comes from the catalogue, a public-domain dataset, a one-time research call, or a labelled composite — never from a second capture step. Packaging capture is retained as a curator tool and, optionally, as a never-prompted dead-end escape (§5.2).
  3. Adopt curator-only Open Food Facts (Option B) for German coverage, enforced technically by an allowlist at request level and by the organisation-wide domain restriction at Console level. Revisit the runtime dual database only if curator throughput proves inadequate, and only with counsel sign-off.
  4. Reject automatic promotion of nutrient values. Retain a human verification gate, sufficient at one occurrence, and use AI research to make that gate roughly an order of magnitude faster.
  5. Build the deterministic validators before the research path, and never delegate arithmetic to the model.
  6. Pre-seed the head of the catalogue through the chat subscription, under the five-artefact reproducibility discipline of §7.4, and treat the first fifty products as the calibration exercise of §10.2.
  7. Run the calibration gate before any researched value reaches a user.
  8. Sequence this after the Epic 29 branded-food track settles, as its own epic. There is a real dependency: the taxonomy composites are what make both the category-plausibility validator and the honest composite fallback possible.

12Open decisions

#DecisionRecommendation
1Is packaged-food identification worth the pull toward exactness?Yes, if and only if the §8.4 design rules are binding.
2German sourcing: dual database, curator-only, or exclusion?Curator-only (Option B).
3Does a pure-scan meal consume a trial credit?No — credits are defined as free AI estimates, and a scan makes none.
4Who may verify and promote, and is one occurrence sufficient?Founder plus named curators; yes, one packaging-verified occurrence.
5Commercial resolver as a live fallback?Out for now — monthly cost, and its data cannot be promoted.
6Composite fallback for branded foods: forbidden, or permitted when labelled?Permitted when labelled (§8.3).
7Pre-seed volume and market split before launch?~500 DE + ~500 US, head-first.
8Epic sequencing?After Epic 29's branded-food track; own epic; not in the tracker yet.
9Does packaging capture survive as a never-prompted dead-end escape hatch?Resolved 2026-08-31: not in the logging flow. Remaining question is whether even an unobtrusive opt-in offer is acceptable, or whether it is cut entirely and packaging capture exists only as a curator tool. Recommend cutting it from the user-facing app, for consistency with decision 1.

Prepared as an analysis for founder decision. No implementation exists, no tracker story has been created, and no code has been changed. Figures for external services are current published rates as of 2026-08-31 and should be re-checked before budgeting. Statements about licence obligations are a technical reading, not legal advice, and the Open Food Facts question in particular should be confirmed with counsel before any sourcing decision is implemented.