Status: final, v1.0. No unresolved TBDs remain except the explicitly out-of-scope v1.1 items in §9. Future changes go through an MCI Improvement Proposal (§8), not a direct edit.
MCI expresses the daily cost of 1 HU ≡ 1 Reference-Human Basal Day, as defined by the Humoney whitepaper:
RH-BMR = 1,700 kcal/day exact, permanent
1 kcal = 4,184 J exact, thermochemical
1 HU = 1,700 × 4,184 = 7,112,800 J exact integer
1 HU = 1.976 kWh (rounded; actual 1.9757777...)
mean basal power = 82.3 W (rounded; actual 82.3240740...)
These are locked in mci/constants.py and must never be altered without an MCI Improvement Proposal (see §7).
Six staples: wheat, rice (milled), maize, vegetable oil, pulses, sugar.
Reference oil: Palm oil. Reference pulse: Beans. See §7 Decisions for the live coverage data behind both.
MCI-G has no pulses leg — the Pink Sheet has no pulse/legume series at all — and is priced over the other five staples, reweighted. See §7 "Decision: MCI-G basket without pulses". MCI-D retains all six staples (FPMA has domestic bean/lentil/pulses series in most countries).
No ancillary/cooking-energy leg in v1.0 — this is a designed v1.1 item, not an omission.
Derived by scripts/derive_weights.py from FAOSTAT Food Balance Sheets (dataset FBS — "Food Balances (2010-)"), World aggregate (Area Code 5000), element "Food supply (kcal/capita/day)" (Element Code 664), averaged over 2014–2023, normalized over the six staples so shares sum to 1. Locked in methodology/weights.json together with the exact query parameters, retrieval timestamp, and the source zip's SHA-256, on 2026-07-22:
| Staple | Weight |
|---|---|
| wheat | 0.3014 |
| rice | 0.2916 |
| maize | 0.0836 |
| vegetable_oil | 0.1714 |
| pulses | 0.0369 |
| sugar | 0.1151 |
A filtered, committed snapshot of the underlying FAOSTAT rows lives at data/snapshots/faostat_weights/world_kcal_664.csv (1,676 rows: World × element 664, all items, all years 2010–2023), with provenance.json alongside it. scripts/derive_weights.py --offline recomputes weights.json from that snapshot only, and reproduces it bit-for-bit (the full ~52 MB source zip itself is not committed — only the small filtered slice actually used, plus enough provenance to re-derive it).
After commit, weights are locked — the pipeline reads the JSON, never recomputes silently. Re-deriving requires deleting/regenerating weights.json deliberately, which is itself an MCI Improvement Proposal (§8).
Densities (kcal per kg, edible basis) per staple come from USDA FoodData Central when FDC_API_KEY is set (via mci/sources/fdc.py, which queries the "SR Legacy" generic/reference data type and reads USDA nutrient number 208, Energy in KCAL), else from literature values hard-coded in mci/constants.py (each with a citation comment and a TODO(verify-FDC) marker — see OPEN_QUESTIONS.md). No FDC_API_KEY was set in the Phase 2 build environment, so the committed weights.json/densities used in this repo's example outputs use the literature fallback.
For a given month *t* and price set *P* (USD/kg per staple *i*):
kg_i = 1700 kcal × weight_i ÷ density_i (kg of staple i per day)
cost(P, t) = Σ_i kg_i × P_i(t) (USD per day, per price set)
cost evaluated on international reference prices.cost evaluatedper-country on FPMA retail prices. A country enters the median only if it has current prices for staples covering ≥ 80% of basket energy weight that month; weights are renormalized over available staples per country, and coverage is flagged in output. A population-weighted mean is a v1.x variant, not implemented in v1.0.
FpmaSeriePrice endpoint returns price_value_dollar already converted by FAO. Gap handling: per §5's ≥80%-coverage-per-country rule. Not yet enabled — licence terms unclear, see SOURCES.md and OPEN_QUESTIONS.md.
series exists (§2, §7); the other five staples' prices are used as-is from the "Monthly Prices" sheet, unit-converted from $/mt or $/kg to $/kg (§7 arithmetic uses $/kg throughout). Enabled.
See §3 and SOURCES.md.
Full endpoint/licence/status detail lives in SOURCES.md — this section only records what's relevant to the arithmetic (FX, gaps, units).
Every judgment call gets a block here: what was chosen, what the alternatives were, why.
Decision: FAOSTAT access route (bulk download vs. REST API). Chosen: the bulk-download zip (bulks-faostat.fao.org). Alternatives: FAO's two documented REST APIs. Why: fenixservices.fao.org/faostat/api/v1/... returned HTTP 521 (origin down) on live verification 2026-07-22; faostatservices.fao.org/api/v1/... returned HTTP 401 (requires an authorization header not available to this build). The bulk-download service publishes the identical underlying dataset as FAO's own official public channel, so no data-fidelity tradeoff was made — only an access-path one. If the REST APIs come back, re-verify but there's no methodological reason to switch back.
Decision: weights year window (2014–2023). Chosen: a trailing 10-year window within the FBS "2010-" release, i.e. 2014–2023 (2023 being the most recent year available as of retrieval). Alternatives: the full 2010–2023 window (14 years), or a 5-year window (2019–2023). Why: a 10-year window sits inside the spec's "5–10 year" guidance at its more-stable end (more years than 5, damping any single-year shock) while still being materially "recent" (excludes 2010–2013 only for that reason, not because they carry a different data-quality flag).
Decision: item mapping for vegetable_oil and pulses weights. Chosen: the FBS *aggregate* categories "Vegetable Oils" and "Pulses" for the *weight* (dietary-energy share of the category), independent of which *specific* commodity (palm vs. soybean oil; beans vs. lentils) is later chosen to *price* that basket slot (§2). Alternatives: use only the specific commodity's own FBS item (e.g. "Soyabean Oil" alone) for the weight too. Why: the basket is defined at the category level ("vegetable_oil", "pulses" — mci/constants.py:BASKET_STAPLES); collapsing the weight down to one commodity would double-count a sourcing decision that belongs to the *price* series, not the *dietary-energy* one, and would make the weight sensitive to a choice (which oil/pulse has better market data coverage) that has nothing to do with how much dietary energy the category actually supplies globally.
Decision: sugar item mapping ("Sugar (Raw Equivalent)" vs. "Sugar & Sweeteners"). Chosen: "Sugar (Raw Equivalent)". Alternatives: the broader "Sugar & Sweeteners" aggregate (which also includes honey and other sweeteners). Why: MCI prices sugar via world sugar commodity benchmarks (e.g. World Bank Pink Sheet "Sugar, world", ICE No. 11), which are themselves quoted in raw-sugar-equivalent terms — matching the weight's item to the same commodity basis as the price series keeps kg_i × P_i(t) internally consistent, rather than pricing raw sugar against a weight that includes non-sugar sweeteners it was never priced against.
Decision: reference oil (palm vs. soybean). Chosen: Palm oil. Alternatives: soybean oil. Why: live FPMA domestic-series coverage 2026-07-22 shows Palm Oil (all case/label variants combined: "Palm Oil", "Palm oil", "Palm Oil (traditional)", "Palm oil (refined)") at ~79 country series vs. Soybean oil at ~11 — a large enough gap that it's not close. Pink Sheet carries both ("Palm oil", "Soybean oil" columns), so this doesn't create a Pink Sheet coverage problem either way; Palm oil wins on FPMA coverage without costing anything on the MCI-G side.
Decision: reference pulse (beans vs. lentils). Chosen: Beans. Alternatives: lentils; the generic FPMA "Pulses" commodity itself. Why: live FPMA coverage 2026-07-22 shows Beans (all variants: red, black, white, mixed, kidney, etc. combined) at ~144 series vs. Lentils at ~28 vs. generic "Pulses" at ~18 — beans dominate by roughly 5x. Moot for Pink Sheet, which carries no pulse series regardless (next Decision).
Decision: MCI-G basket without pulses. Chosen: reweight MCI-G over the remaining five staples (wheat, rice, maize, vegetable_oil, sugar), normalizing their FAOSTAT-derived weights to sum to 1 (via mci.constants.reweight_excluding — see mci/constants.py), rather than substituting a proxy international pulse price or forcing a six-staple MCI-G with a synthetic pulse series. Alternatives considered: (a) find a proxy pulse series from a different international source outside the Pink Sheet/FAO-international scope named in the spec — rejected, out of the spec's named source list; (b) leave pulses priced at zero/omitted from the sum without reweighting the other five — rejected, that would silently shrink MCI-G's total relative to a "full basket" cost rather than honestly re-normalizing. Why reweighting: it keeps Σ weight_i = 1 (so MCI-G still prices "one full day's dietary energy," just sourced from five staples instead of six) while being transparent that MCI-G and MCI-D price structurally different basket compositions. Resulting MCI-G weights (vs. MCI-D's six-staple weights in §3):
| Staple | MCI-D weight | MCI-G weight |
|---|---|---|
| wheat | 0.3014 | 0.3130 |
| rice | 0.2916 | 0.3027 |
| maize | 0.0836 | 0.0868 |
| vegetable_oil | 0.1714 | 0.1780 |
| sugar | 0.1151 | 0.1195 |
| pulses | 0.0369 | *(not priced in MCI-G)* |
This is exactly the divergence the spec asked to be stated prominently: MCI-G's basket carries about 3.8 percentage points of weight (0.0369 ÷ 0.9631) redistributed away from pulses and onto the other five staples, relative to MCI-D's basket.
Decision: FDC data type ("SR Legacy" vs. "Foundation"/"Branded"). Chosen: SR Legacy, USDA's older but broader generic-commodity dataset. Alternatives: "Foundation" (newer, more rigorously sampled, but much thinner commodity coverage as of 2026-07-22) and "Branded" (specific packaged products — wrong level of abstraction for "wheat" as a category). Why: MCI needs one representative density per *category* (wheat/rice/maize/oil/pulse/sugar), not a specific manufacturer's product; SR Legacy's generic entries (e.g. "Wheat flour, whole-grain, soft wheat") are the closest fit, and it has an entry for every staple category MCI needs, which was verified live for wheat flour (2026-07-22, fdc_id 168944) before choosing it as the default in mci/sources/fdc.py.
Decision: FPMA per-country, per-staple aggregation across varieties. Chosen: when a country reports multiple FPMA series for one basket staple in a month (e.g. "Beans (red)" and "Beans (black)" both present), mci.pipeline.compute_mci_d_from_fpma_df takes their unweighted mean as that country's price for the staple. Alternatives: pick a single "canonical" variety per staple and discard the rest; weight varieties by some estimate of local consumption share (data not available at this grain). Why: an unweighted mean is a transparent, deterministic default that uses all the reported price signal for that staple in that country without requiring per-country, per-commodity consumption-share data MCI does not have — better than an arbitrary single-variety pick, and simpler than a weighting scheme the underlying data can't actually support.
Decision: FPMA "Liter" unit density approximation for oil. Chosen: a literature density of 0.92 kg/L for any FPMA oil series reported in Liter (mci/sources/fpma.py:UNIT_TO_KG) — crude/refined palm oil at ambient temperature is commonly cited in this range. Alternatives: reject Liter-denominated series entirely (loses real coverage — a live sample series, Angola/Cuando Cubango Palm Oil, was Liter-denominated); look up a temperature- and oil-type-specific density per series (no such per-series metadata is available from FPMA). Why: a single literature constant is transparent and good enough for a Liter→kg conversion where the alternative is discarding the observation; marked TODO(verify-density) in code since this hasn't mattered yet — FPMA is disabled pending §7's licence Decision, so no published MCI-D value depends on it today.
Changes to this methodology only via an MCI Improvement Proposal (mips/MIP-XXXX.md), with 30 days' public notice, and semantic versioning of the methodology itself (independent of the software's version number).