FA-96901 / Recipe scaling and nutrition / Open access
Volume-to-mass ingredient converter: tablespoons per cup · case 01
Two tablespoons of butter convert to 38 g instead of 28 g.
ROOT CAUSE
The unit table assumes 12 tablespoons per cup, inflating every spoon measure by a third.
VERIFIED REPAIR
Use 16 tbsp and 48 tsp per cup.
Unsuccessful approach: Fixing tablespoons but leaving 36 teaspoons per cup keeps every teaspoon conversion a third too heavy.
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': 12, 'tsp': 36}
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: tablespoons per cup', ['100', 'tbsp', ' Water '], '1475 g'],
['repair check: tablespoons per cup', ['15', 'tsp', 'water'], '74 g'],
['generated control 1', ['100', 'cup', 'PACKED FLOUR'], '12000 g'],
['generated control 2', ['6', 'ml', 'honey, sifted'], '7.8 g'],
['generated control 3', ['1/3', 'ml', 'butter'], '0.3 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: tablespoons per cup', ['4', 'tbsp', ' Flour '], '30 g'],
['repair check: tablespoons per cup', ['120', 'tsp', 'brown sugar'], '363 g'],
['generated control 1', ['15', 'cup', 'honey'], '5100 g'],
['generated control 2', ['250', 'ml', ' Water '], '249 g'],
['generated control 3', ['1', 'ml', '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: tablespoons per cup', ['3', 'tsp', ' Water '], '15 g'],
['repair check: tablespoons per cup', ['120', 'tsp', 'water, sifted'], '531 g'],
['generated control 1', ['15', 'cup', 'butter'], '3405 g'],
['generated control 2', ['5', 'ml', 'water'], '5.0 g'],
['generated control 3', ['5', 'cup', 'butter'], '1135 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: tablespoons per cup', ['15', 'tsp', ' Sugar '], '63 g'],
['repair check: tablespoons per cup', ['5', 'tsp', 'sugar'], '21 g'],
['generated control 1', ['100', 'ml', ' Water '], '100 g'],
['generated control 2', ['15', 'ml', 'packed flour'], '7.6 g'],
['generated control 3', ['15', 'ml', 'flour, sifted'], '6.8 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: tablespoons per cup', ['2', 'tbsp', 'water'], '30 g'],
['repair check: tablespoons per cup', ['100', 'tsp', 'FLOUR'], '250 g'],
['generated control 1', ['1/4', 'tbsp', 'sugar, sifted'], '2.8 g'],
['generated control 2', ['1/2', 'cup', 'FLOUR'], '60 g'],
['generated control 3', ['3/4', 'tsp', ' Packed Flour '], '1.9 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| one cup flour | 120 g | 120 g | Passed |
| exactly ten grams | 13 g | 10 g | Failed |
| packed brown sugar | 213 g | 213 g | Passed |
| regression: tablespoons per cup | 1967 g | 1475 g | Failed |
| repair check: tablespoons per cup | 98 g | 74 g | Failed |
| generated control 1 | 12000 g | 12000 g | Passed |
| generated control 2 | 7.8 g | 7.8 g | Passed |
| generated control 3 | 0.3 g | 0.3 g | Passed |
SHA-256 / 7074a6b2149d58c70753fba413d4f9be3e44623358dd2e42265a4e5b779dd9aa
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': 36}
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: tablespoons per cup', ['100', 'tbsp', ' Water '], '1475 g'],
['repair check: tablespoons per cup', ['15', 'tsp', 'water'], '74 g'],
['generated control 1', ['100', 'cup', 'PACKED FLOUR'], '12000 g'],
['generated control 2', ['6', 'ml', 'honey, sifted'], '7.8 g'],
['generated control 3', ['1/3', 'ml', 'butter'], '0.3 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: tablespoons per cup', ['4', 'tbsp', ' Flour '], '30 g'],
['repair check: tablespoons per cup', ['120', 'tsp', 'brown sugar'], '363 g'],
['generated control 1', ['15', 'cup', 'honey'], '5100 g'],
['generated control 2', ['250', 'ml', ' Water '], '249 g'],
['generated control 3', ['1', 'ml', '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: tablespoons per cup', ['3', 'tsp', ' Water '], '15 g'],
['repair check: tablespoons per cup', ['120', 'tsp', 'water, sifted'], '531 g'],
['generated control 1', ['15', 'cup', 'butter'], '3405 g'],
['generated control 2', ['5', 'ml', 'water'], '5.0 g'],
['generated control 3', ['5', 'cup', 'butter'], '1135 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: tablespoons per cup', ['15', 'tsp', ' Sugar '], '63 g'],
['repair check: tablespoons per cup', ['5', 'tsp', 'sugar'], '21 g'],
['generated control 1', ['100', 'ml', ' Water '], '100 g'],
['generated control 2', ['15', 'ml', 'packed flour'], '7.6 g'],
['generated control 3', ['15', 'ml', 'flour, sifted'], '6.8 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: tablespoons per cup', ['2', 'tbsp', 'water'], '30 g'],
['repair check: tablespoons per cup', ['100', 'tsp', 'FLOUR'], '250 g'],
['generated control 1', ['1/4', 'tbsp', 'sugar, sifted'], '2.8 g'],
['generated control 2', ['1/2', 'cup', 'FLOUR'], '60 g'],
['generated control 3', ['3/4', 'tsp', ' Packed Flour '], '1.9 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| one cup flour | 120 g | 120 g | Passed |
| exactly ten grams | 13 g | 10 g | Failed |
| packed brown sugar | 213 g | 213 g | Passed |
| regression: tablespoons per cup | 1475 g | 1475 g | Passed |
| repair check: tablespoons per cup | 98 g | 74 g | Failed |
| generated control 1 | 12000 g | 12000 g | Passed |
| generated control 2 | 7.8 g | 7.8 g | Passed |
| generated control 3 | 0.3 g | 0.3 g | Passed |
SHA-256 / b0f49bd1f0217a0076d114432ead6397275b4ff18c7ddc5f782f90804865fc05
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: tablespoons per cup', ['100', 'tbsp', ' Water '], '1475 g'],
['repair check: tablespoons per cup', ['15', 'tsp', 'water'], '74 g'],
['generated control 1', ['100', 'cup', 'PACKED FLOUR'], '12000 g'],
['generated control 2', ['6', 'ml', 'honey, sifted'], '7.8 g'],
['generated control 3', ['1/3', 'ml', 'butter'], '0.3 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: tablespoons per cup', ['4', 'tbsp', ' Flour '], '30 g'],
['repair check: tablespoons per cup', ['120', 'tsp', 'brown sugar'], '363 g'],
['generated control 1', ['15', 'cup', 'honey'], '5100 g'],
['generated control 2', ['250', 'ml', ' Water '], '249 g'],
['generated control 3', ['1', 'ml', '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: tablespoons per cup', ['3', 'tsp', ' Water '], '15 g'],
['repair check: tablespoons per cup', ['120', 'tsp', 'water, sifted'], '531 g'],
['generated control 1', ['15', 'cup', 'butter'], '3405 g'],
['generated control 2', ['5', 'ml', 'water'], '5.0 g'],
['generated control 3', ['5', 'cup', 'butter'], '1135 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: tablespoons per cup', ['15', 'tsp', ' Sugar '], '63 g'],
['repair check: tablespoons per cup', ['5', 'tsp', 'sugar'], '21 g'],
['generated control 1', ['100', 'ml', ' Water '], '100 g'],
['generated control 2', ['15', 'ml', 'packed flour'], '7.6 g'],
['generated control 3', ['15', 'ml', 'flour, sifted'], '6.8 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: tablespoons per cup', ['2', 'tbsp', 'water'], '30 g'],
['repair check: tablespoons per cup', ['100', 'tsp', 'FLOUR'], '250 g'],
['generated control 1', ['1/4', 'tbsp', 'sugar, sifted'], '2.8 g'],
['generated control 2', ['1/2', 'cup', 'FLOUR'], '60 g'],
['generated control 3', ['3/4', 'tsp', ' Packed Flour '], '1.9 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| one cup flour | 120 g | 120 g | Passed |
| exactly ten grams | 10 g | 10 g | Passed |
| packed brown sugar | 213 g | 213 g | Passed |
| regression: tablespoons per cup | 1475 g | 1475 g | Passed |
| repair check: tablespoons per cup | 74 g | 74 g | Passed |
| generated control 1 | 12000 g | 12000 g | Passed |
| generated control 2 | 7.8 g | 7.8 g | Passed |
| generated control 3 | 0.3 g | 0.3 g | Passed |
SHA-256 / 4202c818ba9f3bae5485be95d99db8ac4eddad77a3f612f112b5ee3da6f5fe3d
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.951621+00:00.
Case digest / e3a064c847bacb9e67a44151244b8bdcf44cec234b9155ff6a426e639e085308