FA-70886 / Weather index computation / Open access
Magnus dew point with ice branch: freezing branch boundary · case 01
Readings at exactly 0 degC are computed with ice constants.
ROOT CAUSE
The water/ice constant selection excludes 0 degC from the water branch.
VERIFIED REPAIR
Use the water constants for T >= 0.
Unsuccessful approach: Moving the boundary to -10 degC uses water constants for supercooled readings that the contract assigns to ice.
Case contract
Input temperature in degC and RH in percent. RH <= 0 or RH > 100 returns None. Use Magnus constants a=17.62, b=243.12 when T >= 0 and a=22.46, b=272.62 below freezing; g = ln(RH/100) + aT/(b+T); dew/frost point = b*g/(a-g) rounded to 0.01.
Why this case matters
Dew and frost point drive fog, icing and frost forecasts.
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):
if rh <= 0 or rh > 100:
return None
a, b = (17.62, 243.12) if t_c > 0 else (22.46, 272.62)
g = math.log(rh / 100.0) + a * t_c / (b + t_c)
return round(b * g / (a - g), 2)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['-20 C at 0% RH', [-20, 0], None], ['-20 C at 0.5% RH', [-20, 0.5], -65.32], ['-20 C at 5% RH', [-20, 5], -47.79], ['-20 C at 30% RH', [-20, 30], -31.95], ['-20 C at 50% RH', [-20, 50], -27.02], ['-20 C at 80% RH', [-20, 80], -22.3], ['-5 C at 5% RH', [-5, 5], -35.98], ['0 C at 0.5% RH', [0, 0.5], -56.21]], [['-20 C at 104% RH', [-20, 104], None], ['-5 C at 0% RH', [-5, 0], None], ['-5 C at 0.5% RH', [-5, 0.5], -55.32], ['-5 C at 5% RH', [-5, 5], -35.98], ['-5 C at 30% RH', [-5, 30], -18.38], ['-5 C at 50% RH', [-5, 50], -12.87], ['-0.5 C at 5% RH', [-0.5, 5], -32.47], ['0 C at 50% RH', [0, 50], -9.2]], [['-5 C at 5% RH', [-5, 5], -35.98], ['-5 C at 100% RH', [-5, 100], -5.0], ['-5 C at 104% RH', [-5, 104], None], ['-0.5 C at 0% RH', [-0.5, 0], None], ['-0.5 C at 0.5% RH', [-0.5, 0.5], -52.36], ['-0.5 C at 5% RH', [-0.5, 5], -32.47], ['-0.5 C at 30% RH', [-0.5, 30], -14.32], ['0 C at 5% RH', [0, 5], -35.33]], [['-0.5 C at 5% RH', [-0.5, 5], -32.47], ['-0.5 C at 80% RH', [-0.5, 80], -3.17], ['-0.5 C at 100% RH', [-0.5, 100], -0.5], ['-0.5 C at 104% RH', [-0.5, 104], None], ['0 C at 0% RH', [0, 0], None], ['0 C at 0.5% RH', [0, 0.5], -56.21], ['0 C at 5% RH', [0, 5], -35.33], ['0 C at 80% RH', [0, 80], -3.04]], [['-5 C at 5% RH', [-5, 5], -35.98], ['0 C at 30% RH', [0, 30], -15.55], ['0 C at 50% RH', [0, 50], -9.2], ['0 C at 80% RH', [0, 80], -3.04], ['0 C at 100% RH', [0, 100], 0.0], ['0 C at 104% RH', [0, 104], None], ['0.5 C at 0% RH', [0.5, 0], None], ['0.5 C at 0.5% RH', [0.5, 0.5], -55.91]]]
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 |
|---|---|---|---|
| -20 C at 0% RH | None | None | Passed |
| -20 C at 0.5% RH | -65.32 | -65.32 | Passed |
| -20 C at 5% RH | -47.79 | -47.79 | Passed |
| -20 C at 30% RH | -31.95 | -31.95 | Passed |
| -20 C at 50% RH | -27.02 | -27.02 | Passed |
| -20 C at 80% RH | -22.3 | -22.3 | Passed |
| -5 C at 5% RH | -35.98 | -35.98 | Passed |
| 0 C at 0.5% RH | -52.04 | -56.21 | Failed |
SHA-256 / 3ba5537a8d68fa59fb11b3c89e6352baba633b5567b0fe57589204dd32f4ebf9
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):
if rh <= 0 or rh > 100:
return None
a, b = (17.62, 243.12) if t_c >= -10 else (22.46, 272.62)
g = math.log(rh / 100.0) + a * t_c / (b + t_c)
return round(b * g / (a - g), 2)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['-20 C at 0% RH', [-20, 0], None], ['-20 C at 0.5% RH', [-20, 0.5], -65.32], ['-20 C at 5% RH', [-20, 5], -47.79], ['-20 C at 30% RH', [-20, 30], -31.95], ['-20 C at 50% RH', [-20, 50], -27.02], ['-20 C at 80% RH', [-20, 80], -22.3], ['-5 C at 5% RH', [-5, 5], -35.98], ['0 C at 0.5% RH', [0, 0.5], -56.21]], [['-20 C at 104% RH', [-20, 104], None], ['-5 C at 0% RH', [-5, 0], None], ['-5 C at 0.5% RH', [-5, 0.5], -55.32], ['-5 C at 5% RH', [-5, 5], -35.98], ['-5 C at 30% RH', [-5, 30], -18.38], ['-5 C at 50% RH', [-5, 50], -12.87], ['-0.5 C at 5% RH', [-0.5, 5], -32.47], ['0 C at 50% RH', [0, 50], -9.2]], [['-5 C at 5% RH', [-5, 5], -35.98], ['-5 C at 100% RH', [-5, 100], -5.0], ['-5 C at 104% RH', [-5, 104], None], ['-0.5 C at 0% RH', [-0.5, 0], None], ['-0.5 C at 0.5% RH', [-0.5, 0.5], -52.36], ['-0.5 C at 5% RH', [-0.5, 5], -32.47], ['-0.5 C at 30% RH', [-0.5, 30], -14.32], ['0 C at 5% RH', [0, 5], -35.33]], [['-0.5 C at 5% RH', [-0.5, 5], -32.47], ['-0.5 C at 80% RH', [-0.5, 80], -3.17], ['-0.5 C at 100% RH', [-0.5, 100], -0.5], ['-0.5 C at 104% RH', [-0.5, 104], None], ['0 C at 0% RH', [0, 0], None], ['0 C at 0.5% RH', [0, 0.5], -56.21], ['0 C at 5% RH', [0, 5], -35.33], ['0 C at 80% RH', [0, 80], -3.04]], [['-5 C at 5% RH', [-5, 5], -35.98], ['0 C at 30% RH', [0, 30], -15.55], ['0 C at 50% RH', [0, 50], -9.2], ['0 C at 80% RH', [0, 80], -3.04], ['0 C at 100% RH', [0, 100], 0.0], ['0 C at 104% RH', [0, 104], None], ['0.5 C at 0% RH', [0.5, 0], None], ['0.5 C at 0.5% RH', [0.5, 0.5], -55.91]]]
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 |
|---|---|---|---|
| -20 C at 0% RH | None | None | Passed |
| -20 C at 0.5% RH | -65.32 | -65.32 | Passed |
| -20 C at 5% RH | -47.79 | -47.79 | Passed |
| -20 C at 30% RH | -31.95 | -31.95 | Passed |
| -20 C at 50% RH | -27.02 | -27.02 | Passed |
| -20 C at 80% RH | -22.3 | -22.3 | Passed |
| -5 C at 5% RH | -38.99 | -35.98 | Failed |
| 0 C at 0.5% RH | -56.21 | -56.21 | Passed |
SHA-256 / 03fc4a54784a09fe519f08521e146d8397499cabec7f695886af860b6ebced91
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):
if rh <= 0 or rh > 100:
return None
a, b = (17.62, 243.12) if t_c >= 0 else (22.46, 272.62)
g = math.log(rh / 100.0) + a * t_c / (b + t_c)
return round(b * g / (a - g), 2)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['-20 C at 0% RH', [-20, 0], None], ['-20 C at 0.5% RH', [-20, 0.5], -65.32], ['-20 C at 5% RH', [-20, 5], -47.79], ['-20 C at 30% RH', [-20, 30], -31.95], ['-20 C at 50% RH', [-20, 50], -27.02], ['-20 C at 80% RH', [-20, 80], -22.3], ['-5 C at 5% RH', [-5, 5], -35.98], ['0 C at 0.5% RH', [0, 0.5], -56.21]], [['-20 C at 104% RH', [-20, 104], None], ['-5 C at 0% RH', [-5, 0], None], ['-5 C at 0.5% RH', [-5, 0.5], -55.32], ['-5 C at 5% RH', [-5, 5], -35.98], ['-5 C at 30% RH', [-5, 30], -18.38], ['-5 C at 50% RH', [-5, 50], -12.87], ['-0.5 C at 5% RH', [-0.5, 5], -32.47], ['0 C at 50% RH', [0, 50], -9.2]], [['-5 C at 5% RH', [-5, 5], -35.98], ['-5 C at 100% RH', [-5, 100], -5.0], ['-5 C at 104% RH', [-5, 104], None], ['-0.5 C at 0% RH', [-0.5, 0], None], ['-0.5 C at 0.5% RH', [-0.5, 0.5], -52.36], ['-0.5 C at 5% RH', [-0.5, 5], -32.47], ['-0.5 C at 30% RH', [-0.5, 30], -14.32], ['0 C at 5% RH', [0, 5], -35.33]], [['-0.5 C at 5% RH', [-0.5, 5], -32.47], ['-0.5 C at 80% RH', [-0.5, 80], -3.17], ['-0.5 C at 100% RH', [-0.5, 100], -0.5], ['-0.5 C at 104% RH', [-0.5, 104], None], ['0 C at 0% RH', [0, 0], None], ['0 C at 0.5% RH', [0, 0.5], -56.21], ['0 C at 5% RH', [0, 5], -35.33], ['0 C at 80% RH', [0, 80], -3.04]], [['-5 C at 5% RH', [-5, 5], -35.98], ['0 C at 30% RH', [0, 30], -15.55], ['0 C at 50% RH', [0, 50], -9.2], ['0 C at 80% RH', [0, 80], -3.04], ['0 C at 100% RH', [0, 100], 0.0], ['0 C at 104% RH', [0, 104], None], ['0.5 C at 0% RH', [0.5, 0], None], ['0.5 C at 0.5% RH', [0.5, 0.5], -55.91]]]
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 |
|---|---|---|---|
| -20 C at 0% RH | None | None | Passed |
| -20 C at 0.5% RH | -65.32 | -65.32 | Passed |
| -20 C at 5% RH | -47.79 | -47.79 | Passed |
| -20 C at 30% RH | -31.95 | -31.95 | Passed |
| -20 C at 50% RH | -27.02 | -27.02 | Passed |
| -20 C at 80% RH | -22.3 | -22.3 | Passed |
| -5 C at 5% RH | -35.98 | -35.98 | Passed |
| 0 C at 0.5% RH | -56.21 | -56.21 | Passed |
SHA-256 / 136ec2a05333642176ab3550d372a9dfae2b6259958f59190f8da9c5344aeffe
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:24.825560+00:00.
Case digest / 0e56d3500420dafe60990e2f787b55e1b21473aa49fe96c1aed631f48df2b3ee