FA-97181 / Recipe scaling and nutrition / Open access
Roast timing and carryover planner: carryover by weight · case 01
A 4 kg medium-rare roast is pulled 2C too late because carryover follows doneness.
ROOT CAUSE
Carryover is chosen from the doneness instead of the roast weight.
VERIFIED REPAIR
Pick carryover from the weight bands.
Unsuccessful approach: Dropping the 3 kg tier under-predicts carryover for large roasts.
Case contract
Doneness (trimmed, lower) rare 52C/30 min per kg, medium rare 57/35, medium 63/40, well 71/50; unknown -> error; weight <= 0 -> error. Carryover 2C below 1.5 kg, 4C below 3 kg, else 6C. Beef and lamb pull at target - carryover. Poultry ignores doneness: pull at 74 (no carryover credit) and uses the well-done rate. cook_min = ceiling to a multiple of 5 of weight*rate. rest_min = half-up weight*5 clamped to [10, 30].
Why this case matters
Roast planners must account for carryover cooking and food-safety minimums for poultry.
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(weight_kg, doneness, cut):
T = {'rare': 52, 'medium rare': 57, 'medium': 63, 'well': 71}
PER = {'rare': 30, 'medium rare': 35, 'medium': 40, 'well': 50}
d = doneness.strip().lower()
if d not in T:
return 'error: doneness'
if weight_kg <= 0:
return 'error: weight'
w = Fraction(str(weight_kg))
carry = 2 if d == 'rare' else 4
if cut == 'poultry':
pull = 74
else:
pull = T[d] - carry
per = PER['well'] if cut == 'poultry' else PER[d]
cook = 5 * math.ceil(w * per / 5)
rest = min(30, max(10, math.floor(w * 5 + Fraction(1, 2))))
return {'pull_c': pull, 'cook_min': cook, 'rest_min': rest}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['small rare roast', [1, 'rare', 'beef'], {'cook_min': 30, 'pull_c': 50, 'rest_min': 10}],
['large medium roast', [4.2, 'medium', 'beef'], {'cook_min': 170, 'pull_c': 57, 'rest_min': 21}],
['chicken', [2, 'medium', 'poultry'], {'cook_min': 100, 'pull_c': 74, 'rest_min': 10}],
['regression: carryover by weight', [3, 'well', 'beef'], {'cook_min': 150, 'pull_c': 65, 'rest_min': 15}],
['repair check: carryover by weight', [3.5, 'rare', 'beef'],
{'cook_min': 105, 'pull_c': 46, 'rest_min': 18}],
['generated control 1', [2, 'rare', 'beef'], {'cook_min': 60, 'pull_c': 48, 'rest_min': 10}],
['generated control 2', [2, 'well', 'beef'], {'cook_min': 100, 'pull_c': 67, 'rest_min': 10}],
['generated control 3', [6, 'Medium', 'beef'], {'cook_min': 240, 'pull_c': 57, 'rest_min': 30}]],
[['large medium roast', [4.2, 'medium', 'beef'], {'cook_min': 170, 'pull_c': 57, 'rest_min': 21}],
['chicken', [2, 'medium', 'poultry'], {'cook_min': 100, 'pull_c': 74, 'rest_min': 10}],
['bad doneness', [2, 'blue', 'beef'], 'error: doneness'],
['regression: carryover by weight', [3, 'medium rare', 'beef'],
{'cook_min': 105, 'pull_c': 51, 'rest_min': 15}],
['repair check: carryover by weight', [4.2, 'rare', 'beef'],
{'cook_min': 130, 'pull_c': 46, 'rest_min': 21}],
['generated control 1', [1.5, 'well', 'beef'], {'cook_min': 75, 'pull_c': 67, 'rest_min': 10}],
['generated control 2', [0, 'medium rare', 'lamb'], 'error: weight'],
['generated control 3', [0, 'blue', 'beef'], 'error: doneness']],
[['chicken', [2, 'medium', 'poultry'], {'cook_min': 100, 'pull_c': 74, 'rest_min': 10}],
['bad doneness', [2, 'blue', 'beef'], 'error: doneness'],
['zero weight', [0, 'rare', 'beef'], 'error: weight'],
['regression: carryover by weight', [1, 'medium rare', 'beef'],
{'cook_min': 35, 'pull_c': 55, 'rest_min': 10}],
['repair check: carryover by weight', [4.2, 'Medium', 'beef'],
{'cook_min': 170, 'pull_c': 57, 'rest_min': 21}],
['generated control 1', [2.4, 'well', 'beef'], {'cook_min': 120, 'pull_c': 67, 'rest_min': 12}],
['generated control 2', [3.5, 'blue', 'beef'], 'error: doneness'],
['generated control 3', [1.2, 'blue', 'beef'], 'error: doneness']],
[['bad doneness', [2, 'blue', 'beef'], 'error: doneness'],
['zero weight', [0, 'rare', 'beef'], 'error: weight'],
['small rare roast', [1, 'rare', 'beef'], {'cook_min': 30, 'pull_c': 50, 'rest_min': 10}],
['regression: carryover by weight', [3, 'rare', 'beef'], {'cook_min': 90, 'pull_c': 46, 'rest_min': 15}],
['repair check: carryover by weight', [4.2, 'well', 'beef'],
{'cook_min': 210, 'pull_c': 65, 'rest_min': 21}],
['generated control 1', [1.2, 'medium rare', 'poultry'], {'cook_min': 60, 'pull_c': 74, 'rest_min': 10}],
['generated control 2', [0, 'blue', 'beef'], 'error: doneness'],
['generated control 3', [4.2, 'blue', 'poultry'], 'error: doneness']],
[['zero weight', [0, 'rare', 'beef'], 'error: weight'],
['small rare roast', [1, 'rare', 'beef'], {'cook_min': 30, 'pull_c': 50, 'rest_min': 10}],
['large medium roast', [4.2, 'medium', 'beef'], {'cook_min': 170, 'pull_c': 57, 'rest_min': 21}],
['regression: carryover by weight', [4.2, 'Medium', 'lamb'],
{'cook_min': 170, 'pull_c': 57, 'rest_min': 21}],
['repair check: carryover by weight', [3.5, 'Medium', 'lamb'],
{'cook_min': 140, 'pull_c': 57, 'rest_min': 18}],
['generated control 1', [3.5, 'blue', 'beef'], 'error: doneness'],
['generated control 2', [0.5, 'well', 'beef'], {'cook_min': 25, 'pull_c': 69, 'rest_min': 10}],
['generated control 3', [1.5, 'well', 'beef'], {'cook_min': 75, 'pull_c': 67, 'rest_min': 10}]]]
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 |
|---|---|---|---|
| small rare roast | {'cook_min': 30, 'pull_c': 50, 'rest_min': 10} | {'cook_min': 30, 'pull_c': 50, 'rest_min': 10} | Passed |
| large medium roast | {'cook_min': 170, 'pull_c': 59, 'rest_min': 21} | {'cook_min': 170, 'pull_c': 57, 'rest_min': 21} | Failed |
| chicken | {'cook_min': 100, 'pull_c': 74, 'rest_min': 10} | {'cook_min': 100, 'pull_c': 74, 'rest_min': 10} | Passed |
| regression: carryover by weight | {'cook_min': 150, 'pull_c': 67, 'rest_min': 15} | {'cook_min': 150, 'pull_c': 65, 'rest_min': 15} | Failed |
| repair check: carryover by weight | {'cook_min': 105, 'pull_c': 50, 'rest_min': 18} | {'cook_min': 105, 'pull_c': 46, 'rest_min': 18} | Failed |
| generated control 1 | {'cook_min': 60, 'pull_c': 50, 'rest_min': 10} | {'cook_min': 60, 'pull_c': 48, 'rest_min': 10} | Failed |
| generated control 2 | {'cook_min': 100, 'pull_c': 67, 'rest_min': 10} | {'cook_min': 100, 'pull_c': 67, 'rest_min': 10} | Passed |
| generated control 3 | {'cook_min': 240, 'pull_c': 59, 'rest_min': 30} | {'cook_min': 240, 'pull_c': 57, 'rest_min': 30} | Failed |
SHA-256 / 627741178f1973c1cd44a64cdfc59b3b2491e6a7520df0a61a1748b4b96c3440
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(weight_kg, doneness, cut):
T = {'rare': 52, 'medium rare': 57, 'medium': 63, 'well': 71}
PER = {'rare': 30, 'medium rare': 35, 'medium': 40, 'well': 50}
d = doneness.strip().lower()
if d not in T:
return 'error: doneness'
if weight_kg <= 0:
return 'error: weight'
w = Fraction(str(weight_kg))
carry = 2 if w < Fraction(3, 2) else 4
if cut == 'poultry':
pull = 74
else:
pull = T[d] - carry
per = PER['well'] if cut == 'poultry' else PER[d]
cook = 5 * math.ceil(w * per / 5)
rest = min(30, max(10, math.floor(w * 5 + Fraction(1, 2))))
return {'pull_c': pull, 'cook_min': cook, 'rest_min': rest}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['small rare roast', [1, 'rare', 'beef'], {'cook_min': 30, 'pull_c': 50, 'rest_min': 10}],
['large medium roast', [4.2, 'medium', 'beef'], {'cook_min': 170, 'pull_c': 57, 'rest_min': 21}],
['chicken', [2, 'medium', 'poultry'], {'cook_min': 100, 'pull_c': 74, 'rest_min': 10}],
['regression: carryover by weight', [3, 'well', 'beef'], {'cook_min': 150, 'pull_c': 65, 'rest_min': 15}],
['repair check: carryover by weight', [3.5, 'rare', 'beef'],
{'cook_min': 105, 'pull_c': 46, 'rest_min': 18}],
['generated control 1', [2, 'rare', 'beef'], {'cook_min': 60, 'pull_c': 48, 'rest_min': 10}],
['generated control 2', [2, 'well', 'beef'], {'cook_min': 100, 'pull_c': 67, 'rest_min': 10}],
['generated control 3', [6, 'Medium', 'beef'], {'cook_min': 240, 'pull_c': 57, 'rest_min': 30}]],
[['large medium roast', [4.2, 'medium', 'beef'], {'cook_min': 170, 'pull_c': 57, 'rest_min': 21}],
['chicken', [2, 'medium', 'poultry'], {'cook_min': 100, 'pull_c': 74, 'rest_min': 10}],
['bad doneness', [2, 'blue', 'beef'], 'error: doneness'],
['regression: carryover by weight', [3, 'medium rare', 'beef'],
{'cook_min': 105, 'pull_c': 51, 'rest_min': 15}],
['repair check: carryover by weight', [4.2, 'rare', 'beef'],
{'cook_min': 130, 'pull_c': 46, 'rest_min': 21}],
['generated control 1', [1.5, 'well', 'beef'], {'cook_min': 75, 'pull_c': 67, 'rest_min': 10}],
['generated control 2', [0, 'medium rare', 'lamb'], 'error: weight'],
['generated control 3', [0, 'blue', 'beef'], 'error: doneness']],
[['chicken', [2, 'medium', 'poultry'], {'cook_min': 100, 'pull_c': 74, 'rest_min': 10}],
['bad doneness', [2, 'blue', 'beef'], 'error: doneness'],
['zero weight', [0, 'rare', 'beef'], 'error: weight'],
['regression: carryover by weight', [1, 'medium rare', 'beef'],
{'cook_min': 35, 'pull_c': 55, 'rest_min': 10}],
['repair check: carryover by weight', [4.2, 'Medium', 'beef'],
{'cook_min': 170, 'pull_c': 57, 'rest_min': 21}],
['generated control 1', [2.4, 'well', 'beef'], {'cook_min': 120, 'pull_c': 67, 'rest_min': 12}],
['generated control 2', [3.5, 'blue', 'beef'], 'error: doneness'],
['generated control 3', [1.2, 'blue', 'beef'], 'error: doneness']],
[['bad doneness', [2, 'blue', 'beef'], 'error: doneness'],
['zero weight', [0, 'rare', 'beef'], 'error: weight'],
['small rare roast', [1, 'rare', 'beef'], {'cook_min': 30, 'pull_c': 50, 'rest_min': 10}],
['regression: carryover by weight', [3, 'rare', 'beef'], {'cook_min': 90, 'pull_c': 46, 'rest_min': 15}],
['repair check: carryover by weight', [4.2, 'well', 'beef'],
{'cook_min': 210, 'pull_c': 65, 'rest_min': 21}],
['generated control 1', [1.2, 'medium rare', 'poultry'], {'cook_min': 60, 'pull_c': 74, 'rest_min': 10}],
['generated control 2', [0, 'blue', 'beef'], 'error: doneness'],
['generated control 3', [4.2, 'blue', 'poultry'], 'error: doneness']],
[['zero weight', [0, 'rare', 'beef'], 'error: weight'],
['small rare roast', [1, 'rare', 'beef'], {'cook_min': 30, 'pull_c': 50, 'rest_min': 10}],
['large medium roast', [4.2, 'medium', 'beef'], {'cook_min': 170, 'pull_c': 57, 'rest_min': 21}],
['regression: carryover by weight', [4.2, 'Medium', 'lamb'],
{'cook_min': 170, 'pull_c': 57, 'rest_min': 21}],
['repair check: carryover by weight', [3.5, 'Medium', 'lamb'],
{'cook_min': 140, 'pull_c': 57, 'rest_min': 18}],
['generated control 1', [3.5, 'blue', 'beef'], 'error: doneness'],
['generated control 2', [0.5, 'well', 'beef'], {'cook_min': 25, 'pull_c': 69, 'rest_min': 10}],
['generated control 3', [1.5, 'well', 'beef'], {'cook_min': 75, 'pull_c': 67, 'rest_min': 10}]]]
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 |
|---|---|---|---|
| small rare roast | {'cook_min': 30, 'pull_c': 50, 'rest_min': 10} | {'cook_min': 30, 'pull_c': 50, 'rest_min': 10} | Passed |
| large medium roast | {'cook_min': 170, 'pull_c': 59, 'rest_min': 21} | {'cook_min': 170, 'pull_c': 57, 'rest_min': 21} | Failed |
| chicken | {'cook_min': 100, 'pull_c': 74, 'rest_min': 10} | {'cook_min': 100, 'pull_c': 74, 'rest_min': 10} | Passed |
| regression: carryover by weight | {'cook_min': 150, 'pull_c': 67, 'rest_min': 15} | {'cook_min': 150, 'pull_c': 65, 'rest_min': 15} | Failed |
| repair check: carryover by weight | {'cook_min': 105, 'pull_c': 48, 'rest_min': 18} | {'cook_min': 105, 'pull_c': 46, 'rest_min': 18} | Failed |
| generated control 1 | {'cook_min': 60, 'pull_c': 48, 'rest_min': 10} | {'cook_min': 60, 'pull_c': 48, 'rest_min': 10} | Passed |
| generated control 2 | {'cook_min': 100, 'pull_c': 67, 'rest_min': 10} | {'cook_min': 100, 'pull_c': 67, 'rest_min': 10} | Passed |
| generated control 3 | {'cook_min': 240, 'pull_c': 59, 'rest_min': 30} | {'cook_min': 240, 'pull_c': 57, 'rest_min': 30} | Failed |
SHA-256 / 125688691ec5e12a0702121a77ab455ef18fda8c8837cb1ceec1fbfd61a47d8a
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(weight_kg, doneness, cut):
T = {'rare': 52, 'medium rare': 57, 'medium': 63, 'well': 71}
PER = {'rare': 30, 'medium rare': 35, 'medium': 40, 'well': 50}
d = doneness.strip().lower()
if d not in T:
return 'error: doneness'
if weight_kg <= 0:
return 'error: weight'
w = Fraction(str(weight_kg))
carry = 2 if w < Fraction(3, 2) else 4 if w < 3 else 6
if cut == 'poultry':
pull = 74
else:
pull = T[d] - carry
per = PER['well'] if cut == 'poultry' else PER[d]
cook = 5 * math.ceil(w * per / 5)
rest = min(30, max(10, math.floor(w * 5 + Fraction(1, 2))))
return {'pull_c': pull, 'cook_min': cook, 'rest_min': rest}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['small rare roast', [1, 'rare', 'beef'], {'cook_min': 30, 'pull_c': 50, 'rest_min': 10}],
['large medium roast', [4.2, 'medium', 'beef'], {'cook_min': 170, 'pull_c': 57, 'rest_min': 21}],
['chicken', [2, 'medium', 'poultry'], {'cook_min': 100, 'pull_c': 74, 'rest_min': 10}],
['regression: carryover by weight', [3, 'well', 'beef'], {'cook_min': 150, 'pull_c': 65, 'rest_min': 15}],
['repair check: carryover by weight', [3.5, 'rare', 'beef'],
{'cook_min': 105, 'pull_c': 46, 'rest_min': 18}],
['generated control 1', [2, 'rare', 'beef'], {'cook_min': 60, 'pull_c': 48, 'rest_min': 10}],
['generated control 2', [2, 'well', 'beef'], {'cook_min': 100, 'pull_c': 67, 'rest_min': 10}],
['generated control 3', [6, 'Medium', 'beef'], {'cook_min': 240, 'pull_c': 57, 'rest_min': 30}]],
[['large medium roast', [4.2, 'medium', 'beef'], {'cook_min': 170, 'pull_c': 57, 'rest_min': 21}],
['chicken', [2, 'medium', 'poultry'], {'cook_min': 100, 'pull_c': 74, 'rest_min': 10}],
['bad doneness', [2, 'blue', 'beef'], 'error: doneness'],
['regression: carryover by weight', [3, 'medium rare', 'beef'],
{'cook_min': 105, 'pull_c': 51, 'rest_min': 15}],
['repair check: carryover by weight', [4.2, 'rare', 'beef'],
{'cook_min': 130, 'pull_c': 46, 'rest_min': 21}],
['generated control 1', [1.5, 'well', 'beef'], {'cook_min': 75, 'pull_c': 67, 'rest_min': 10}],
['generated control 2', [0, 'medium rare', 'lamb'], 'error: weight'],
['generated control 3', [0, 'blue', 'beef'], 'error: doneness']],
[['chicken', [2, 'medium', 'poultry'], {'cook_min': 100, 'pull_c': 74, 'rest_min': 10}],
['bad doneness', [2, 'blue', 'beef'], 'error: doneness'],
['zero weight', [0, 'rare', 'beef'], 'error: weight'],
['regression: carryover by weight', [1, 'medium rare', 'beef'],
{'cook_min': 35, 'pull_c': 55, 'rest_min': 10}],
['repair check: carryover by weight', [4.2, 'Medium', 'beef'],
{'cook_min': 170, 'pull_c': 57, 'rest_min': 21}],
['generated control 1', [2.4, 'well', 'beef'], {'cook_min': 120, 'pull_c': 67, 'rest_min': 12}],
['generated control 2', [3.5, 'blue', 'beef'], 'error: doneness'],
['generated control 3', [1.2, 'blue', 'beef'], 'error: doneness']],
[['bad doneness', [2, 'blue', 'beef'], 'error: doneness'],
['zero weight', [0, 'rare', 'beef'], 'error: weight'],
['small rare roast', [1, 'rare', 'beef'], {'cook_min': 30, 'pull_c': 50, 'rest_min': 10}],
['regression: carryover by weight', [3, 'rare', 'beef'], {'cook_min': 90, 'pull_c': 46, 'rest_min': 15}],
['repair check: carryover by weight', [4.2, 'well', 'beef'],
{'cook_min': 210, 'pull_c': 65, 'rest_min': 21}],
['generated control 1', [1.2, 'medium rare', 'poultry'], {'cook_min': 60, 'pull_c': 74, 'rest_min': 10}],
['generated control 2', [0, 'blue', 'beef'], 'error: doneness'],
['generated control 3', [4.2, 'blue', 'poultry'], 'error: doneness']],
[['zero weight', [0, 'rare', 'beef'], 'error: weight'],
['small rare roast', [1, 'rare', 'beef'], {'cook_min': 30, 'pull_c': 50, 'rest_min': 10}],
['large medium roast', [4.2, 'medium', 'beef'], {'cook_min': 170, 'pull_c': 57, 'rest_min': 21}],
['regression: carryover by weight', [4.2, 'Medium', 'lamb'],
{'cook_min': 170, 'pull_c': 57, 'rest_min': 21}],
['repair check: carryover by weight', [3.5, 'Medium', 'lamb'],
{'cook_min': 140, 'pull_c': 57, 'rest_min': 18}],
['generated control 1', [3.5, 'blue', 'beef'], 'error: doneness'],
['generated control 2', [0.5, 'well', 'beef'], {'cook_min': 25, 'pull_c': 69, 'rest_min': 10}],
['generated control 3', [1.5, 'well', 'beef'], {'cook_min': 75, 'pull_c': 67, 'rest_min': 10}]]]
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 |
|---|---|---|---|
| small rare roast | {'cook_min': 30, 'pull_c': 50, 'rest_min': 10} | {'cook_min': 30, 'pull_c': 50, 'rest_min': 10} | Passed |
| large medium roast | {'cook_min': 170, 'pull_c': 57, 'rest_min': 21} | {'cook_min': 170, 'pull_c': 57, 'rest_min': 21} | Passed |
| chicken | {'cook_min': 100, 'pull_c': 74, 'rest_min': 10} | {'cook_min': 100, 'pull_c': 74, 'rest_min': 10} | Passed |
| regression: carryover by weight | {'cook_min': 150, 'pull_c': 65, 'rest_min': 15} | {'cook_min': 150, 'pull_c': 65, 'rest_min': 15} | Passed |
| repair check: carryover by weight | {'cook_min': 105, 'pull_c': 46, 'rest_min': 18} | {'cook_min': 105, 'pull_c': 46, 'rest_min': 18} | Passed |
| generated control 1 | {'cook_min': 60, 'pull_c': 48, 'rest_min': 10} | {'cook_min': 60, 'pull_c': 48, 'rest_min': 10} | Passed |
| generated control 2 | {'cook_min': 100, 'pull_c': 67, 'rest_min': 10} | {'cook_min': 100, 'pull_c': 67, 'rest_min': 10} | Passed |
| generated control 3 | {'cook_min': 240, 'pull_c': 57, 'rest_min': 30} | {'cook_min': 240, 'pull_c': 57, 'rest_min': 30} | Passed |
SHA-256 / 23290931c3635884310359f6e27f2640bf2bdd00658a4f69d9fb1d949ce5ba0e
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:29.622362+00:00.
Case digest / a1f53540822d22c34202e9b6a044316a983c2a18f78f19092e71eb462b5566c8