FAILURE MAP
← Case archive

FA-96926 / Recipe scaling and nutrition / Open access

Volume-to-mass ingredient converter: millilitres per cup · case 01

250 ml of water converts to 236 g instead of 249 g.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

Millilitres are converted with a 250 ml metric cup although densities are per 236.5 ml US cup.

VERIFIED REPAIR

Divide millilitres by 236.5 to get US cups.

Unsuccessful approach: The 240 ml nutrition-label cup still disagrees with the 236.5 ml cup the density table assumes.

Case contract

Convert amount (fraction string) of cup/tbsp/tsp/ml to grams. 1 cup = 16 tbsp = 48 tsp = 236.5 ml. Grams per cup: flour 120, sugar 200, brown sugar 145 (213 when prefixed "packed "), butter 227, honey 340, water 236. Names are trimmed and case-insensitive; a ", sifted" suffix multiplies density by 9/10. Results below 10 g print one decimal ("%.1f g"), otherwise whole grams, both half-up. Unknown ingredient or unit returns an error string.

Why this case matters

Recipe apps convert American volume measures to weights for scaling and nutrition lookup.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(amount, unit, ingredient):
    DENS = {'flour': 120, 'sugar': 200, 'brown sugar': 145, 'butter': 227, 'honey': 340, 'water': 236}
    PER_CUP = {'cup': 1, 'tbsp': 16, 'tsp': 48}
    name = ingredient.strip().lower()
    packed = name.startswith('packed ')
    if packed:
        name = name[len('packed '):]
    sifted = name.endswith(', sifted')
    if sifted:
        name = name[:-len(', sifted')]
    if name not in DENS:
        return 'error: unknown ingredient'
    if unit == 'ml':
        cups = Fraction(amount) / Fraction(250)
    elif unit in PER_CUP:
        cups = Fraction(amount) / PER_CUP[unit]
    else:
        return 'error: unknown unit'
    d = Fraction(DENS[name])
    if packed and name == 'brown sugar':
        d = Fraction(213)
    if sifted:
        d = d * Fraction(9, 10)
    g = cups * d
    if g < 10:
        return '%.1f g' % (math.floor(g * 10 + Fraction(1, 2)) / 10)
    return '%d g' % math.floor(g + Fraction(1, 2))
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['one cup flour', ['1', 'cup', 'flour'], '120 g'], ['exactly ten grams', ['4', 'tsp', 'flour'], '10 g'],
  ['packed brown sugar', ['1', 'cup', 'packed brown sugar'], '213 g'],
  ['regression: millilitres per cup', ['6', 'ml', 'packed flour'], '3.0 g'],
  ['repair check: millilitres per cup', ['250', 'ml', 'honey'], '359 g'],
  ['generated control 1', ['15', 'tbsp', 'SUGAR'], '188 g'],
  ['generated control 2', ['2', 'tbsp', 'water'], '30 g'],
  ['generated control 3', ['100', 'tsp', 'sugar'], '417 g']],
 [['exactly ten grams', ['4', 'tsp', 'flour'], '10 g'],
  ['packed brown sugar', ['1', 'cup', 'packed brown sugar'], '213 g'],
  ['unknown ingredient', ['1', 'cup', 'saffron'], 'error: unknown ingredient'],
  ['regression: millilitres per cup', ['15', 'ml', 'honey'], '22 g'],
  ['repair check: millilitres per cup', ['100', 'ml', 'packed water'], '100 g'],
  ['generated control 1', ['1/3', 'ml', 'water'], '0.3 g'],
  ['generated control 2', ['5', 'pinch', 'sugar'], 'error: unknown unit'],
  ['generated control 3', ['1/4', 'tbsp', 'saffron'], 'error: unknown ingredient']],
 [['packed brown sugar', ['1', 'cup', 'packed brown sugar'], '213 g'],
  ['unknown ingredient', ['1', 'cup', 'saffron'], 'error: unknown ingredient'],
  ['metric cup of water', ['250', 'ml', 'water'], '249 g'],
  ['regression: millilitres per cup', ['250', 'ml', 'flour, sifted'], '114 g'],
  ['repair check: millilitres per cup', ['4', 'ml', 'BROWN SUGAR'], '2.5 g'],
  ['generated control 1', ['250', 'tbsp', 'BROWN SUGAR'], '2266 g'],
  ['generated control 2', ['1/2', 'tbsp', 'packed honey'], '11 g'],
  ['generated control 3', ['120', 'tbsp', 'sugar'], '1500 g']],
 [['unknown ingredient', ['1', 'cup', 'saffron'], 'error: unknown ingredient'],
  ['metric cup of water', ['250', 'ml', 'water'], '249 g'],
  ['sifted flour tablespoon', ['2', 'tbsp', 'Flour, sifted'], '14 g'],
  ['regression: millilitres per cup', ['1/2', 'ml', '  Flour '], '0.3 g'],
  ['repair check: millilitres per cup', ['250', 'ml', 'sugar, sifted'], '190 g'],
  ['generated control 1', ['3/4', 'pinch', '  Honey '], 'error: unknown unit'],
  ['generated control 2', ['3', 'tsp', 'honey, sifted'], '19 g'],
  ['generated control 3', ['2', 'ml', 'FLOUR'], '1.0 g']],
 [['metric cup of water', ['250', 'ml', 'water'], '249 g'],
  ['sifted flour tablespoon', ['2', 'tbsp', 'Flour, sifted'], '14 g'],
  ['one cup flour', ['1', 'cup', 'flour'], '120 g'],
  ['regression: millilitres per cup', ['6', 'ml', '  Butter '], '5.8 g'],
  ['repair check: millilitres per cup', ['4', 'ml', 'water, sifted'], '3.6 g'],
  ['generated control 1', ['1', 'ml', '  Flour '], '0.5 g'],
  ['generated control 2', ['1/4', 'cup', 'sugar'], '50 g'],
  ['generated control 3', ['4', 'cup', '  Packed Flour '], '480 g']]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
one cup flour120 g120 gPassed
exactly ten grams10 g10 gPassed
packed brown sugar213 g213 gPassed
regression: millilitres per cup2.9 g3.0 gFailed
repair check: millilitres per cup340 g359 gFailed
generated control 1188 g188 gPassed
generated control 230 g30 gPassed
generated control 3417 g417 gPassed

SHA-256 / a42bfbd40620bd54968d71f2abae5548a27d6757ae1aeaebbd4c18855628e24b

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(amount, unit, ingredient):
    DENS = {'flour': 120, 'sugar': 200, 'brown sugar': 145, 'butter': 227, 'honey': 340, 'water': 236}
    PER_CUP = {'cup': 1, 'tbsp': 16, 'tsp': 48}
    name = ingredient.strip().lower()
    packed = name.startswith('packed ')
    if packed:
        name = name[len('packed '):]
    sifted = name.endswith(', sifted')
    if sifted:
        name = name[:-len(', sifted')]
    if name not in DENS:
        return 'error: unknown ingredient'
    if unit == 'ml':
        cups = Fraction(amount) / Fraction(240)
    elif unit in PER_CUP:
        cups = Fraction(amount) / PER_CUP[unit]
    else:
        return 'error: unknown unit'
    d = Fraction(DENS[name])
    if packed and name == 'brown sugar':
        d = Fraction(213)
    if sifted:
        d = d * Fraction(9, 10)
    g = cups * d
    if g < 10:
        return '%.1f g' % (math.floor(g * 10 + Fraction(1, 2)) / 10)
    return '%d g' % math.floor(g + Fraction(1, 2))
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['one cup flour', ['1', 'cup', 'flour'], '120 g'], ['exactly ten grams', ['4', 'tsp', 'flour'], '10 g'],
  ['packed brown sugar', ['1', 'cup', 'packed brown sugar'], '213 g'],
  ['regression: millilitres per cup', ['6', 'ml', 'packed flour'], '3.0 g'],
  ['repair check: millilitres per cup', ['250', 'ml', 'honey'], '359 g'],
  ['generated control 1', ['15', 'tbsp', 'SUGAR'], '188 g'],
  ['generated control 2', ['2', 'tbsp', 'water'], '30 g'],
  ['generated control 3', ['100', 'tsp', 'sugar'], '417 g']],
 [['exactly ten grams', ['4', 'tsp', 'flour'], '10 g'],
  ['packed brown sugar', ['1', 'cup', 'packed brown sugar'], '213 g'],
  ['unknown ingredient', ['1', 'cup', 'saffron'], 'error: unknown ingredient'],
  ['regression: millilitres per cup', ['15', 'ml', 'honey'], '22 g'],
  ['repair check: millilitres per cup', ['100', 'ml', 'packed water'], '100 g'],
  ['generated control 1', ['1/3', 'ml', 'water'], '0.3 g'],
  ['generated control 2', ['5', 'pinch', 'sugar'], 'error: unknown unit'],
  ['generated control 3', ['1/4', 'tbsp', 'saffron'], 'error: unknown ingredient']],
 [['packed brown sugar', ['1', 'cup', 'packed brown sugar'], '213 g'],
  ['unknown ingredient', ['1', 'cup', 'saffron'], 'error: unknown ingredient'],
  ['metric cup of water', ['250', 'ml', 'water'], '249 g'],
  ['regression: millilitres per cup', ['250', 'ml', 'flour, sifted'], '114 g'],
  ['repair check: millilitres per cup', ['4', 'ml', 'BROWN SUGAR'], '2.5 g'],
  ['generated control 1', ['250', 'tbsp', 'BROWN SUGAR'], '2266 g'],
  ['generated control 2', ['1/2', 'tbsp', 'packed honey'], '11 g'],
  ['generated control 3', ['120', 'tbsp', 'sugar'], '1500 g']],
 [['unknown ingredient', ['1', 'cup', 'saffron'], 'error: unknown ingredient'],
  ['metric cup of water', ['250', 'ml', 'water'], '249 g'],
  ['sifted flour tablespoon', ['2', 'tbsp', 'Flour, sifted'], '14 g'],
  ['regression: millilitres per cup', ['1/2', 'ml', '  Flour '], '0.3 g'],
  ['repair check: millilitres per cup', ['250', 'ml', 'sugar, sifted'], '190 g'],
  ['generated control 1', ['3/4', 'pinch', '  Honey '], 'error: unknown unit'],
  ['generated control 2', ['3', 'tsp', 'honey, sifted'], '19 g'],
  ['generated control 3', ['2', 'ml', 'FLOUR'], '1.0 g']],
 [['metric cup of water', ['250', 'ml', 'water'], '249 g'],
  ['sifted flour tablespoon', ['2', 'tbsp', 'Flour, sifted'], '14 g'],
  ['one cup flour', ['1', 'cup', 'flour'], '120 g'],
  ['regression: millilitres per cup', ['6', 'ml', '  Butter '], '5.8 g'],
  ['repair check: millilitres per cup', ['4', 'ml', 'water, sifted'], '3.6 g'],
  ['generated control 1', ['1', 'ml', '  Flour '], '0.5 g'],
  ['generated control 2', ['1/4', 'cup', 'sugar'], '50 g'],
  ['generated control 3', ['4', 'cup', '  Packed Flour '], '480 g']]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
one cup flour120 g120 gPassed
exactly ten grams10 g10 gPassed
packed brown sugar213 g213 gPassed
regression: millilitres per cup3.0 g3.0 gPassed
repair check: millilitres per cup354 g359 gFailed
generated control 1188 g188 gPassed
generated control 230 g30 gPassed
generated control 3417 g417 gPassed

SHA-256 / 5960fd049323237739d357ca4d9231b53f61a29d1150e85f900bdf20739c88f6

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(amount, unit, ingredient):
    DENS = {'flour': 120, 'sugar': 200, 'brown sugar': 145, 'butter': 227, 'honey': 340, 'water': 236}
    PER_CUP = {'cup': 1, 'tbsp': 16, 'tsp': 48}
    name = ingredient.strip().lower()
    packed = name.startswith('packed ')
    if packed:
        name = name[len('packed '):]
    sifted = name.endswith(', sifted')
    if sifted:
        name = name[:-len(', sifted')]
    if name not in DENS:
        return 'error: unknown ingredient'
    if unit == 'ml':
        cups = Fraction(amount) / Fraction(2365, 10)
    elif unit in PER_CUP:
        cups = Fraction(amount) / PER_CUP[unit]
    else:
        return 'error: unknown unit'
    d = Fraction(DENS[name])
    if packed and name == 'brown sugar':
        d = Fraction(213)
    if sifted:
        d = d * Fraction(9, 10)
    g = cups * d
    if g < 10:
        return '%.1f g' % (math.floor(g * 10 + Fraction(1, 2)) / 10)
    return '%d g' % math.floor(g + Fraction(1, 2))
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['one cup flour', ['1', 'cup', 'flour'], '120 g'], ['exactly ten grams', ['4', 'tsp', 'flour'], '10 g'],
  ['packed brown sugar', ['1', 'cup', 'packed brown sugar'], '213 g'],
  ['regression: millilitres per cup', ['6', 'ml', 'packed flour'], '3.0 g'],
  ['repair check: millilitres per cup', ['250', 'ml', 'honey'], '359 g'],
  ['generated control 1', ['15', 'tbsp', 'SUGAR'], '188 g'],
  ['generated control 2', ['2', 'tbsp', 'water'], '30 g'],
  ['generated control 3', ['100', 'tsp', 'sugar'], '417 g']],
 [['exactly ten grams', ['4', 'tsp', 'flour'], '10 g'],
  ['packed brown sugar', ['1', 'cup', 'packed brown sugar'], '213 g'],
  ['unknown ingredient', ['1', 'cup', 'saffron'], 'error: unknown ingredient'],
  ['regression: millilitres per cup', ['15', 'ml', 'honey'], '22 g'],
  ['repair check: millilitres per cup', ['100', 'ml', 'packed water'], '100 g'],
  ['generated control 1', ['1/3', 'ml', 'water'], '0.3 g'],
  ['generated control 2', ['5', 'pinch', 'sugar'], 'error: unknown unit'],
  ['generated control 3', ['1/4', 'tbsp', 'saffron'], 'error: unknown ingredient']],
 [['packed brown sugar', ['1', 'cup', 'packed brown sugar'], '213 g'],
  ['unknown ingredient', ['1', 'cup', 'saffron'], 'error: unknown ingredient'],
  ['metric cup of water', ['250', 'ml', 'water'], '249 g'],
  ['regression: millilitres per cup', ['250', 'ml', 'flour, sifted'], '114 g'],
  ['repair check: millilitres per cup', ['4', 'ml', 'BROWN SUGAR'], '2.5 g'],
  ['generated control 1', ['250', 'tbsp', 'BROWN SUGAR'], '2266 g'],
  ['generated control 2', ['1/2', 'tbsp', 'packed honey'], '11 g'],
  ['generated control 3', ['120', 'tbsp', 'sugar'], '1500 g']],
 [['unknown ingredient', ['1', 'cup', 'saffron'], 'error: unknown ingredient'],
  ['metric cup of water', ['250', 'ml', 'water'], '249 g'],
  ['sifted flour tablespoon', ['2', 'tbsp', 'Flour, sifted'], '14 g'],
  ['regression: millilitres per cup', ['1/2', 'ml', '  Flour '], '0.3 g'],
  ['repair check: millilitres per cup', ['250', 'ml', 'sugar, sifted'], '190 g'],
  ['generated control 1', ['3/4', 'pinch', '  Honey '], 'error: unknown unit'],
  ['generated control 2', ['3', 'tsp', 'honey, sifted'], '19 g'],
  ['generated control 3', ['2', 'ml', 'FLOUR'], '1.0 g']],
 [['metric cup of water', ['250', 'ml', 'water'], '249 g'],
  ['sifted flour tablespoon', ['2', 'tbsp', 'Flour, sifted'], '14 g'],
  ['one cup flour', ['1', 'cup', 'flour'], '120 g'],
  ['regression: millilitres per cup', ['6', 'ml', '  Butter '], '5.8 g'],
  ['repair check: millilitres per cup', ['4', 'ml', 'water, sifted'], '3.6 g'],
  ['generated control 1', ['1', 'ml', '  Flour '], '0.5 g'],
  ['generated control 2', ['1/4', 'cup', 'sugar'], '50 g'],
  ['generated control 3', ['4', 'cup', '  Packed Flour '], '480 g']]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
one cup flour120 g120 gPassed
exactly ten grams10 g10 gPassed
packed brown sugar213 g213 gPassed
regression: millilitres per cup3.0 g3.0 gPassed
repair check: millilitres per cup359 g359 gPassed
generated control 1188 g188 gPassed
generated control 230 g30 gPassed
generated control 3417 g417 gPassed

SHA-256 / 09153729595c7de6c297d17507c31cb16d4cc4e2e4fa779ab061d7ebc6668172

Verification & scope

A deterministic toy contract stated in full here; it is a bounded teaching model, not an authoritative reference or standards implementation. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:52:27.174501+00:00.

Case digest / 72db3e062a4577f62ba5926f3f9622cf1e3403408a4ae1de5f34808ff1c4a937