The allergen matrix that stays right: catch the reformulation nobody told you about
Your allergen chart is correct the day you write it - this reads every supplier sheet, works each dish out by arithmetic, and flags the ones that went stale
Version history
An allergen chart is correct on the day you write it and slowly becomes fiction after that. This blueprint reads every supplier sheet once, works out each dish by arithmetic, and tells you which dishes went stale.
The architecture
the same flow as text
▼ (mailed to one address, or dropped in a folder)
[ Docling — reads the page ]
│ PDF/photo → text + table structure
▼
[ Ollama, local model — maps wording to the allergen list ]
│ "semolina" → cereals/gluten · "casein" → milk · unsure → UNKNOWN
▼
[ Grist — the ingredient register ] ← one row per ingredient, evidence date, source file
▼ set union, in a formula column
[ Recipes → dishes ] a dish carries every allergen of every ingredient in it
├─ every ingredient verified and in date → dish publishable
├─ any ingredient stale or UNKNOWN → dish marked unverified
└─ a new sheet contradicts the old one → affected dishes listed
▼
[ WeasyPrint ] → counter chart · PPDS labels · dated archive copy
[ n8n ] → the review clock, the re-check, the flags to your phone
Software adds allergens. Software never removes one. "No evidence" is not "free from".
That last line is the design, and I want to be blunt about why. If you ask a language model "does this dish contain milk?", it will answer, and it will sometimes answer no when the sheet was ambiguous. In an invoice check a false clean costs you money. Here a false clean is the whole failure. So the model gets one narrow job — reading a declaration and mapping wording to a fixed list — and it is allowed to say UNKNOWN. Everything downstream is set arithmetic in a spreadsheet formula. A dish is never marked clear because nothing was found; it is marked clear only when every ingredient in it has current, human-confirmed evidence.
The problem
The allergen matrix on your wall is a snapshot. Recipes get tweaked, a supplier is out of stock so someone grabs a different brand for a fortnight, and the manufacturer quietly reformulates a coating. None of those events walk over and update your chart. So the chart stays right for a while and then it is wrong, and nobody can tell you the date it stopped being right.
I am not going to quote you a reformulation rate. Nobody publishes one I would trust, and the mechanism does not need a rate to matter, because the cost of missing one change is not measured in percent. What is documented is the gap in the chain: the Codex Code of Practice on Food Allergen Management (CXC 80-2020) says manufacturers should have procedures for suppliers to notify them of formulation changes. Should. It is a recommendation, not a guarantee that an email lands in your inbox and gets read.
Meanwhile the obligation is real and it is on you. In the EU, Regulation 1169/2011 Annex II lists the 14 allergens and has required allergen information for non-prepacked food — restaurant meals, deli counters, bakery items — since 13 December 2014. In the UK, PPDS food packed on the premises where it is sold has needed a full ingredients list with allergens emphasised since 1 October 2021, and on 5 March 2025 the FSA published best-practice guidance pushing all non-prepacked food towards written-first allergen information. That guidance is strongly recommended, not law, and it is worth knowing the difference.
The US is arriving late and from the opposite end. There is still no federal rule for food prepared and served on site. California's SB 68, the Allergen Disclosure for Dining Experiences Act, added Health and Safety Code §114093.5 and took effect on 1 July 2026: written disclosure of the nine major allergens per menu item, on the menu or by QR code with a printed alternative. It only binds chains with 20 or more locations, so if you run one restaurant it does not apply to you. Read the bills copying it though — Maryland HB 181 and Missouri HB 3446, both introduced in 2026 — and they are drafted to cover every restaurant regardless of size. The phrase that keeps recurring in all of them is "knows or reasonably should know". That is a documentation standard, and documentation is the thing this blueprint builds.
Tool choices — and why
Setup outline
1. List your top 20 ingredients by how many dishes they appear in. Start there. The long tail can wait a month.
2. Build the ingredient table first: supplier, product code, product name, allergens carried, evidence date, link to the source file. Evidence date is not optional — a register without it is the same wall chart with extra steps.
3. Collect the current spec sheets for those 20. Most suppliers will email them; for the rest, photograph the pack. This is the boring week and there is no way around it.
4. Wire Docling behind n8n and run those 20 through. Read every output yourself and correct it. You are building your prompt against real sheets, and you will find at least one supplier whose PDF is a scan of a fax.
5. Add recipes and dishes, then write the rollup as a formula: dish allergens = union of ingredient allergens. If a sub-recipe goes into three dishes, model it as an ingredient so the union chains properly.
6. Add the two status columns before you print anything: verified (a human confirmed this ingredient row against a sheet, on this date) and publishable (every ingredient in this dish is verified and in date). Only publishable dishes go on a printed chart.
7. Generate the chart and the labels with WeasyPrint, and archive a dated PDF on every regeneration.
8. Turn on the review clock: six months for allergen-carrying ingredients, twelve for everything else, plus an immediate flag on any new sheet, any supplier switch, and any delivery whose packaging looks different.
9. Handle cross-contact separately. That is a kitchen question — shared fryer, shared slicer, shared prep surface — and it belongs in a column you fill in by walking the kitchen, not in anything a document reader produces.
Pitfalls — the real ones
Verified repos
Docling — MIT, 65k stars, active (August 2026)
Ollama — MIT, 179k stars, active (August 2026)
Grist — Apache-2.0, 11.5k stars, active (August 2026)
WeasyPrint — BSD-3-Clause, 9.5k stars, active (August 2026)
n8n — Sustainable Use License (free self-hosted internal use), 201k stars, active
Open Food Facts — AGPL-3.0 server, ODbL data, active (August 2026) — optional tripwire only
NocoDB — 64k stars, active (August 2026) — alternative to Grist