# Cillino ODbL release: schema and modifications

Version 2026-10-18.1 · 2026-10-18. Every line of the .jsonl.gz file is one JSON object with a `table` field.

## Tables
| table | one row per | notes |
|---|---|---|
| sauce | sauce whose identity comes only from Open Food Facts records | `review_status` rejected = hidden on the site (not a sauce, or out of scope); kept for completeness |
| brand | brand known only from Open Food Facts | |
| variant | size/package known only from Open Food Facts | `gtin` = barcode (GTIN-14, zero-padded) |
| claim | one fact from one Open Food Facts record | `value` as used; `method` imported / normalized / inferred; `source_field` the OFF field(s) read; `transform` the Cillino code that produced an inferred value; `license_code`; `retrieved_at` |
| link | Open Food Facts record ↔ Cillino entity | `match_method` (barcode, brand+name, …), `match_score`, `status` (matched / needs_review / rejected) |
| ingredient_list | ingredient list text from Open Food Facts | `raw_text` is unchanged |
| ingredient_item | one item of such a list | `raw_label` as split by Cillino; `ingredient` = Cillino dictionary entry (NULL if unmapped) |
| market | country where a variant is sold, from Open Food Facts | |
| image | photo record (the record is ODbL; `license_code`/`license_version` are the licence of the **photograph**, not of the record) | author (`photographer`), `license_code`, `license_version`, `original_url`, `modifications` (full) and `modification_notice` (short), `rights_class`, `verification` |
| merge | Cillino merge of two records involving Open Food Facts data | evidence in `reason` |
| decision | review decision about an Open Food Facts record | queue, verdict, rule (see below), note, by rule or by hand |
| field | published field | `depends_on`, `method`, `layer`, `legal_review` |
| site_file / site_row | the published OFF-layer files | `site_file` = a whole small file, or the non-list part of a large one; `site_row` = one element (`key`, `i` or `k`) of a large list or map |

## How Cillino changed the data
- **Normalization:** barcodes zero-padded to 14 digits and check-digit validated; sizes parsed from the printed
  quantity (the printed text is kept, `quantity_as_printed`); names, brands and ingredient text kept as published.
- **Classification (inferred):** sauce type, other types, family (hot / BBQ), style, named peppers, smoked and
  fermented, from Open Food Facts categories, product name and ingredients (ingest/hotsauce/sources/off.py and
  off_bulk_classify.py). Records that are not sauces are kept with review_status = rejected.
- **Ingredient mapping:** each list split into items and mapped to Cillino's ingredient dictionary.
- **Flavor reading (inferred):** flavor tags with their evidence, the label's own heat word, and whether the profile
  is established, from ingredient order and wording (ingest/hotsauce/flavor.py). In `site_file` rows under
  `inferred`.
- **Matching and merging:** Open Food Facts records linked to existing Cillino sauces by barcode, or by brand and
  name under documented rules (UM-1/UM-2, DUP-1, DUP-B; docs/reports/review-queues.md). European barcodes of a US
  product are attached to it as regional variants. Every merge is in `merge`, every decision in `decision`.
- **Similar sauces:** `related` lists computed from flavor tags, peppers, style and type across the catalog.
- **Photos:** see `image.modifications`. Photos themselves are CC BY-SA 3.0 and are not in this file.

## Rules referenced in `decision`
UM-1 same product · UM-2 different product · C-1 sauce · C-2 not a sauce · C-3 outside launch scope · C-4 peppercorn
sauce · C-5 unresolved · P-1 photo set aside · DUP-1 merge sauces · DUP-B merge brands. Rules without a code were
manual decisions after looking at the record.
