FAILURE MAP
← Case archive

FA-96996 / Recipe scaling and nutrition / Open access

Atwater energy calculator: kilojoule rounding stage · case 01

kJ disagrees with the exact energy because it is converted from the rounded kcal.

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

ROOT CAUSE

Kilojoules are computed from the already rounded kilocalories.

VERIFIED REPAIR

Convert the exact kcal to kJ and round once.

Unsuccessful approach: Floor-dividing the rounded kcal compounds two rounding steps.

Case contract

Gram amounts as strings. Total carbohydrate includes fiber and polyols; available carb = max(0, carb - fiber - polyol). kcal = 4*protein + 9*fat + 4*available + 2*fiber + 7*alcohol + 2.4*polyol. Return [kcal, kJ, fat_energy_pct]: kcal half-up integer of the exact energy, kJ half-up integer of exact kcal * 4.184, fat pct = half-up of 9*fat/exact kcal*100 (0 if energy is 0).

Why this case matters

Recipe energy totals use factor systems where fiber and sugar alcohols are not full carbohydrate.

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(protein, fat, carb, fiber, alcohol, polyol):
    p, fat, carb, fib, alc, poly = (Fraction(v) for v in (protein, fat, carb, fiber, alcohol, polyol))
    avail = carb - fib - poly
    avail = max(avail, Fraction(0))
    exact = 4 * p + 9 * fat + 4 * avail + 2 * fib + 7 * alc + Fraction(12, 5) * poly
    def r(x):
        return math.floor(x + Fraction(1, 2))
    kj = r(r(exact) * Fraction(4184, 1000))
    pct_fat = r(9 * fat * 100 / exact) if exact else 0
    return [r(exact), kj, pct_fat]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['all zero', ['0', '0', '0', '0', '0', '0'], [0, 0, 0]],
  ['fat only', ['0', '10', '0', '0', '0', '0'], [90, 377, 100]],
  ['fiber heavier than carb', ['5', '1', '3', '6', '0', '0'], [41, 172, 22]],
  ['regression: kilojoule rounding stage', ['17', '20', '13', '5', '0', '4'], [284, 1187, 63]],
  ['repair check: kilojoule rounding stage', ['2', '11', '10', '2', '0', '4'], [137, 572, 72]],
  ['generated control 1', ['32', '85/4', '53', '3', '0', '4'], [519, 2171, 37]],
  ['generated control 2', ['39', '0', '20', '3', '14', '10'], [312, 1305, 0]],
  ['generated control 3', ['31', '21/2', '31', '5', '14', '4'], [424, 1774, 22]]],
 [['fat only', ['0', '10', '0', '0', '0', '0'], [90, 377, 100]],
  ['fiber heavier than carb', ['5', '1', '3', '6', '0', '0'], [41, 172, 22]],
  ['sugar-free candy', ['0', '5', '30', '1', '0', '20'], [131, 548, 34]],
  ['regression: kilojoule rounding stage', ['36', '51/4', '19', '3', '0', '0'], [329, 1375, 35]],
  ['repair check: kilojoule rounding stage', ['40', '5/2', '59', '8', '14', '0'], [501, 2094, 4]],
  ['generated control 1', ['37', '11', '23', '1', '5', '0'], [372, 1556, 27]],
  ['generated control 2', ['21', '2', '0', '2', '5', '4'], [151, 630, 12]],
  ['generated control 3', ['8', '4', '18', '1', '14', '10'], [220, 920, 16]]],
 [['fiber heavier than carb', ['5', '1', '3', '6', '0', '0'], [41, 172, 22]],
  ['sugar-free candy', ['0', '5', '30', '1', '0', '20'], [131, 548, 34]],
  ['cocktail', ['0', '0', '12', '0', '14', '0'], [146, 611, 0]],
  ['regression: kilojoule rounding stage', ['18', '13', '33', '1', '14', '4'], [411, 1718, 28]],
  ['repair check: kilojoule rounding stage', ['34', '51/2', '31', '33', '5', '4'], [476, 1992, 48]],
  ['generated control 1', ['23', '14', '45', '47', '5', '10'], [371, 1552, 34]],
  ['generated control 2', ['31', '16', '4', '1', '0', '10'], [294, 1230, 49]],
  ['generated control 3', ['21', '26', '0', '5', '0', '0'], [328, 1372, 71]]],
 [['sugar-free candy', ['0', '5', '30', '1', '0', '20'], [131, 548, 34]],
  ['cocktail', ['0', '0', '12', '0', '14', '0'], [146, 611, 0]],
  ['all zero', ['0', '0', '0', '0', '0', '0'], [0, 0, 0]],
  ['regression: kilojoule rounding stage', ['2', '6', '0', '8', '0', '4'], [88, 367, 62]],
  ['repair check: kilojoule rounding stage', ['20', '23', '57', '59', '0', '0'], [405, 1695, 51]],
  ['generated control 1', ['31', '6', '40', '0', '14', '0'], [436, 1824, 12]],
  ['generated control 2', ['24', '2', '46', '3', '0', '0'], [292, 1222, 6]],
  ['generated control 3', ['8', '18', '15', '2', '0', '0'], [250, 1046, 65]]],
 [['cocktail', ['0', '0', '12', '0', '14', '0'], [146, 611, 0]],
  ['all zero', ['0', '0', '0', '0', '0', '0'], [0, 0, 0]],
  ['fat only', ['0', '10', '0', '0', '0', '0'], [90, 377, 100]],
  ['regression: kilojoule rounding stage', ['26', '9', '59', '0', '5', '4'], [450, 1881, 18]],
  ['repair check: kilojoule rounding stage', ['11', '23', '15', '8', '5', '0'], [330, 1381, 63]],
  ['generated control 1', ['8', '6', '0', '1', '14', '10'], [210, 879, 26]],
  ['generated control 2', ['36', '10', '7', '0', '5', '0'], [297, 1243, 30]],
  ['generated control 3', ['4', '26', '7', '9', '14', '10'], [390, 1632, 60]]]]
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
all zero[0, 0, 0][0, 0, 0]Passed
fat only[90, 377, 100][90, 377, 100]Passed
fiber heavier than carb[41, 172, 22][41, 172, 22]Passed
regression: kilojoule rounding stage[284, 1188, 63][284, 1187, 63]Failed
repair check: kilojoule rounding stage[137, 573, 72][137, 572, 72]Failed
generated control 1[519, 2171, 37][519, 2171, 37]Passed
generated control 2[312, 1305, 0][312, 1305, 0]Passed
generated control 3[424, 1774, 22][424, 1774, 22]Passed

SHA-256 / ce1ce982ffd46381ad0bd09202df1caa1d1085ec34619194f594897b0f292667

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(protein, fat, carb, fiber, alcohol, polyol):
    p, fat, carb, fib, alc, poly = (Fraction(v) for v in (protein, fat, carb, fiber, alcohol, polyol))
    avail = carb - fib - poly
    avail = max(avail, Fraction(0))
    exact = 4 * p + 9 * fat + 4 * avail + 2 * fib + 7 * alc + Fraction(12, 5) * poly
    def r(x):
        return math.floor(x + Fraction(1, 2))
    kj = r(exact) * 4184 // 1000
    pct_fat = r(9 * fat * 100 / exact) if exact else 0
    return [r(exact), kj, pct_fat]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['all zero', ['0', '0', '0', '0', '0', '0'], [0, 0, 0]],
  ['fat only', ['0', '10', '0', '0', '0', '0'], [90, 377, 100]],
  ['fiber heavier than carb', ['5', '1', '3', '6', '0', '0'], [41, 172, 22]],
  ['regression: kilojoule rounding stage', ['17', '20', '13', '5', '0', '4'], [284, 1187, 63]],
  ['repair check: kilojoule rounding stage', ['2', '11', '10', '2', '0', '4'], [137, 572, 72]],
  ['generated control 1', ['32', '85/4', '53', '3', '0', '4'], [519, 2171, 37]],
  ['generated control 2', ['39', '0', '20', '3', '14', '10'], [312, 1305, 0]],
  ['generated control 3', ['31', '21/2', '31', '5', '14', '4'], [424, 1774, 22]]],
 [['fat only', ['0', '10', '0', '0', '0', '0'], [90, 377, 100]],
  ['fiber heavier than carb', ['5', '1', '3', '6', '0', '0'], [41, 172, 22]],
  ['sugar-free candy', ['0', '5', '30', '1', '0', '20'], [131, 548, 34]],
  ['regression: kilojoule rounding stage', ['36', '51/4', '19', '3', '0', '0'], [329, 1375, 35]],
  ['repair check: kilojoule rounding stage', ['40', '5/2', '59', '8', '14', '0'], [501, 2094, 4]],
  ['generated control 1', ['37', '11', '23', '1', '5', '0'], [372, 1556, 27]],
  ['generated control 2', ['21', '2', '0', '2', '5', '4'], [151, 630, 12]],
  ['generated control 3', ['8', '4', '18', '1', '14', '10'], [220, 920, 16]]],
 [['fiber heavier than carb', ['5', '1', '3', '6', '0', '0'], [41, 172, 22]],
  ['sugar-free candy', ['0', '5', '30', '1', '0', '20'], [131, 548, 34]],
  ['cocktail', ['0', '0', '12', '0', '14', '0'], [146, 611, 0]],
  ['regression: kilojoule rounding stage', ['18', '13', '33', '1', '14', '4'], [411, 1718, 28]],
  ['repair check: kilojoule rounding stage', ['34', '51/2', '31', '33', '5', '4'], [476, 1992, 48]],
  ['generated control 1', ['23', '14', '45', '47', '5', '10'], [371, 1552, 34]],
  ['generated control 2', ['31', '16', '4', '1', '0', '10'], [294, 1230, 49]],
  ['generated control 3', ['21', '26', '0', '5', '0', '0'], [328, 1372, 71]]],
 [['sugar-free candy', ['0', '5', '30', '1', '0', '20'], [131, 548, 34]],
  ['cocktail', ['0', '0', '12', '0', '14', '0'], [146, 611, 0]],
  ['all zero', ['0', '0', '0', '0', '0', '0'], [0, 0, 0]],
  ['regression: kilojoule rounding stage', ['2', '6', '0', '8', '0', '4'], [88, 367, 62]],
  ['repair check: kilojoule rounding stage', ['20', '23', '57', '59', '0', '0'], [405, 1695, 51]],
  ['generated control 1', ['31', '6', '40', '0', '14', '0'], [436, 1824, 12]],
  ['generated control 2', ['24', '2', '46', '3', '0', '0'], [292, 1222, 6]],
  ['generated control 3', ['8', '18', '15', '2', '0', '0'], [250, 1046, 65]]],
 [['cocktail', ['0', '0', '12', '0', '14', '0'], [146, 611, 0]],
  ['all zero', ['0', '0', '0', '0', '0', '0'], [0, 0, 0]],
  ['fat only', ['0', '10', '0', '0', '0', '0'], [90, 377, 100]],
  ['regression: kilojoule rounding stage', ['26', '9', '59', '0', '5', '4'], [450, 1881, 18]],
  ['repair check: kilojoule rounding stage', ['11', '23', '15', '8', '5', '0'], [330, 1381, 63]],
  ['generated control 1', ['8', '6', '0', '1', '14', '10'], [210, 879, 26]],
  ['generated control 2', ['36', '10', '7', '0', '5', '0'], [297, 1243, 30]],
  ['generated control 3', ['4', '26', '7', '9', '14', '10'], [390, 1632, 60]]]]
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
all zero[0, 0, 0][0, 0, 0]Passed
fat only[90, 376, 100][90, 377, 100]Failed
fiber heavier than carb[41, 171, 22][41, 172, 22]Failed
regression: kilojoule rounding stage[284, 1188, 63][284, 1187, 63]Failed
repair check: kilojoule rounding stage[137, 573, 72][137, 572, 72]Failed
generated control 1[519, 2171, 37][519, 2171, 37]Passed
generated control 2[312, 1305, 0][312, 1305, 0]Passed
generated control 3[424, 1774, 22][424, 1774, 22]Passed

SHA-256 / 46e1ce965e9690b29a2399d3c3c435adcedf6ff0f2d0e635ae7a42ffe868dc84

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(protein, fat, carb, fiber, alcohol, polyol):
    p, fat, carb, fib, alc, poly = (Fraction(v) for v in (protein, fat, carb, fiber, alcohol, polyol))
    avail = carb - fib - poly
    avail = max(avail, Fraction(0))
    exact = 4 * p + 9 * fat + 4 * avail + 2 * fib + 7 * alc + Fraction(12, 5) * poly
    def r(x):
        return math.floor(x + Fraction(1, 2))
    kj = r(exact * Fraction(4184, 1000))
    pct_fat = r(9 * fat * 100 / exact) if exact else 0
    return [r(exact), kj, pct_fat]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['all zero', ['0', '0', '0', '0', '0', '0'], [0, 0, 0]],
  ['fat only', ['0', '10', '0', '0', '0', '0'], [90, 377, 100]],
  ['fiber heavier than carb', ['5', '1', '3', '6', '0', '0'], [41, 172, 22]],
  ['regression: kilojoule rounding stage', ['17', '20', '13', '5', '0', '4'], [284, 1187, 63]],
  ['repair check: kilojoule rounding stage', ['2', '11', '10', '2', '0', '4'], [137, 572, 72]],
  ['generated control 1', ['32', '85/4', '53', '3', '0', '4'], [519, 2171, 37]],
  ['generated control 2', ['39', '0', '20', '3', '14', '10'], [312, 1305, 0]],
  ['generated control 3', ['31', '21/2', '31', '5', '14', '4'], [424, 1774, 22]]],
 [['fat only', ['0', '10', '0', '0', '0', '0'], [90, 377, 100]],
  ['fiber heavier than carb', ['5', '1', '3', '6', '0', '0'], [41, 172, 22]],
  ['sugar-free candy', ['0', '5', '30', '1', '0', '20'], [131, 548, 34]],
  ['regression: kilojoule rounding stage', ['36', '51/4', '19', '3', '0', '0'], [329, 1375, 35]],
  ['repair check: kilojoule rounding stage', ['40', '5/2', '59', '8', '14', '0'], [501, 2094, 4]],
  ['generated control 1', ['37', '11', '23', '1', '5', '0'], [372, 1556, 27]],
  ['generated control 2', ['21', '2', '0', '2', '5', '4'], [151, 630, 12]],
  ['generated control 3', ['8', '4', '18', '1', '14', '10'], [220, 920, 16]]],
 [['fiber heavier than carb', ['5', '1', '3', '6', '0', '0'], [41, 172, 22]],
  ['sugar-free candy', ['0', '5', '30', '1', '0', '20'], [131, 548, 34]],
  ['cocktail', ['0', '0', '12', '0', '14', '0'], [146, 611, 0]],
  ['regression: kilojoule rounding stage', ['18', '13', '33', '1', '14', '4'], [411, 1718, 28]],
  ['repair check: kilojoule rounding stage', ['34', '51/2', '31', '33', '5', '4'], [476, 1992, 48]],
  ['generated control 1', ['23', '14', '45', '47', '5', '10'], [371, 1552, 34]],
  ['generated control 2', ['31', '16', '4', '1', '0', '10'], [294, 1230, 49]],
  ['generated control 3', ['21', '26', '0', '5', '0', '0'], [328, 1372, 71]]],
 [['sugar-free candy', ['0', '5', '30', '1', '0', '20'], [131, 548, 34]],
  ['cocktail', ['0', '0', '12', '0', '14', '0'], [146, 611, 0]],
  ['all zero', ['0', '0', '0', '0', '0', '0'], [0, 0, 0]],
  ['regression: kilojoule rounding stage', ['2', '6', '0', '8', '0', '4'], [88, 367, 62]],
  ['repair check: kilojoule rounding stage', ['20', '23', '57', '59', '0', '0'], [405, 1695, 51]],
  ['generated control 1', ['31', '6', '40', '0', '14', '0'], [436, 1824, 12]],
  ['generated control 2', ['24', '2', '46', '3', '0', '0'], [292, 1222, 6]],
  ['generated control 3', ['8', '18', '15', '2', '0', '0'], [250, 1046, 65]]],
 [['cocktail', ['0', '0', '12', '0', '14', '0'], [146, 611, 0]],
  ['all zero', ['0', '0', '0', '0', '0', '0'], [0, 0, 0]],
  ['fat only', ['0', '10', '0', '0', '0', '0'], [90, 377, 100]],
  ['regression: kilojoule rounding stage', ['26', '9', '59', '0', '5', '4'], [450, 1881, 18]],
  ['repair check: kilojoule rounding stage', ['11', '23', '15', '8', '5', '0'], [330, 1381, 63]],
  ['generated control 1', ['8', '6', '0', '1', '14', '10'], [210, 879, 26]],
  ['generated control 2', ['36', '10', '7', '0', '5', '0'], [297, 1243, 30]],
  ['generated control 3', ['4', '26', '7', '9', '14', '10'], [390, 1632, 60]]]]
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
all zero[0, 0, 0][0, 0, 0]Passed
fat only[90, 377, 100][90, 377, 100]Passed
fiber heavier than carb[41, 172, 22][41, 172, 22]Passed
regression: kilojoule rounding stage[284, 1187, 63][284, 1187, 63]Passed
repair check: kilojoule rounding stage[137, 572, 72][137, 572, 72]Passed
generated control 1[519, 2171, 37][519, 2171, 37]Passed
generated control 2[312, 1305, 0][312, 1305, 0]Passed
generated control 3[424, 1774, 22][424, 1774, 22]Passed

SHA-256 / 4fa56a0fa42b301e8ea1ec0b548ffe0cab6e36813bbcb295cee049eb3af5ef8c

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

Case digest / 8e88b62f5429872eebc196a1815d48568f624c930714dbf6fbf509a0ade28939