This repository is the canonical home of the FDP-1 specification. FDP-1 is a minimal, RFC-style specification for declaring where a nutrient value came from and how well a score built on it is validated. It does not score food — it wraps any existing system (Nutri-Score, Health Star Rating, Nutri-Grade, Food Compass, or a proprietary score) without modifying it.
Every food score tells you its answer. None tells you what it knew.
Nutri-Score says B; Yuka says 40/100. There's no way to tell whether they disagree about the food or about the algorithm, because neither declares which data it read. FDP-1 is the receipt — attach it to a score and someone else can check the number instead of trusting it.
-
A score is only as good as its worst input. Seven fields on a value, five on a score, one rule — the weakest-link rule (§3.1): a score's grade is its lowest-graded input. 40 lab values + 1 label value = Grade C. No averaging, because averaging is how a system buries its weak inputs.
-
A value is readable on its own.
nutrient_refnames which nutrient — canonically a CDNO term, with FDC numbers, INFOODS tagnames and ChEBI accepted and resolved to CDNO (seeresolver/).source_refnames where the number came from. Neither is inferable from the other. -
There are three ways to say nothing, and they differ (§4). Omitting a field is silence.
OPENis not known.NONEis nothing to know. A score resting on anOPENinput comes out honestly ungraded instead of quietly confident. -
Once FDP, always FDP (§5). A conforming document stays valid under every future revision. That's why the spec is small — everything in it is permanent, so very little belongs in it.
The reference validator is dependency-free (Python ≥ 3.11, standard library only):
python validator/validate_fdp.py examples/iron-two-hosts.jsonIt recomputes the weakest-link grade rather than trusting the declared one, and
exits non-zero on any non-conformance. See
examples/iron-two-hosts.json — one food, full
provenance on every input, a ~6× absorbed-iron delta across two host states,
honestly ungraded (—) because one modifier is OPEN.
Proving a validator says yes is half a test. Clone this repository and watch it
say no — three fixtures under tests/non-conforming/ (a welded protein_mg
column, an empty field where §4 requires the literal OPEN, and a bare "iron"
where §2 requires a CURIE) are each rejected, and the conforming example is checked
in the same run so a validator that broke and refused everything could not pass:
git clone https://github.com/murffious/fdp-1 && cd fdp-1
pytest tests/ # or: python tests/test_rejections.pyBoth invocations run the same assertions. That matters more than it sounds: until
2026-08-30 only the script form existed, so pytest tests/ in a fresh clone printed
no tests collected — the suite looked like pytest and was not.
A fuller reference implementation — a Python package that ingests foods, runs
digestion, and emits FDP-1 declarations, plus the MASTER_CROSSWALK.tsv
nutrient→metabolite join — lives at
github.com/murffious/biology_as_code.
The spec and the implementation are deliberately separate artifacts.
Draft — Request for Comments. Expected to change until three independent implementations exist. Open an issue — that is the entire mechanism by which FDP-1 becomes a standard rather than a document.
Apache-2.0 (see LICENSE), with a patent
non-assertion covenant over the specification and its reference
validator.