FA-70961 / Weather index computation / Open access
Livestock temperature-humidity index: mild band upper edge · case 01
A THI of exactly 79.0 is reported as mild instead of moderate.
ROOT CAUSE
The mild band includes its exclusive upper bound.
VERIFIED REPAIR
Classify 72 <= THI < 79 as mild.
Unsuccessful approach: Rounding THI to an integer for the comparison classifies 78.5 to 78.9 as moderate.
Case contract
Input barn temperature degC and RH percent. THI = (1.8T+32) - (0.55 - 0.0055RH)(1.8T - 26); THI is rounded to 0.1 first and the stress level is taken from the rounded value: <72 none, <79 mild, <89 moderate, <99 severe, else emergency.
Why this case matters
Dairy heat-stress alerts and cooling automation key off THI bands.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(t_c, rh):
thi = (1.8 * t_c + 32) - (0.55 - 0.0055 * rh) * (1.8 * t_c - 26)
thi = round(thi, 1)
if thi < 72:
level = "none"
elif thi <= 79:
level = "mild"
elif thi < 89:
level = "moderate"
elif thi < 99:
level = "severe"
else:
level = "emergency"
return [thi, level]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['15 C barn at 20% RH', [15, 20], [58.6, 'none']], ['15 C barn at 40% RH', [15, 40], [58.7, 'none']], ['15 C barn at 55% RH', [15, 55], [58.8, 'none']], ['15 C barn at 70% RH', [15, 70], [58.8, 'none']], ['15 C barn at 85% RH', [15, 85], [58.9, 'none']], ['15 C barn at 100% RH', [15, 100], [59.0, 'none']], ['27 C barn at 85% RH', [27, 85], [78.7, 'mild']], ['THI on 79 boundary 26.1 C 100%', [26.1, 100], [79.0, 'moderate']]], [['21 C barn at 40% RH', [21, 40], [65.9, 'none']], ['21 C barn at 55% RH', [21, 55], [66.9, 'none']], ['21 C barn at 70% RH', [21, 70], [67.9, 'none']], ['21 C barn at 85% RH', [21, 85], [68.8, 'none']], ['21 C barn at 100% RH', [21, 100], [69.8, 'none']], ['22 C barn at 20% RH', [22, 20], [65.6, 'none']], ['26 C barn at 100% RH', [26, 100], [78.8, 'mild']], ['THI on 79 boundary 26.4 C 96%', [26.4, 96], [79.0, 'moderate']]], [['22 C barn at 55% RH', [22, 55], [68.2, 'none']], ['22 C barn at 70% RH', [22, 70], [69.4, 'none']], ['22 C barn at 85% RH', [22, 85], [70.5, 'none']], ['22 C barn at 100% RH', [22, 100], [71.6, 'none']], ['24 C barn at 20% RH', [24, 20], [67.6, 'none']], ['24 C barn at 40% RH', [24, 40], [69.5, 'none']], ['27 C barn at 85% RH', [27, 85], [78.7, 'mild']], ['THI on 79 boundary 26.2 C 99%', [26.2, 99], [79.0, 'moderate']]], [['24 C barn at 70% RH', [24, 70], [72.4, 'mild']], ['24 C barn at 85% RH', [24, 85], [73.8, 'mild']], ['24 C barn at 100% RH', [24, 100], [75.2, 'mild']], ['25 C barn at 20% RH', [25, 20], [68.6, 'none']], ['25 C barn at 40% RH', [25, 40], [70.7, 'none']], ['25 C barn at 55% RH', [25, 55], [72.3, 'mild']], ['26 C barn at 100% RH', [26, 100], [78.8, 'mild']], ['THI on 79 boundary 26.5 C 94%', [26.5, 94], [79.0, 'moderate']]], [['25 C barn at 85% RH', [25, 85], [75.4, 'mild']], ['25 C barn at 100% RH', [25, 100], [77.0, 'mild']], ['26 C barn at 20% RH', [26, 20], [69.6, 'none']], ['26 C barn at 40% RH', [26, 40], [71.9, 'none']], ['26 C barn at 55% RH', [26, 55], [73.7, 'mild']], ['26 C barn at 70% RH', [26, 70], [75.4, 'mild']], ['27 C barn at 85% RH', [27, 85], [78.7, 'mild']], ['THI on 79 boundary 26.3 C 97%', [26.3, 97], [79.0, 'moderate']]]]
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 |
|---|---|---|---|
| 15 C barn at 20% RH | [58.6, 'none'] | [58.6, 'none'] | Passed |
| 15 C barn at 40% RH | [58.7, 'none'] | [58.7, 'none'] | Passed |
| 15 C barn at 55% RH | [58.8, 'none'] | [58.8, 'none'] | Passed |
| 15 C barn at 70% RH | [58.8, 'none'] | [58.8, 'none'] | Passed |
| 15 C barn at 85% RH | [58.9, 'none'] | [58.9, 'none'] | Passed |
| 15 C barn at 100% RH | [59.0, 'none'] | [59.0, 'none'] | Passed |
| 27 C barn at 85% RH | [78.7, 'mild'] | [78.7, 'mild'] | Passed |
| THI on 79 boundary 26.1 C 100% | [79.0, 'mild'] | [79.0, 'moderate'] | Failed |
SHA-256 / f0534320135c1215385b94362582276592e0695d7ec580dfe7270b57c981c777
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(t_c, rh):
thi = (1.8 * t_c + 32) - (0.55 - 0.0055 * rh) * (1.8 * t_c - 26)
thi = round(thi, 1)
if thi < 72:
level = "none"
elif round(thi) < 79:
level = "mild"
elif thi < 89:
level = "moderate"
elif thi < 99:
level = "severe"
else:
level = "emergency"
return [thi, level]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['15 C barn at 20% RH', [15, 20], [58.6, 'none']], ['15 C barn at 40% RH', [15, 40], [58.7, 'none']], ['15 C barn at 55% RH', [15, 55], [58.8, 'none']], ['15 C barn at 70% RH', [15, 70], [58.8, 'none']], ['15 C barn at 85% RH', [15, 85], [58.9, 'none']], ['15 C barn at 100% RH', [15, 100], [59.0, 'none']], ['27 C barn at 85% RH', [27, 85], [78.7, 'mild']], ['THI on 79 boundary 26.1 C 100%', [26.1, 100], [79.0, 'moderate']]], [['21 C barn at 40% RH', [21, 40], [65.9, 'none']], ['21 C barn at 55% RH', [21, 55], [66.9, 'none']], ['21 C barn at 70% RH', [21, 70], [67.9, 'none']], ['21 C barn at 85% RH', [21, 85], [68.8, 'none']], ['21 C barn at 100% RH', [21, 100], [69.8, 'none']], ['22 C barn at 20% RH', [22, 20], [65.6, 'none']], ['26 C barn at 100% RH', [26, 100], [78.8, 'mild']], ['THI on 79 boundary 26.4 C 96%', [26.4, 96], [79.0, 'moderate']]], [['22 C barn at 55% RH', [22, 55], [68.2, 'none']], ['22 C barn at 70% RH', [22, 70], [69.4, 'none']], ['22 C barn at 85% RH', [22, 85], [70.5, 'none']], ['22 C barn at 100% RH', [22, 100], [71.6, 'none']], ['24 C barn at 20% RH', [24, 20], [67.6, 'none']], ['24 C barn at 40% RH', [24, 40], [69.5, 'none']], ['27 C barn at 85% RH', [27, 85], [78.7, 'mild']], ['THI on 79 boundary 26.2 C 99%', [26.2, 99], [79.0, 'moderate']]], [['24 C barn at 70% RH', [24, 70], [72.4, 'mild']], ['24 C barn at 85% RH', [24, 85], [73.8, 'mild']], ['24 C barn at 100% RH', [24, 100], [75.2, 'mild']], ['25 C barn at 20% RH', [25, 20], [68.6, 'none']], ['25 C barn at 40% RH', [25, 40], [70.7, 'none']], ['25 C barn at 55% RH', [25, 55], [72.3, 'mild']], ['26 C barn at 100% RH', [26, 100], [78.8, 'mild']], ['THI on 79 boundary 26.5 C 94%', [26.5, 94], [79.0, 'moderate']]], [['25 C barn at 85% RH', [25, 85], [75.4, 'mild']], ['25 C barn at 100% RH', [25, 100], [77.0, 'mild']], ['26 C barn at 20% RH', [26, 20], [69.6, 'none']], ['26 C barn at 40% RH', [26, 40], [71.9, 'none']], ['26 C barn at 55% RH', [26, 55], [73.7, 'mild']], ['26 C barn at 70% RH', [26, 70], [75.4, 'mild']], ['27 C barn at 85% RH', [27, 85], [78.7, 'mild']], ['THI on 79 boundary 26.3 C 97%', [26.3, 97], [79.0, 'moderate']]]]
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 |
|---|---|---|---|
| 15 C barn at 20% RH | [58.6, 'none'] | [58.6, 'none'] | Passed |
| 15 C barn at 40% RH | [58.7, 'none'] | [58.7, 'none'] | Passed |
| 15 C barn at 55% RH | [58.8, 'none'] | [58.8, 'none'] | Passed |
| 15 C barn at 70% RH | [58.8, 'none'] | [58.8, 'none'] | Passed |
| 15 C barn at 85% RH | [58.9, 'none'] | [58.9, 'none'] | Passed |
| 15 C barn at 100% RH | [59.0, 'none'] | [59.0, 'none'] | Passed |
| 27 C barn at 85% RH | [78.7, 'moderate'] | [78.7, 'mild'] | Failed |
| THI on 79 boundary 26.1 C 100% | [79.0, 'moderate'] | [79.0, 'moderate'] | Passed |
SHA-256 / c39fd6935b96965cd07fa438f8d43911aa24e2d9f9a82813ddd14d203c5496dd
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(t_c, rh):
thi = (1.8 * t_c + 32) - (0.55 - 0.0055 * rh) * (1.8 * t_c - 26)
thi = round(thi, 1)
if thi < 72:
level = "none"
elif thi < 79:
level = "mild"
elif thi < 89:
level = "moderate"
elif thi < 99:
level = "severe"
else:
level = "emergency"
return [thi, level]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['15 C barn at 20% RH', [15, 20], [58.6, 'none']], ['15 C barn at 40% RH', [15, 40], [58.7, 'none']], ['15 C barn at 55% RH', [15, 55], [58.8, 'none']], ['15 C barn at 70% RH', [15, 70], [58.8, 'none']], ['15 C barn at 85% RH', [15, 85], [58.9, 'none']], ['15 C barn at 100% RH', [15, 100], [59.0, 'none']], ['27 C barn at 85% RH', [27, 85], [78.7, 'mild']], ['THI on 79 boundary 26.1 C 100%', [26.1, 100], [79.0, 'moderate']]], [['21 C barn at 40% RH', [21, 40], [65.9, 'none']], ['21 C barn at 55% RH', [21, 55], [66.9, 'none']], ['21 C barn at 70% RH', [21, 70], [67.9, 'none']], ['21 C barn at 85% RH', [21, 85], [68.8, 'none']], ['21 C barn at 100% RH', [21, 100], [69.8, 'none']], ['22 C barn at 20% RH', [22, 20], [65.6, 'none']], ['26 C barn at 100% RH', [26, 100], [78.8, 'mild']], ['THI on 79 boundary 26.4 C 96%', [26.4, 96], [79.0, 'moderate']]], [['22 C barn at 55% RH', [22, 55], [68.2, 'none']], ['22 C barn at 70% RH', [22, 70], [69.4, 'none']], ['22 C barn at 85% RH', [22, 85], [70.5, 'none']], ['22 C barn at 100% RH', [22, 100], [71.6, 'none']], ['24 C barn at 20% RH', [24, 20], [67.6, 'none']], ['24 C barn at 40% RH', [24, 40], [69.5, 'none']], ['27 C barn at 85% RH', [27, 85], [78.7, 'mild']], ['THI on 79 boundary 26.2 C 99%', [26.2, 99], [79.0, 'moderate']]], [['24 C barn at 70% RH', [24, 70], [72.4, 'mild']], ['24 C barn at 85% RH', [24, 85], [73.8, 'mild']], ['24 C barn at 100% RH', [24, 100], [75.2, 'mild']], ['25 C barn at 20% RH', [25, 20], [68.6, 'none']], ['25 C barn at 40% RH', [25, 40], [70.7, 'none']], ['25 C barn at 55% RH', [25, 55], [72.3, 'mild']], ['26 C barn at 100% RH', [26, 100], [78.8, 'mild']], ['THI on 79 boundary 26.5 C 94%', [26.5, 94], [79.0, 'moderate']]], [['25 C barn at 85% RH', [25, 85], [75.4, 'mild']], ['25 C barn at 100% RH', [25, 100], [77.0, 'mild']], ['26 C barn at 20% RH', [26, 20], [69.6, 'none']], ['26 C barn at 40% RH', [26, 40], [71.9, 'none']], ['26 C barn at 55% RH', [26, 55], [73.7, 'mild']], ['26 C barn at 70% RH', [26, 70], [75.4, 'mild']], ['27 C barn at 85% RH', [27, 85], [78.7, 'mild']], ['THI on 79 boundary 26.3 C 97%', [26.3, 97], [79.0, 'moderate']]]]
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 |
|---|---|---|---|
| 15 C barn at 20% RH | [58.6, 'none'] | [58.6, 'none'] | Passed |
| 15 C barn at 40% RH | [58.7, 'none'] | [58.7, 'none'] | Passed |
| 15 C barn at 55% RH | [58.8, 'none'] | [58.8, 'none'] | Passed |
| 15 C barn at 70% RH | [58.8, 'none'] | [58.8, 'none'] | Passed |
| 15 C barn at 85% RH | [58.9, 'none'] | [58.9, 'none'] | Passed |
| 15 C barn at 100% RH | [59.0, 'none'] | [59.0, 'none'] | Passed |
| 27 C barn at 85% RH | [78.7, 'mild'] | [78.7, 'mild'] | Passed |
| THI on 79 boundary 26.1 C 100% | [79.0, 'moderate'] | [79.0, 'moderate'] | Passed |
SHA-256 / 2e27110dad20e641ff9f2d683707e7c18fd65df92e60a5127c67109f931446d4
Verification & scope
Stipulated deterministic teaching model of an operational weather index; coefficients and thresholds are fixed by the contract and no claim of standards conformance is made. 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:48:25.443459+00:00.
Case digest / 436ff366dde1f7dcf3d3f271bbdb4044659133440cd83392c25cdf2224e15942