FA-97271 / Recipe scaling and nutrition / Open access
Macronutrient target splitter: protein floor · case 01
A 120 kg athlete on 1500 kcal gets 56 g protein.
ROOT CAUSE
The 1.6 g/kg protein floor is not applied.
VERIFIED REPAIR
Apply ceiling(1.6*weight) as a floor.
Unsuccessful approach: Flooring the per-kg target lets protein fall a gram short.
Case contract
split = [protein%, carb%, fat%] must sum to 100 else "error: split". protein_g = max(half-up kcal*p/400, ceiling(1.6*weight_kg)). Remaining kcal = kcal - 4*protein_g is divided between carb and fat in the ratio c:f; fat_g = half-up(rem*f/(c+f)/9); carb_g = half-up((rem - 9*fat_g)/4). Return [protein_g, carb_g, fat_g].
Why this case matters
Meal-plan generators turn calorie targets into gram targets with a protein floor by body weight.
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(kcal, weight_kg, split):
p, c, f = split
if p + c + f != 100:
return 'error: split'
def r(x):
return math.floor(x + Fraction(1, 2))
protein_g = max(r(Fraction(kcal * p, 400)), 0)
rem = kcal - 4 * protein_g
fat_g = r(Fraction(rem * f, c + f) / 9)
carb_g = r(Fraction(rem - 9 * fat_g, 4))
return [protein_g, carb_g, fat_g]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['balanced', [2000, 70, [30, 40, 30]], [150, 199, 67]],
['protein floor binds', [1500, 120, [15, 55, 30]], [192, 118, 29]],
['bad split', [2000, 70, [30, 40, 31]], 'error: split'],
['regression: protein floor', [2500, 91, [15, 55, 30]], [146, 310, 75]],
['repair check: protein floor', [1500, 118, [30, 40, 30]], [189, 107, 35]],
['generated control 1', [3000, 120, [20, 50, 25]], 'error: split'],
['generated control 2', [1500, 118, [30, 40, 29]], 'error: split'],
['generated control 3', [2000, 50, [40, 30, 30]], [200, 149, 67]]],
[['protein floor binds', [1500, 120, [15, 55, 30]], [192, 118, 29]],
['bad split', [2000, 70, [30, 40, 31]], 'error: split'],
['split under 100', [2000, 70, [30, 40, 20]], 'error: split'],
['regression: protein floor', [1500, 118, [25, 45, 30]], [189, 112, 33]],
['repair check: protein floor', [1800, 118, [25, 45, 30]], [189, 158, 46]],
['generated control 1', [2200, 91, [40, 30, 30]], [220, 166, 73]],
['generated control 2', [2200, 118, [40, 30, 30]], [220, 166, 73]],
['generated control 3', [2500, 72, [20, 50, 30]], [125, 313, 83]]],
[['bad split', [2000, 70, [30, 40, 31]], 'error: split'],
['split under 100', [2000, 70, [30, 40, 20]], 'error: split'],
['fractional floor', [1200, 83, [20, 50, 30]], [133, 104, 28]],
['regression: protein floor', [1500, 100, [25, 45, 30]], [160, 130, 38]],
['repair check: protein floor', [2000, 118, [10, 60, 30]], [189, 208, 46]],
['generated control 1', [2200, 50, [10, 60, 30]], [80, 313, 70]],
['generated control 2', [1500, 50, [35, 35, 30]], [131, 132, 50]],
['generated control 3', [1500, 60, [30, 40, 29]], 'error: split']],
[['split under 100', [2000, 70, [30, 40, 20]], 'error: split'],
['fractional floor', [1200, 83, [20, 50, 30]], [133, 104, 28]],
['balanced', [2000, 70, [30, 40, 30]], [150, 199, 67]],
['regression: protein floor', [2000, 60, [15, 55, 30]], [96, 262, 63]],
['repair check: protein floor', [1800, 118, [40, 30, 30]], [189, 131, 58]],
['generated control 1', [2500, 100, [35, 35, 30]], [219, 219, 83]],
['generated control 2', [3000, 83, [30, 40, 29]], 'error: split'],
['generated control 3', [1500, 60, [30, 40, 29]], 'error: split']],
[['fractional floor', [1200, 83, [20, 50, 30]], [133, 104, 28]],
['balanced', [2000, 70, [30, 40, 30]], [150, 199, 67]],
['protein floor binds', [1500, 120, [15, 55, 30]], [192, 118, 29]],
['regression: protein floor', [2500, 120, [15, 55, 30]], [192, 280, 68]],
['repair check: protein floor', [3000, 91, [15, 55, 30]], [146, 390, 95]],
['generated control 1', [3000, 91, [35, 35, 30]], [263, 262, 100]],
['generated control 2', [2000, 72, [25, 45, 30]], [125, 224, 67]],
['generated control 3', [3000, 50, [15, 55, 30]], [113, 412, 100]]]]
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 |
|---|---|---|---|
| balanced | [150, 199, 67] | [150, 199, 67] | Passed |
| protein floor binds | [56, 207, 50] | [192, 118, 29] | Failed |
| bad split | error: split | error: split | Passed |
| regression: protein floor | [94, 344, 83] | [146, 310, 75] | Failed |
| repair check: protein floor | [113, 150, 50] | [189, 107, 35] | Failed |
| generated control 1 | error: split | error: split | Passed |
| generated control 2 | error: split | error: split | Passed |
| generated control 3 | [200, 149, 67] | [200, 149, 67] | Passed |
SHA-256 / 8b6cbc5fac9463172b55385ec217da3c125926fd4d771227a81edaca9907d6b5
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(kcal, weight_kg, split):
p, c, f = split
if p + c + f != 100:
return 'error: split'
def r(x):
return math.floor(x + Fraction(1, 2))
protein_g = max(r(Fraction(kcal * p, 400)), math.floor(Fraction(16, 10) * weight_kg))
rem = kcal - 4 * protein_g
fat_g = r(Fraction(rem * f, c + f) / 9)
carb_g = r(Fraction(rem - 9 * fat_g, 4))
return [protein_g, carb_g, fat_g]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['balanced', [2000, 70, [30, 40, 30]], [150, 199, 67]],
['protein floor binds', [1500, 120, [15, 55, 30]], [192, 118, 29]],
['bad split', [2000, 70, [30, 40, 31]], 'error: split'],
['regression: protein floor', [2500, 91, [15, 55, 30]], [146, 310, 75]],
['repair check: protein floor', [1500, 118, [30, 40, 30]], [189, 107, 35]],
['generated control 1', [3000, 120, [20, 50, 25]], 'error: split'],
['generated control 2', [1500, 118, [30, 40, 29]], 'error: split'],
['generated control 3', [2000, 50, [40, 30, 30]], [200, 149, 67]]],
[['protein floor binds', [1500, 120, [15, 55, 30]], [192, 118, 29]],
['bad split', [2000, 70, [30, 40, 31]], 'error: split'],
['split under 100', [2000, 70, [30, 40, 20]], 'error: split'],
['regression: protein floor', [1500, 118, [25, 45, 30]], [189, 112, 33]],
['repair check: protein floor', [1800, 118, [25, 45, 30]], [189, 158, 46]],
['generated control 1', [2200, 91, [40, 30, 30]], [220, 166, 73]],
['generated control 2', [2200, 118, [40, 30, 30]], [220, 166, 73]],
['generated control 3', [2500, 72, [20, 50, 30]], [125, 313, 83]]],
[['bad split', [2000, 70, [30, 40, 31]], 'error: split'],
['split under 100', [2000, 70, [30, 40, 20]], 'error: split'],
['fractional floor', [1200, 83, [20, 50, 30]], [133, 104, 28]],
['regression: protein floor', [1500, 100, [25, 45, 30]], [160, 130, 38]],
['repair check: protein floor', [2000, 118, [10, 60, 30]], [189, 208, 46]],
['generated control 1', [2200, 50, [10, 60, 30]], [80, 313, 70]],
['generated control 2', [1500, 50, [35, 35, 30]], [131, 132, 50]],
['generated control 3', [1500, 60, [30, 40, 29]], 'error: split']],
[['split under 100', [2000, 70, [30, 40, 20]], 'error: split'],
['fractional floor', [1200, 83, [20, 50, 30]], [133, 104, 28]],
['balanced', [2000, 70, [30, 40, 30]], [150, 199, 67]],
['regression: protein floor', [2000, 60, [15, 55, 30]], [96, 262, 63]],
['repair check: protein floor', [1800, 118, [40, 30, 30]], [189, 131, 58]],
['generated control 1', [2500, 100, [35, 35, 30]], [219, 219, 83]],
['generated control 2', [3000, 83, [30, 40, 29]], 'error: split'],
['generated control 3', [1500, 60, [30, 40, 29]], 'error: split']],
[['fractional floor', [1200, 83, [20, 50, 30]], [133, 104, 28]],
['balanced', [2000, 70, [30, 40, 30]], [150, 199, 67]],
['protein floor binds', [1500, 120, [15, 55, 30]], [192, 118, 29]],
['regression: protein floor', [2500, 120, [15, 55, 30]], [192, 280, 68]],
['repair check: protein floor', [3000, 91, [15, 55, 30]], [146, 390, 95]],
['generated control 1', [3000, 91, [35, 35, 30]], [263, 262, 100]],
['generated control 2', [2000, 72, [25, 45, 30]], [125, 224, 67]],
['generated control 3', [3000, 50, [15, 55, 30]], [113, 412, 100]]]]
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 |
|---|---|---|---|
| balanced | [150, 199, 67] | [150, 199, 67] | Passed |
| protein floor binds | [192, 118, 29] | [192, 118, 29] | Passed |
| bad split | error: split | error: split | Passed |
| regression: protein floor | [145, 311, 75] | [146, 310, 75] | Failed |
| repair check: protein floor | [188, 106, 36] | [189, 107, 35] | Failed |
| generated control 1 | error: split | error: split | Passed |
| generated control 2 | error: split | error: split | Passed |
| generated control 3 | [200, 149, 67] | [200, 149, 67] | Passed |
SHA-256 / 239b21bbc5273d50e7224e1984db0a376defc1f01e9be708b31151cbfdafc844
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(kcal, weight_kg, split):
p, c, f = split
if p + c + f != 100:
return 'error: split'
def r(x):
return math.floor(x + Fraction(1, 2))
protein_g = max(r(Fraction(kcal * p, 400)), math.ceil(Fraction(16, 10) * weight_kg))
rem = kcal - 4 * protein_g
fat_g = r(Fraction(rem * f, c + f) / 9)
carb_g = r(Fraction(rem - 9 * fat_g, 4))
return [protein_g, carb_g, fat_g]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['balanced', [2000, 70, [30, 40, 30]], [150, 199, 67]],
['protein floor binds', [1500, 120, [15, 55, 30]], [192, 118, 29]],
['bad split', [2000, 70, [30, 40, 31]], 'error: split'],
['regression: protein floor', [2500, 91, [15, 55, 30]], [146, 310, 75]],
['repair check: protein floor', [1500, 118, [30, 40, 30]], [189, 107, 35]],
['generated control 1', [3000, 120, [20, 50, 25]], 'error: split'],
['generated control 2', [1500, 118, [30, 40, 29]], 'error: split'],
['generated control 3', [2000, 50, [40, 30, 30]], [200, 149, 67]]],
[['protein floor binds', [1500, 120, [15, 55, 30]], [192, 118, 29]],
['bad split', [2000, 70, [30, 40, 31]], 'error: split'],
['split under 100', [2000, 70, [30, 40, 20]], 'error: split'],
['regression: protein floor', [1500, 118, [25, 45, 30]], [189, 112, 33]],
['repair check: protein floor', [1800, 118, [25, 45, 30]], [189, 158, 46]],
['generated control 1', [2200, 91, [40, 30, 30]], [220, 166, 73]],
['generated control 2', [2200, 118, [40, 30, 30]], [220, 166, 73]],
['generated control 3', [2500, 72, [20, 50, 30]], [125, 313, 83]]],
[['bad split', [2000, 70, [30, 40, 31]], 'error: split'],
['split under 100', [2000, 70, [30, 40, 20]], 'error: split'],
['fractional floor', [1200, 83, [20, 50, 30]], [133, 104, 28]],
['regression: protein floor', [1500, 100, [25, 45, 30]], [160, 130, 38]],
['repair check: protein floor', [2000, 118, [10, 60, 30]], [189, 208, 46]],
['generated control 1', [2200, 50, [10, 60, 30]], [80, 313, 70]],
['generated control 2', [1500, 50, [35, 35, 30]], [131, 132, 50]],
['generated control 3', [1500, 60, [30, 40, 29]], 'error: split']],
[['split under 100', [2000, 70, [30, 40, 20]], 'error: split'],
['fractional floor', [1200, 83, [20, 50, 30]], [133, 104, 28]],
['balanced', [2000, 70, [30, 40, 30]], [150, 199, 67]],
['regression: protein floor', [2000, 60, [15, 55, 30]], [96, 262, 63]],
['repair check: protein floor', [1800, 118, [40, 30, 30]], [189, 131, 58]],
['generated control 1', [2500, 100, [35, 35, 30]], [219, 219, 83]],
['generated control 2', [3000, 83, [30, 40, 29]], 'error: split'],
['generated control 3', [1500, 60, [30, 40, 29]], 'error: split']],
[['fractional floor', [1200, 83, [20, 50, 30]], [133, 104, 28]],
['balanced', [2000, 70, [30, 40, 30]], [150, 199, 67]],
['protein floor binds', [1500, 120, [15, 55, 30]], [192, 118, 29]],
['regression: protein floor', [2500, 120, [15, 55, 30]], [192, 280, 68]],
['repair check: protein floor', [3000, 91, [15, 55, 30]], [146, 390, 95]],
['generated control 1', [3000, 91, [35, 35, 30]], [263, 262, 100]],
['generated control 2', [2000, 72, [25, 45, 30]], [125, 224, 67]],
['generated control 3', [3000, 50, [15, 55, 30]], [113, 412, 100]]]]
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 |
|---|---|---|---|
| balanced | [150, 199, 67] | [150, 199, 67] | Passed |
| protein floor binds | [192, 118, 29] | [192, 118, 29] | Passed |
| bad split | error: split | error: split | Passed |
| regression: protein floor | [146, 310, 75] | [146, 310, 75] | Passed |
| repair check: protein floor | [189, 107, 35] | [189, 107, 35] | Passed |
| generated control 1 | error: split | error: split | Passed |
| generated control 2 | error: split | error: split | Passed |
| generated control 3 | [200, 149, 67] | [200, 149, 67] | Passed |
SHA-256 / 30facebc75308d0251a67e7a4ff9d0b156de6aa7dede51f5d02ed25aef432037
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:30.533801+00:00.
Case digest / 7be8c0797ba6b08588ecc60bfeb5bb3cf56d88fca75ffa808feba89551198c13