FA-70931 / Weather index computation / Open access
Shade apparent temperature: wind speed units · case 01
Breezy days feel implausibly cold; a 36 km/h wind lowers the value by 25 degrees.
ROOT CAUSE
Wind in km/h is used where the formula expects m/s.
VERIFIED REPAIR
Convert with km/h / 3.6.
Unsuccessful approach: Dividing by 1.609344 converts to mph, still overstating the wind term.
Case contract
Input air temperature degC, RH percent, wind in km/h measured at 10 m. e = RH/100*6.105*exp(17.27*Ta/(237.7+Ta)) hPa; wind in m/s = km/h / 3.6; AT = Ta + 0.33e - 0.70ws - 4.00 rounded to 0.1.
Why this case matters
Feels-like temperature on consumer forecasts uses this non-radiative apparent temperature.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(ta, rh, wind_kmh):
e = rh / 100.0 * 6.105 * math.exp(17.27 * ta / (237.7 + ta))
ws = wind_kmh
at = ta + 0.33 * e - 0.70 * ws - 4.00
return round(at, 1)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['-5 C 10% RH wind 0 km/h', [-5, 10, 0], -8.9], ['-5 C 10% RH wind 10 km/h', [-5, 10, 10], -10.8], ['-5 C 10% RH wind 36 km/h', [-5, 10, 36], -15.9], ['-5 C 10% RH wind 72 km/h', [-5, 10, 72], -22.9], ['-5 C 50% RH wind 0 km/h', [-5, 50, 0], -8.3], ['-5 C 50% RH wind 10 km/h', [-5, 50, 10], -10.2], ['-5 C 50% RH wind 36 km/h', [-5, 50, 36], -15.3], ['-5 C 50% RH wind 72 km/h', [-5, 50, 72], -22.3]], [['-5 C 50% RH wind 10 km/h', [-5, 50, 10], -10.2], ['-5 C 50% RH wind 72 km/h', [-5, 50, 72], -22.3], ['-5 C 90% RH wind 0 km/h', [-5, 90, 0], -7.7], ['-5 C 90% RH wind 10 km/h', [-5, 90, 10], -9.7], ['-5 C 90% RH wind 36 km/h', [-5, 90, 36], -14.7], ['-5 C 90% RH wind 72 km/h', [-5, 90, 72], -21.7], ['0 C 10% RH wind 0 km/h', [0, 10, 0], -3.8], ['0 C 10% RH wind 10 km/h', [0, 10, 10], -5.7]], [['-5 C 90% RH wind 10 km/h', [-5, 90, 10], -9.7], ['0 C 10% RH wind 36 km/h', [0, 10, 36], -10.8], ['0 C 10% RH wind 72 km/h', [0, 10, 72], -17.8], ['0 C 50% RH wind 0 km/h', [0, 50, 0], -3.0], ['0 C 50% RH wind 10 km/h', [0, 50, 10], -4.9], ['0 C 50% RH wind 36 km/h', [0, 50, 36], -10.0], ['0 C 50% RH wind 72 km/h', [0, 50, 72], -17.0], ['0 C 90% RH wind 0 km/h', [0, 90, 0], -2.2]], [['0 C 10% RH wind 10 km/h', [0, 10, 10], -5.7], ['0 C 90% RH wind 10 km/h', [0, 90, 10], -4.1], ['0 C 90% RH wind 36 km/h', [0, 90, 36], -9.2], ['0 C 90% RH wind 72 km/h', [0, 90, 72], -16.2], ['12 C 10% RH wind 0 km/h', [12, 10, 0], 8.5], ['12 C 10% RH wind 10 km/h', [12, 10, 10], 6.5], ['12 C 10% RH wind 36 km/h', [12, 10, 36], 1.5], ['12 C 10% RH wind 72 km/h', [12, 10, 72], -5.5]], [['0 C 50% RH wind 10 km/h', [0, 50, 10], -4.9], ['12 C 50% RH wind 0 km/h', [12, 50, 0], 10.3], ['12 C 50% RH wind 10 km/h', [12, 50, 10], 8.4], ['12 C 50% RH wind 36 km/h', [12, 50, 36], 3.3], ['12 C 50% RH wind 72 km/h', [12, 50, 72], -3.7], ['12 C 90% RH wind 0 km/h', [12, 90, 0], 12.2], ['12 C 90% RH wind 10 km/h', [12, 90, 10], 10.2], ['12 C 90% RH wind 36 km/h', [12, 90, 36], 5.2]]]
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 |
|---|---|---|---|
| -5 C 10% RH wind 0 km/h | -8.9 | -8.9 | Passed |
| -5 C 10% RH wind 10 km/h | -15.9 | -10.8 | Failed |
| -5 C 10% RH wind 36 km/h | -34.1 | -15.9 | Failed |
| -5 C 10% RH wind 72 km/h | -59.3 | -22.9 | Failed |
| -5 C 50% RH wind 0 km/h | -8.3 | -8.3 | Passed |
| -5 C 50% RH wind 10 km/h | -15.3 | -10.2 | Failed |
| -5 C 50% RH wind 36 km/h | -33.5 | -15.3 | Failed |
| -5 C 50% RH wind 72 km/h | -58.7 | -22.3 | Failed |
SHA-256 / 573612d68f5f87d4349f0ee8133c1e54215282dec9a6d395add045988362e816
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(ta, rh, wind_kmh):
e = rh / 100.0 * 6.105 * math.exp(17.27 * ta / (237.7 + ta))
ws = wind_kmh / 1.609344
at = ta + 0.33 * e - 0.70 * ws - 4.00
return round(at, 1)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['-5 C 10% RH wind 0 km/h', [-5, 10, 0], -8.9], ['-5 C 10% RH wind 10 km/h', [-5, 10, 10], -10.8], ['-5 C 10% RH wind 36 km/h', [-5, 10, 36], -15.9], ['-5 C 10% RH wind 72 km/h', [-5, 10, 72], -22.9], ['-5 C 50% RH wind 0 km/h', [-5, 50, 0], -8.3], ['-5 C 50% RH wind 10 km/h', [-5, 50, 10], -10.2], ['-5 C 50% RH wind 36 km/h', [-5, 50, 36], -15.3], ['-5 C 50% RH wind 72 km/h', [-5, 50, 72], -22.3]], [['-5 C 50% RH wind 10 km/h', [-5, 50, 10], -10.2], ['-5 C 50% RH wind 72 km/h', [-5, 50, 72], -22.3], ['-5 C 90% RH wind 0 km/h', [-5, 90, 0], -7.7], ['-5 C 90% RH wind 10 km/h', [-5, 90, 10], -9.7], ['-5 C 90% RH wind 36 km/h', [-5, 90, 36], -14.7], ['-5 C 90% RH wind 72 km/h', [-5, 90, 72], -21.7], ['0 C 10% RH wind 0 km/h', [0, 10, 0], -3.8], ['0 C 10% RH wind 10 km/h', [0, 10, 10], -5.7]], [['-5 C 90% RH wind 10 km/h', [-5, 90, 10], -9.7], ['0 C 10% RH wind 36 km/h', [0, 10, 36], -10.8], ['0 C 10% RH wind 72 km/h', [0, 10, 72], -17.8], ['0 C 50% RH wind 0 km/h', [0, 50, 0], -3.0], ['0 C 50% RH wind 10 km/h', [0, 50, 10], -4.9], ['0 C 50% RH wind 36 km/h', [0, 50, 36], -10.0], ['0 C 50% RH wind 72 km/h', [0, 50, 72], -17.0], ['0 C 90% RH wind 0 km/h', [0, 90, 0], -2.2]], [['0 C 10% RH wind 10 km/h', [0, 10, 10], -5.7], ['0 C 90% RH wind 10 km/h', [0, 90, 10], -4.1], ['0 C 90% RH wind 36 km/h', [0, 90, 36], -9.2], ['0 C 90% RH wind 72 km/h', [0, 90, 72], -16.2], ['12 C 10% RH wind 0 km/h', [12, 10, 0], 8.5], ['12 C 10% RH wind 10 km/h', [12, 10, 10], 6.5], ['12 C 10% RH wind 36 km/h', [12, 10, 36], 1.5], ['12 C 10% RH wind 72 km/h', [12, 10, 72], -5.5]], [['0 C 50% RH wind 10 km/h', [0, 50, 10], -4.9], ['12 C 50% RH wind 0 km/h', [12, 50, 0], 10.3], ['12 C 50% RH wind 10 km/h', [12, 50, 10], 8.4], ['12 C 50% RH wind 36 km/h', [12, 50, 36], 3.3], ['12 C 50% RH wind 72 km/h', [12, 50, 72], -3.7], ['12 C 90% RH wind 0 km/h', [12, 90, 0], 12.2], ['12 C 90% RH wind 10 km/h', [12, 90, 10], 10.2], ['12 C 90% RH wind 36 km/h', [12, 90, 36], 5.2]]]
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 |
|---|---|---|---|
| -5 C 10% RH wind 0 km/h | -8.9 | -8.9 | Passed |
| -5 C 10% RH wind 10 km/h | -13.2 | -10.8 | Failed |
| -5 C 10% RH wind 36 km/h | -24.5 | -15.9 | Failed |
| -5 C 10% RH wind 72 km/h | -40.2 | -22.9 | Failed |
| -5 C 50% RH wind 0 km/h | -8.3 | -8.3 | Passed |
| -5 C 50% RH wind 10 km/h | -12.7 | -10.2 | Failed |
| -5 C 50% RH wind 36 km/h | -24.0 | -15.3 | Failed |
| -5 C 50% RH wind 72 km/h | -39.6 | -22.3 | Failed |
SHA-256 / 54b668bc91073803a725b3baf67fba8e81e074ec0e68a49b6bf4cfc9619d162e
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(ta, rh, wind_kmh):
e = rh / 100.0 * 6.105 * math.exp(17.27 * ta / (237.7 + ta))
ws = wind_kmh / 3.6
at = ta + 0.33 * e - 0.70 * ws - 4.00
return round(at, 1)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['-5 C 10% RH wind 0 km/h', [-5, 10, 0], -8.9], ['-5 C 10% RH wind 10 km/h', [-5, 10, 10], -10.8], ['-5 C 10% RH wind 36 km/h', [-5, 10, 36], -15.9], ['-5 C 10% RH wind 72 km/h', [-5, 10, 72], -22.9], ['-5 C 50% RH wind 0 km/h', [-5, 50, 0], -8.3], ['-5 C 50% RH wind 10 km/h', [-5, 50, 10], -10.2], ['-5 C 50% RH wind 36 km/h', [-5, 50, 36], -15.3], ['-5 C 50% RH wind 72 km/h', [-5, 50, 72], -22.3]], [['-5 C 50% RH wind 10 km/h', [-5, 50, 10], -10.2], ['-5 C 50% RH wind 72 km/h', [-5, 50, 72], -22.3], ['-5 C 90% RH wind 0 km/h', [-5, 90, 0], -7.7], ['-5 C 90% RH wind 10 km/h', [-5, 90, 10], -9.7], ['-5 C 90% RH wind 36 km/h', [-5, 90, 36], -14.7], ['-5 C 90% RH wind 72 km/h', [-5, 90, 72], -21.7], ['0 C 10% RH wind 0 km/h', [0, 10, 0], -3.8], ['0 C 10% RH wind 10 km/h', [0, 10, 10], -5.7]], [['-5 C 90% RH wind 10 km/h', [-5, 90, 10], -9.7], ['0 C 10% RH wind 36 km/h', [0, 10, 36], -10.8], ['0 C 10% RH wind 72 km/h', [0, 10, 72], -17.8], ['0 C 50% RH wind 0 km/h', [0, 50, 0], -3.0], ['0 C 50% RH wind 10 km/h', [0, 50, 10], -4.9], ['0 C 50% RH wind 36 km/h', [0, 50, 36], -10.0], ['0 C 50% RH wind 72 km/h', [0, 50, 72], -17.0], ['0 C 90% RH wind 0 km/h', [0, 90, 0], -2.2]], [['0 C 10% RH wind 10 km/h', [0, 10, 10], -5.7], ['0 C 90% RH wind 10 km/h', [0, 90, 10], -4.1], ['0 C 90% RH wind 36 km/h', [0, 90, 36], -9.2], ['0 C 90% RH wind 72 km/h', [0, 90, 72], -16.2], ['12 C 10% RH wind 0 km/h', [12, 10, 0], 8.5], ['12 C 10% RH wind 10 km/h', [12, 10, 10], 6.5], ['12 C 10% RH wind 36 km/h', [12, 10, 36], 1.5], ['12 C 10% RH wind 72 km/h', [12, 10, 72], -5.5]], [['0 C 50% RH wind 10 km/h', [0, 50, 10], -4.9], ['12 C 50% RH wind 0 km/h', [12, 50, 0], 10.3], ['12 C 50% RH wind 10 km/h', [12, 50, 10], 8.4], ['12 C 50% RH wind 36 km/h', [12, 50, 36], 3.3], ['12 C 50% RH wind 72 km/h', [12, 50, 72], -3.7], ['12 C 90% RH wind 0 km/h', [12, 90, 0], 12.2], ['12 C 90% RH wind 10 km/h', [12, 90, 10], 10.2], ['12 C 90% RH wind 36 km/h', [12, 90, 36], 5.2]]]
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 |
|---|---|---|---|
| -5 C 10% RH wind 0 km/h | -8.9 | -8.9 | Passed |
| -5 C 10% RH wind 10 km/h | -10.8 | -10.8 | Passed |
| -5 C 10% RH wind 36 km/h | -15.9 | -15.9 | Passed |
| -5 C 10% RH wind 72 km/h | -22.9 | -22.9 | Passed |
| -5 C 50% RH wind 0 km/h | -8.3 | -8.3 | Passed |
| -5 C 50% RH wind 10 km/h | -10.2 | -10.2 | Passed |
| -5 C 50% RH wind 36 km/h | -15.3 | -15.3 | Passed |
| -5 C 50% RH wind 72 km/h | -22.3 | -22.3 | Passed |
SHA-256 / 2c5326c695f0a4664a65b5a92f56ba4ee02630b275fd0ca145c11a792a09feb5
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.155129+00:00.
Case digest / d00baca7d12061a6eb72e28e445b4c66153875cf789f7585dbed778474760098