FAILURE MAP
← Case archive

FA-96906 / Recipe scaling and nutrition / Open access

Volume-to-mass ingredient converter: spoon-to-cup direction · case 01

One teaspoon of sugar converts to 9600 g.

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

ROOT CAUSE

Spoon counts are multiplied by spoons-per-cup instead of divided to get cups.

VERIFIED REPAIR

Divide the amount by the spoons-per-cup count.

Unsuccessful approach: Dividing only for tablespoons leaves teaspoons multiplied by 48.

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(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: spoon-to-cup direction', ['3/4', 'tbsp', 'BROWN SUGAR'], '6.8 g'],
  ['repair check: spoon-to-cup direction', ['100', 'tsp', 'BROWN SUGAR'], '302 g'],
  ['generated control 1', ['2', 'cup', '  Packed Brown Sugar '], '426 g'],
  ['generated control 2', ['5', 'ml', 'SUGAR'], '4.2 g'],
  ['generated control 3', ['1', 'cup', 'saffron'], 'error: unknown ingredient']],
 [['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: spoon-to-cup direction', ['6', 'tsp', 'packed water'], '30 g'],
  ['repair check: spoon-to-cup direction', ['1/2', 'tsp', '  Water, Sifted '], '2.2 g'],
  ['generated control 1', ['1/4', 'ml', 'packed butter'], '0.2 g'],
  ['generated control 2', ['1/3', 'ml', '  Packed Butter '], '0.3 g'],
  ['generated control 3', ['5', 'cup', '  Flour '], '600 g']],
 [['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: spoon-to-cup direction', ['5', 'tbsp', 'butter'], '71 g'],
  ['repair check: spoon-to-cup direction', ['100', 'tsp', 'butter'], '473 g'],
  ['generated control 1', ['1', 'ml', 'packed sugar'], '0.8 g'],
  ['generated control 2', ['3/4', 'cup', 'PACKED WATER'], '177 g'],
  ['generated control 3', ['2', 'ml', 'sugar'], '1.7 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: spoon-to-cup direction', ['1/2', 'tbsp', 'butter'], '7.1 g'],
  ['repair check: spoon-to-cup direction', ['4', 'tsp', 'flour'], '10 g'],
  ['generated control 1', ['5', 'cup', 'packed honey'], '1700 g'],
  ['generated control 2', ['100', 'ml', 'HONEY'], '144 g'],
  ['generated control 3', ['6', 'tbsp', 'brown sugar, sifted'], '49 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: spoon-to-cup direction', ['6', 'tbsp', 'packed butter'], '85 g'],
  ['repair check: spoon-to-cup direction', ['3/4', 'tsp', '  Sugar '], '3.1 g'],
  ['generated control 1', ['3/4', 'cup', 'brown sugar'], '109 g'],
  ['generated control 2', ['2', 'ml', 'butter'], '1.9 g'],
  ['generated control 3', ['1', 'ml', 'flour, sifted'], '0.5 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 grams23040 g10 gFailed
packed brown sugar213 g213 gPassed
regression: spoon-to-cup direction1740 g6.8 gFailed
repair check: spoon-to-cup direction696000 g302 gFailed
generated control 1426 g426 gPassed
generated control 24.2 g4.2 gPassed
generated control 3error: unknown ingredienterror: unknown ingredientPassed

SHA-256 / d0ab70ce8524a82756f4dc1eb66c5af10b62b1a9b7a9993aaf5854b227a7e54a

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(2365, 10)
    elif unit in PER_CUP:
        cups = Fraction(amount) / PER_CUP[unit] if unit == 'tbsp' else 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: spoon-to-cup direction', ['3/4', 'tbsp', 'BROWN SUGAR'], '6.8 g'],
  ['repair check: spoon-to-cup direction', ['100', 'tsp', 'BROWN SUGAR'], '302 g'],
  ['generated control 1', ['2', 'cup', '  Packed Brown Sugar '], '426 g'],
  ['generated control 2', ['5', 'ml', 'SUGAR'], '4.2 g'],
  ['generated control 3', ['1', 'cup', 'saffron'], 'error: unknown ingredient']],
 [['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: spoon-to-cup direction', ['6', 'tsp', 'packed water'], '30 g'],
  ['repair check: spoon-to-cup direction', ['1/2', 'tsp', '  Water, Sifted '], '2.2 g'],
  ['generated control 1', ['1/4', 'ml', 'packed butter'], '0.2 g'],
  ['generated control 2', ['1/3', 'ml', '  Packed Butter '], '0.3 g'],
  ['generated control 3', ['5', 'cup', '  Flour '], '600 g']],
 [['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: spoon-to-cup direction', ['5', 'tbsp', 'butter'], '71 g'],
  ['repair check: spoon-to-cup direction', ['100', 'tsp', 'butter'], '473 g'],
  ['generated control 1', ['1', 'ml', 'packed sugar'], '0.8 g'],
  ['generated control 2', ['3/4', 'cup', 'PACKED WATER'], '177 g'],
  ['generated control 3', ['2', 'ml', 'sugar'], '1.7 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: spoon-to-cup direction', ['1/2', 'tbsp', 'butter'], '7.1 g'],
  ['repair check: spoon-to-cup direction', ['4', 'tsp', 'flour'], '10 g'],
  ['generated control 1', ['5', 'cup', 'packed honey'], '1700 g'],
  ['generated control 2', ['100', 'ml', 'HONEY'], '144 g'],
  ['generated control 3', ['6', 'tbsp', 'brown sugar, sifted'], '49 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: spoon-to-cup direction', ['6', 'tbsp', 'packed butter'], '85 g'],
  ['repair check: spoon-to-cup direction', ['3/4', 'tsp', '  Sugar '], '3.1 g'],
  ['generated control 1', ['3/4', 'cup', 'brown sugar'], '109 g'],
  ['generated control 2', ['2', 'ml', 'butter'], '1.9 g'],
  ['generated control 3', ['1', 'ml', 'flour, sifted'], '0.5 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 grams23040 g10 gFailed
packed brown sugar213 g213 gPassed
regression: spoon-to-cup direction6.8 g6.8 gPassed
repair check: spoon-to-cup direction696000 g302 gFailed
generated control 1426 g426 gPassed
generated control 24.2 g4.2 gPassed
generated control 3error: unknown ingredienterror: unknown ingredientPassed

SHA-256 / 7d931f3f78047b27b45f253c3387ae729e0078fcc1ea1b2f4404511e5011b82a

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: spoon-to-cup direction', ['3/4', 'tbsp', 'BROWN SUGAR'], '6.8 g'],
  ['repair check: spoon-to-cup direction', ['100', 'tsp', 'BROWN SUGAR'], '302 g'],
  ['generated control 1', ['2', 'cup', '  Packed Brown Sugar '], '426 g'],
  ['generated control 2', ['5', 'ml', 'SUGAR'], '4.2 g'],
  ['generated control 3', ['1', 'cup', 'saffron'], 'error: unknown ingredient']],
 [['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: spoon-to-cup direction', ['6', 'tsp', 'packed water'], '30 g'],
  ['repair check: spoon-to-cup direction', ['1/2', 'tsp', '  Water, Sifted '], '2.2 g'],
  ['generated control 1', ['1/4', 'ml', 'packed butter'], '0.2 g'],
  ['generated control 2', ['1/3', 'ml', '  Packed Butter '], '0.3 g'],
  ['generated control 3', ['5', 'cup', '  Flour '], '600 g']],
 [['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: spoon-to-cup direction', ['5', 'tbsp', 'butter'], '71 g'],
  ['repair check: spoon-to-cup direction', ['100', 'tsp', 'butter'], '473 g'],
  ['generated control 1', ['1', 'ml', 'packed sugar'], '0.8 g'],
  ['generated control 2', ['3/4', 'cup', 'PACKED WATER'], '177 g'],
  ['generated control 3', ['2', 'ml', 'sugar'], '1.7 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: spoon-to-cup direction', ['1/2', 'tbsp', 'butter'], '7.1 g'],
  ['repair check: spoon-to-cup direction', ['4', 'tsp', 'flour'], '10 g'],
  ['generated control 1', ['5', 'cup', 'packed honey'], '1700 g'],
  ['generated control 2', ['100', 'ml', 'HONEY'], '144 g'],
  ['generated control 3', ['6', 'tbsp', 'brown sugar, sifted'], '49 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: spoon-to-cup direction', ['6', 'tbsp', 'packed butter'], '85 g'],
  ['repair check: spoon-to-cup direction', ['3/4', 'tsp', '  Sugar '], '3.1 g'],
  ['generated control 1', ['3/4', 'cup', 'brown sugar'], '109 g'],
  ['generated control 2', ['2', 'ml', 'butter'], '1.9 g'],
  ['generated control 3', ['1', 'ml', 'flour, sifted'], '0.5 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: spoon-to-cup direction6.8 g6.8 gPassed
repair check: spoon-to-cup direction302 g302 gPassed
generated control 1426 g426 gPassed
generated control 24.2 g4.2 gPassed
generated control 3error: unknown ingredienterror: unknown ingredientPassed

SHA-256 / 110bbdb70964bdeda56b03ee8bfbfb235b44edd1ea300ce6a114d1663e037e27

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:26.956287+00:00.

Case digest / ca3359fb156e26d59484b728b65dc6fc2f9fc0f4928900c6744959920fb47e44