FA-70946 / Weather index computation / Open access
Shade apparent temperature: wind cooling sign · case 01
Stronger wind makes it feel warmer.
ROOT CAUSE
The wind term is added rather than subtracted.
VERIFIED REPAIR
Subtract 0.70 times wind speed in m/s.
Unsuccessful approach: Restoring the sign but using 0.07 removes most of the wind cooling.
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 / 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 | -6.9 | -10.8 | Failed |
| -5 C 10% RH wind 36 km/h | -1.9 | -15.9 | Failed |
| -5 C 10% RH wind 72 km/h | 5.1 | -22.9 | Failed |
| -5 C 50% RH wind 0 km/h | -8.3 | -8.3 | Passed |
| -5 C 50% RH wind 10 km/h | -6.4 | -10.2 | Failed |
| -5 C 50% RH wind 36 km/h | -1.3 | -15.3 | Failed |
| -5 C 50% RH wind 72 km/h | 5.7 | -22.3 | Failed |
SHA-256 / 79edee94ef4cc6670293a38aebf3ca05c5e202b4143899f37bdb4f195169f426
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 / 3.6
at = ta + 0.33 * e - 0.07 * 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 | -9.1 | -10.8 | Failed |
| -5 C 10% RH wind 36 km/h | -9.6 | -15.9 | Failed |
| -5 C 10% RH wind 72 km/h | -10.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 | -8.5 | -10.2 | Failed |
| -5 C 50% RH wind 36 km/h | -9.0 | -15.3 | Failed |
| -5 C 50% RH wind 72 km/h | -9.7 | -22.3 | Failed |
SHA-256 / c230e8f821cb49e6921d958716f47db47d88bcff49a4265b232a9ef17f482e3f
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.360598+00:00.
Case digest / 23bf7057befce9211e758957bd734166c1209184c3194cb6909b92d1bb88dbca