FA-71286 / Weather index computation / Open access
Pasquill-Gifford stability class: night cloud threshold · case 01
Four-octa nights are treated as clear and too stable.
ROOT CAUSE
The thin-overcast night table requires more than four octas.
VERIFIED REPAIR
Use the thin-cloud table for 4 or more octas.
Unsuccessful approach: Lowering the threshold to 3 octas treats clear nights as cloudy.
Case contract
Wind class: <2, <3, <5, <6, >=6 (index 0..4). 8 octas returns "D" day or night. Day: tables by insolation strong [A,A-B,B,C,C], moderate [A-B,B,B-C,C-D,D], slight [B,C,C,D,D]; unknown insolation returns None. Night: >=4 octas [E,E,D,D,D], <=3 octas [F,F,E,D,D].
Why this case matters
Air-dispersion screening models choose plume spread from the stability class.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(wind_ms, is_day, insolation, octas):
day = {"strong": ["A", "A-B", "B", "C", "C"],
"moderate": ["A-B", "B", "B-C", "C-D", "D"],
"slight": ["B", "C", "C", "D", "D"]}
thin = ["E", "E", "D", "D", "D"]
clear = ["F", "F", "E", "D", "D"]
if octas == 8:
return "D"
i = 0 if wind_ms < 2 else 1 if wind_ms < 3 else 2 if wind_ms < 5 else 3 if wind_ms < 6 else 4
if is_day:
if insolation not in day:
return None
return day[insolation][i]
return (thin if octas > 4 else clear)[i]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['wind 1.0 day strong 2 octas', [1.0, True, 'strong', 2], 'A'], ['wind 1.0 day moderate 5 octas', [1.0, True, 'moderate', 5], 'A-B'], ['wind 1.0 day slight 8 octas', [1.0, True, 'slight', 8], 'D'], ['wind 1.0 day slight 3 octas', [1.0, True, 'slight', 3], 'B'], ['wind 1.0 night None 3 octas', [1.0, False, None, 3], 'F'], ['wind 1.0 night None 4 octas', [1.0, False, None, 4], 'E'], ['wind 1.0 night None 8 octas', [1.0, False, None, 8], 'D'], ['wind 1.9 night None 3 octas', [1.9, False, None, 3], 'F']], [['wind 1.0 night None 3 octas', [1.0, False, None, 3], 'F'], ['wind 1.0 day overcast-ish 4 octas', [1.0, True, 'overcast-ish', 4], None], ['wind 1.0 night None 7 octas', [1.0, False, None, 7], 'E'], ['wind 1.0 day strong 7 octas', [1.0, True, 'strong', 7], 'A'], ['wind 1.9 day strong 2 octas', [1.9, True, 'strong', 2], 'A'], ['wind 1.9 day moderate 5 octas', [1.9, True, 'moderate', 5], 'A-B'], ['wind 1.9 day slight 8 octas', [1.9, True, 'slight', 8], 'D'], ['wind 2.9 night None 4 octas', [2.9, False, None, 4], 'E']], [['wind 1.0 night None 4 octas', [1.0, False, None, 4], 'E'], ['wind 1.9 night None 3 octas', [1.9, False, None, 3], 'F'], ['wind 1.9 night None 4 octas', [1.9, False, None, 4], 'E'], ['wind 1.9 night None 8 octas', [1.9, False, None, 8], 'D'], ['wind 1.9 day overcast-ish 4 octas', [1.9, True, 'overcast-ish', 4], None], ['wind 1.9 night None 7 octas', [1.9, False, None, 7], 'E'], ['wind 1.9 day strong 7 octas', [1.9, True, 'strong', 7], 'A'], ['wind 4.9 night None 3 octas', [4.9, False, None, 3], 'E']], [['wind 2.0 day moderate 5 octas', [2.0, True, 'moderate', 5], 'B'], ['wind 2.0 day slight 8 octas', [2.0, True, 'slight', 8], 'D'], ['wind 2.0 day slight 3 octas', [2.0, True, 'slight', 3], 'C'], ['wind 2.0 night None 3 octas', [2.0, False, None, 3], 'F'], ['wind 2.0 night None 4 octas', [2.0, False, None, 4], 'E'], ['wind 2.0 night None 8 octas', [2.0, False, None, 8], 'D'], ['wind 2.9 night None 4 octas', [2.9, False, None, 4], 'E'], ['wind 3.0 night None 3 octas', [3.0, False, None, 3], 'E']], [['wind 1.0 night None 4 octas', [1.0, False, None, 4], 'E'], ['wind 2.0 night None 7 octas', [2.0, False, None, 7], 'E'], ['wind 2.0 day strong 7 octas', [2.0, True, 'strong', 7], 'A-B'], ['wind 2.9 day strong 2 octas', [2.9, True, 'strong', 2], 'A-B'], ['wind 2.9 day moderate 5 octas', [2.9, True, 'moderate', 5], 'B'], ['wind 2.9 day slight 8 octas', [2.9, True, 'slight', 8], 'D'], ['wind 2.9 day slight 3 octas', [2.9, True, 'slight', 3], 'C'], ['wind 2.9 night None 3 octas', [2.9, False, None, 3], 'F']]]
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 |
|---|---|---|---|
| wind 1.0 day strong 2 octas | A | A | Passed |
| wind 1.0 day moderate 5 octas | A-B | A-B | Passed |
| wind 1.0 day slight 8 octas | D | D | Passed |
| wind 1.0 day slight 3 octas | B | B | Passed |
| wind 1.0 night None 3 octas | F | F | Passed |
| wind 1.0 night None 4 octas | F | E | Failed |
| wind 1.0 night None 8 octas | D | D | Passed |
| wind 1.9 night None 3 octas | F | F | Passed |
SHA-256 / d9956f5c344104937805096da9be6b37454c5e2f1af2fe70d5579d6c98463c2d
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(wind_ms, is_day, insolation, octas):
day = {"strong": ["A", "A-B", "B", "C", "C"],
"moderate": ["A-B", "B", "B-C", "C-D", "D"],
"slight": ["B", "C", "C", "D", "D"]}
thin = ["E", "E", "D", "D", "D"]
clear = ["F", "F", "E", "D", "D"]
if octas == 8:
return "D"
i = 0 if wind_ms < 2 else 1 if wind_ms < 3 else 2 if wind_ms < 5 else 3 if wind_ms < 6 else 4
if is_day:
if insolation not in day:
return None
return day[insolation][i]
return (thin if octas >= 3 else clear)[i]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['wind 1.0 day strong 2 octas', [1.0, True, 'strong', 2], 'A'], ['wind 1.0 day moderate 5 octas', [1.0, True, 'moderate', 5], 'A-B'], ['wind 1.0 day slight 8 octas', [1.0, True, 'slight', 8], 'D'], ['wind 1.0 day slight 3 octas', [1.0, True, 'slight', 3], 'B'], ['wind 1.0 night None 3 octas', [1.0, False, None, 3], 'F'], ['wind 1.0 night None 4 octas', [1.0, False, None, 4], 'E'], ['wind 1.0 night None 8 octas', [1.0, False, None, 8], 'D'], ['wind 1.9 night None 3 octas', [1.9, False, None, 3], 'F']], [['wind 1.0 night None 3 octas', [1.0, False, None, 3], 'F'], ['wind 1.0 day overcast-ish 4 octas', [1.0, True, 'overcast-ish', 4], None], ['wind 1.0 night None 7 octas', [1.0, False, None, 7], 'E'], ['wind 1.0 day strong 7 octas', [1.0, True, 'strong', 7], 'A'], ['wind 1.9 day strong 2 octas', [1.9, True, 'strong', 2], 'A'], ['wind 1.9 day moderate 5 octas', [1.9, True, 'moderate', 5], 'A-B'], ['wind 1.9 day slight 8 octas', [1.9, True, 'slight', 8], 'D'], ['wind 2.9 night None 4 octas', [2.9, False, None, 4], 'E']], [['wind 1.0 night None 4 octas', [1.0, False, None, 4], 'E'], ['wind 1.9 night None 3 octas', [1.9, False, None, 3], 'F'], ['wind 1.9 night None 4 octas', [1.9, False, None, 4], 'E'], ['wind 1.9 night None 8 octas', [1.9, False, None, 8], 'D'], ['wind 1.9 day overcast-ish 4 octas', [1.9, True, 'overcast-ish', 4], None], ['wind 1.9 night None 7 octas', [1.9, False, None, 7], 'E'], ['wind 1.9 day strong 7 octas', [1.9, True, 'strong', 7], 'A'], ['wind 4.9 night None 3 octas', [4.9, False, None, 3], 'E']], [['wind 2.0 day moderate 5 octas', [2.0, True, 'moderate', 5], 'B'], ['wind 2.0 day slight 8 octas', [2.0, True, 'slight', 8], 'D'], ['wind 2.0 day slight 3 octas', [2.0, True, 'slight', 3], 'C'], ['wind 2.0 night None 3 octas', [2.0, False, None, 3], 'F'], ['wind 2.0 night None 4 octas', [2.0, False, None, 4], 'E'], ['wind 2.0 night None 8 octas', [2.0, False, None, 8], 'D'], ['wind 2.9 night None 4 octas', [2.9, False, None, 4], 'E'], ['wind 3.0 night None 3 octas', [3.0, False, None, 3], 'E']], [['wind 1.0 night None 4 octas', [1.0, False, None, 4], 'E'], ['wind 2.0 night None 7 octas', [2.0, False, None, 7], 'E'], ['wind 2.0 day strong 7 octas', [2.0, True, 'strong', 7], 'A-B'], ['wind 2.9 day strong 2 octas', [2.9, True, 'strong', 2], 'A-B'], ['wind 2.9 day moderate 5 octas', [2.9, True, 'moderate', 5], 'B'], ['wind 2.9 day slight 8 octas', [2.9, True, 'slight', 8], 'D'], ['wind 2.9 day slight 3 octas', [2.9, True, 'slight', 3], 'C'], ['wind 2.9 night None 3 octas', [2.9, False, None, 3], 'F']]]
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 |
|---|---|---|---|
| wind 1.0 day strong 2 octas | A | A | Passed |
| wind 1.0 day moderate 5 octas | A-B | A-B | Passed |
| wind 1.0 day slight 8 octas | D | D | Passed |
| wind 1.0 day slight 3 octas | B | B | Passed |
| wind 1.0 night None 3 octas | E | F | Failed |
| wind 1.0 night None 4 octas | E | E | Passed |
| wind 1.0 night None 8 octas | D | D | Passed |
| wind 1.9 night None 3 octas | E | F | Failed |
SHA-256 / beaad6c226925c43907ff46ddc49ae9a7b403f790aca226a0791da85029d8c62
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(wind_ms, is_day, insolation, octas):
day = {"strong": ["A", "A-B", "B", "C", "C"],
"moderate": ["A-B", "B", "B-C", "C-D", "D"],
"slight": ["B", "C", "C", "D", "D"]}
thin = ["E", "E", "D", "D", "D"]
clear = ["F", "F", "E", "D", "D"]
if octas == 8:
return "D"
i = 0 if wind_ms < 2 else 1 if wind_ms < 3 else 2 if wind_ms < 5 else 3 if wind_ms < 6 else 4
if is_day:
if insolation not in day:
return None
return day[insolation][i]
return (thin if octas >= 4 else clear)[i]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['wind 1.0 day strong 2 octas', [1.0, True, 'strong', 2], 'A'], ['wind 1.0 day moderate 5 octas', [1.0, True, 'moderate', 5], 'A-B'], ['wind 1.0 day slight 8 octas', [1.0, True, 'slight', 8], 'D'], ['wind 1.0 day slight 3 octas', [1.0, True, 'slight', 3], 'B'], ['wind 1.0 night None 3 octas', [1.0, False, None, 3], 'F'], ['wind 1.0 night None 4 octas', [1.0, False, None, 4], 'E'], ['wind 1.0 night None 8 octas', [1.0, False, None, 8], 'D'], ['wind 1.9 night None 3 octas', [1.9, False, None, 3], 'F']], [['wind 1.0 night None 3 octas', [1.0, False, None, 3], 'F'], ['wind 1.0 day overcast-ish 4 octas', [1.0, True, 'overcast-ish', 4], None], ['wind 1.0 night None 7 octas', [1.0, False, None, 7], 'E'], ['wind 1.0 day strong 7 octas', [1.0, True, 'strong', 7], 'A'], ['wind 1.9 day strong 2 octas', [1.9, True, 'strong', 2], 'A'], ['wind 1.9 day moderate 5 octas', [1.9, True, 'moderate', 5], 'A-B'], ['wind 1.9 day slight 8 octas', [1.9, True, 'slight', 8], 'D'], ['wind 2.9 night None 4 octas', [2.9, False, None, 4], 'E']], [['wind 1.0 night None 4 octas', [1.0, False, None, 4], 'E'], ['wind 1.9 night None 3 octas', [1.9, False, None, 3], 'F'], ['wind 1.9 night None 4 octas', [1.9, False, None, 4], 'E'], ['wind 1.9 night None 8 octas', [1.9, False, None, 8], 'D'], ['wind 1.9 day overcast-ish 4 octas', [1.9, True, 'overcast-ish', 4], None], ['wind 1.9 night None 7 octas', [1.9, False, None, 7], 'E'], ['wind 1.9 day strong 7 octas', [1.9, True, 'strong', 7], 'A'], ['wind 4.9 night None 3 octas', [4.9, False, None, 3], 'E']], [['wind 2.0 day moderate 5 octas', [2.0, True, 'moderate', 5], 'B'], ['wind 2.0 day slight 8 octas', [2.0, True, 'slight', 8], 'D'], ['wind 2.0 day slight 3 octas', [2.0, True, 'slight', 3], 'C'], ['wind 2.0 night None 3 octas', [2.0, False, None, 3], 'F'], ['wind 2.0 night None 4 octas', [2.0, False, None, 4], 'E'], ['wind 2.0 night None 8 octas', [2.0, False, None, 8], 'D'], ['wind 2.9 night None 4 octas', [2.9, False, None, 4], 'E'], ['wind 3.0 night None 3 octas', [3.0, False, None, 3], 'E']], [['wind 1.0 night None 4 octas', [1.0, False, None, 4], 'E'], ['wind 2.0 night None 7 octas', [2.0, False, None, 7], 'E'], ['wind 2.0 day strong 7 octas', [2.0, True, 'strong', 7], 'A-B'], ['wind 2.9 day strong 2 octas', [2.9, True, 'strong', 2], 'A-B'], ['wind 2.9 day moderate 5 octas', [2.9, True, 'moderate', 5], 'B'], ['wind 2.9 day slight 8 octas', [2.9, True, 'slight', 8], 'D'], ['wind 2.9 day slight 3 octas', [2.9, True, 'slight', 3], 'C'], ['wind 2.9 night None 3 octas', [2.9, False, None, 3], 'F']]]
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 |
|---|---|---|---|
| wind 1.0 day strong 2 octas | A | A | Passed |
| wind 1.0 day moderate 5 octas | A-B | A-B | Passed |
| wind 1.0 day slight 8 octas | D | D | Passed |
| wind 1.0 day slight 3 octas | B | B | Passed |
| wind 1.0 night None 3 octas | F | F | Passed |
| wind 1.0 night None 4 octas | E | E | Passed |
| wind 1.0 night None 8 octas | D | D | Passed |
| wind 1.9 night None 3 octas | F | F | Passed |
SHA-256 / 68ae3518a1a0d30b45136ddbc0d4479492bed2efdc0c9f39c638a268dd8f8f10
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:28.339539+00:00.
Case digest / 0b12581507035edad45b967c180d8facaf09ead987268bb3e823db0a783c99a3