FA-71016 / Weather index computation / Open access
Monthly heating and cooling degree days: half-degree rounding · case 01
Days with an odd tmax+tmin are consistently one degree too cool.
ROOT CAUSE
The daily mean is truncated instead of rounded half up.
VERIFIED REPAIR
Use floor(mean + 0.5).
Unsuccessful approach: Python round() rounds halves to even, so 64.5 still becomes 64.
Case contract
daily entries are [tmax_F, tmin_F] with None for missing. A day with a missing value reuses the previous valid daily mean; missing days before any valid day are skipped. Round the daily mean half up to a whole degree, then HDD += 65 - m if m < 65, CDD += m - 65 if m > 65. Return [HDD, CDD].
Why this case matters
Energy billing normalisation and utility demand models use monthly HDD/CDD.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(daily):
hdd = 0
cdd = 0
prev = None
for hi, lo in daily:
if hi is None or lo is None:
if prev is None:
continue
mean = prev
else:
mean = (hi + lo) / 2
prev = mean
m = int(mean)
if m < 65:
hdd += 65 - m
elif m > 65:
cdd += m - 65
return [hdd, cdd]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['month 0', [[[57, 57], [81, 68], [50, 45], [None, 60], [63, 43], [60, 41], [91, 67], [None, None], [92, 75], [None, 60]]], [68, 76]], ['month 1', [[[83, 66], [71, 50], [49, 42], [46, 43], [92, 70], [55, 54], [55, 46], [70, 55], [64, 64], [38, 36]]], [98, 26]], ['month 2', [[[86, 69], [48, 47], [63, 47], [70, 60], [63, 42], [56, 36], [59, 43], [72, 70], [74, 59], [75, 63]]], [72, 25]], ['month 3', [[[None, None], [None, 60], [65, 60], [74, 72], [93, 69], [76, 73], [58, 43], [54, 35], [74, 52], [55, 49]]], [51, 34]], ['month 4', [[[None, 60], [64, 63], [61, 54], [73, 49], [47, 38], [49, 40], [58, 46], [77, 58], [72, 54], [74, 64]]], [69, 7]], ['month 5', [[[83, 71], [69, 53], [79, 74], [80, 71], [47, 46], [83, 64], [74, 51], [52, 52], [None, None], [48, 37]]], [72, 44]], ['month 6', [[[93, 68], [80, 74], [80, 59], [71, 70], [74, 73], [59, 57], [91, 71], [60, 51], [62, 61], [74, 73]]], [19, 73]], ['month 7', [[[78, 54], [83, 68], [57, 36], [81, 75], [47, 41], [86, 63], [81, 59], [41, 37], [67, 50], [65, 60]]], [73, 40]]], [['month 3', [[[None, None], [None, 60], [65, 60], [74, 72], [93, 69], [76, 73], [58, 43], [54, 35], [74, 52], [55, 49]]], [51, 34]], ['month 6', [[[93, 68], [80, 74], [80, 59], [71, 70], [74, 73], [59, 57], [91, 71], [60, 51], [62, 61], [74, 73]]], [19, 73]], ['month 7', [[[78, 54], [83, 68], [57, 36], [81, 75], [47, 41], [86, 63], [81, 59], [41, 37], [67, 50], [65, 60]]], [73, 40]], ['month 8', [[[71, 60], [75, 67], [77, 54], [84, 71], [62, 45], [None, None], [None, None], [90, 75], [None, 60], [65, 51]]], [40, 57]], ['month 9', [[[None, None], [None, None], [67, 66], [64, 51], [None, None], [None, None], [96, 73], [None, None], [75, 50], [72, 67]]], [23, 47]], ['month 10', [[[68, 47], [71, 53], [93, 68], [78, 65], [52, 47], [53, 43], [77, 72], [84, 72], [80, 71], [67, 58]]], [44, 57]], ['month 11', [[[74, 51], [None, 60], [52, 44], [82, 69], [64, 55], [None, None], [55, 53], [81, 73], [77, 63], [45, 37]]], [66, 28]], ['month 12', [[[60, 59], [62, 55], [66, 63], [60, 56], [None, 60], [68, 45], [63, 38], [61, 55], [None, 60], [50, 50]]], [76, 0]]], [['month 6', [[[93, 68], [80, 74], [80, 59], [71, 70], [74, 73], [59, 57], [91, 71], [60, 51], [62, 61], [74, 73]]], [19, 73]], ['month 11', [[[74, 51], [None, 60], [52, 44], [82, 69], [64, 55], [None, None], [55, 53], [81, 73], [77, 63], [45, 37]]], [66, 28]], ['month 14', [[[47, 42], [None, 60], [60, 48], [64, 63], [50, 46], [None, None], [68, 50], [52, 48], [71, 55], [67, 48]]], [116, 0]], ['month 15', [[[71, 61], [None, None], [None, 60], [None, 60], [None, None], [73, 67], [61, 41], [86, 74], [None, 60], [None, 60]]], [14, 55]], ['month 16', [[[None, None], [42, 35], [49, 35], [81, 65], [50, 49], [54, 44], [64, 47], [88, 67], [71, 58], [45, 37]]], [113, 21]], ['month 17', [[[59, 59], [84, 70], [83, 63], [64, 56], [77, 66], [44, 42], [84, 62], [49, 40], [36, 36], [59, 35]]], [100, 35]], ['month 18', [[[52, 38], [66, 61], [67, 54], [87, 75], [60, 47], [58, 35], [61, 40], [79, 57], [50, 35], [54, 39]]], [108, 19]], ['month 19', [[[62, 37], [93, 74], [45, 39], [56, 53], [70, 45], [94, 75], [57, 47], [95, 72], [49, 35], [71, 66]]], [91, 62]]], [['month 9', [[[None, None], [None, None], [67, 66], [64, 51], [None, None], [None, None], [96, 73], [None, None], [75, 50], [72, 67]]], [23, 47]], ['month 17', [[[59, 59], [84, 70], [83, 63], [64, 56], [77, 66], [44, 42], [84, 62], [49, 40], [36, 36], [59, 35]]], [100, 35]], ['month 21', [[[54, 43], [73, 63], [69, 50], [76, 62], [75, 67], [49, 37], [72, 66], [55, 49], [82, 62], [58, 56]]], [64, 24]], ['month 22', [[[65, 61], [None, 60], [75, 71], [92, 75], [76, 69], [81, 75], [81, 70], [85, 65], [58, 55], [68, 59]]], [13, 69]], ['month 23', [[[46, 42], [55, 38], [73, 63], [72, 61], [62, 37], [60, 58], [55, 52], [38, 36], [82, 69], [51, 47]]], [115, 16]], ['month 24', [[[67, 65], [58, 56], [None, None], [61, 57], [84, 60], [78, 71], [56, 42], [70, 64], [None, 60], [67, 66]]], [38, 24]], ['month 25', [[[61, 43], [None, None], [57, 50], [76, 73], [38, 36], [60, 43], [78, 63], [55, 35], [64, 47], [70, 59]]], [107, 16]], ['month 26', [[[None, 60], [None, 60], [62, 41], [85, 67], [60, 58], [65, 42], [58, 54], [60, 37], [74, 60], [84, 63]]], [55, 22]]], [['month 12', [[[60, 59], [62, 55], [66, 63], [60, 56], [None, 60], [68, 45], [63, 38], [61, 55], [None, 60], [50, 50]]], [76, 0]], ['month 22', [[[65, 61], [None, 60], [75, 71], [92, 75], [76, 69], [81, 75], [81, 70], [85, 65], [58, 55], [68, 59]]], [13, 69]], ['month 28', [[[69, 55], [63, 40], [86, 63], [64, 47], [79, 69], [63, 55], [80, 67], [52, 42], [51, 46], [53, 42]]], [82, 28]], ['month 29', [[[70, 54], [68, 60], [54, 39], [None, 60], [None, None], [63, 47], [69, 63], [55, 41], [None, None], [99, 74]]], [102, 23]], ['odd sums', [[[70, 59], [66, 63], [80, 51]]], [0, 1]], ['first day missing', [[[None, None], [70, 50]]], [5, 0]], ['carry forward', [[[90, 71], [None, None], [None, 50]]], [0, 48]], ['base day', [[[65, 65]]], [0, 0]]]]
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 |
|---|---|---|---|
| month 0 | [71, 73] | [68, 76] | Failed |
| month 1 | [104, 25] | [98, 26] | Failed |
| month 2 | [74, 23] | [72, 25] | Failed |
| month 3 | [54, 33] | [51, 34] | Failed |
| month 4 | [73, 6] | [69, 7] | Failed |
| month 5 | [75, 41] | [72, 44] | Failed |
| month 6 | [21, 68] | [19, 73] | Failed |
| month 7 | [76, 38] | [73, 40] | Failed |
SHA-256 / d14627044459c5e39a7fa5fd75363cf89152489c3ad22da145f1f316a5ca3ef8
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(daily):
hdd = 0
cdd = 0
prev = None
for hi, lo in daily:
if hi is None or lo is None:
if prev is None:
continue
mean = prev
else:
mean = (hi + lo) / 2
prev = mean
m = round(mean)
if m < 65:
hdd += 65 - m
elif m > 65:
cdd += m - 65
return [hdd, cdd]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['month 0', [[[57, 57], [81, 68], [50, 45], [None, 60], [63, 43], [60, 41], [91, 67], [None, None], [92, 75], [None, 60]]], [68, 76]], ['month 1', [[[83, 66], [71, 50], [49, 42], [46, 43], [92, 70], [55, 54], [55, 46], [70, 55], [64, 64], [38, 36]]], [98, 26]], ['month 2', [[[86, 69], [48, 47], [63, 47], [70, 60], [63, 42], [56, 36], [59, 43], [72, 70], [74, 59], [75, 63]]], [72, 25]], ['month 3', [[[None, None], [None, 60], [65, 60], [74, 72], [93, 69], [76, 73], [58, 43], [54, 35], [74, 52], [55, 49]]], [51, 34]], ['month 4', [[[None, 60], [64, 63], [61, 54], [73, 49], [47, 38], [49, 40], [58, 46], [77, 58], [72, 54], [74, 64]]], [69, 7]], ['month 5', [[[83, 71], [69, 53], [79, 74], [80, 71], [47, 46], [83, 64], [74, 51], [52, 52], [None, None], [48, 37]]], [72, 44]], ['month 6', [[[93, 68], [80, 74], [80, 59], [71, 70], [74, 73], [59, 57], [91, 71], [60, 51], [62, 61], [74, 73]]], [19, 73]], ['month 7', [[[78, 54], [83, 68], [57, 36], [81, 75], [47, 41], [86, 63], [81, 59], [41, 37], [67, 50], [65, 60]]], [73, 40]]], [['month 3', [[[None, None], [None, 60], [65, 60], [74, 72], [93, 69], [76, 73], [58, 43], [54, 35], [74, 52], [55, 49]]], [51, 34]], ['month 6', [[[93, 68], [80, 74], [80, 59], [71, 70], [74, 73], [59, 57], [91, 71], [60, 51], [62, 61], [74, 73]]], [19, 73]], ['month 7', [[[78, 54], [83, 68], [57, 36], [81, 75], [47, 41], [86, 63], [81, 59], [41, 37], [67, 50], [65, 60]]], [73, 40]], ['month 8', [[[71, 60], [75, 67], [77, 54], [84, 71], [62, 45], [None, None], [None, None], [90, 75], [None, 60], [65, 51]]], [40, 57]], ['month 9', [[[None, None], [None, None], [67, 66], [64, 51], [None, None], [None, None], [96, 73], [None, None], [75, 50], [72, 67]]], [23, 47]], ['month 10', [[[68, 47], [71, 53], [93, 68], [78, 65], [52, 47], [53, 43], [77, 72], [84, 72], [80, 71], [67, 58]]], [44, 57]], ['month 11', [[[74, 51], [None, 60], [52, 44], [82, 69], [64, 55], [None, None], [55, 53], [81, 73], [77, 63], [45, 37]]], [66, 28]], ['month 12', [[[60, 59], [62, 55], [66, 63], [60, 56], [None, 60], [68, 45], [63, 38], [61, 55], [None, 60], [50, 50]]], [76, 0]]], [['month 6', [[[93, 68], [80, 74], [80, 59], [71, 70], [74, 73], [59, 57], [91, 71], [60, 51], [62, 61], [74, 73]]], [19, 73]], ['month 11', [[[74, 51], [None, 60], [52, 44], [82, 69], [64, 55], [None, None], [55, 53], [81, 73], [77, 63], [45, 37]]], [66, 28]], ['month 14', [[[47, 42], [None, 60], [60, 48], [64, 63], [50, 46], [None, None], [68, 50], [52, 48], [71, 55], [67, 48]]], [116, 0]], ['month 15', [[[71, 61], [None, None], [None, 60], [None, 60], [None, None], [73, 67], [61, 41], [86, 74], [None, 60], [None, 60]]], [14, 55]], ['month 16', [[[None, None], [42, 35], [49, 35], [81, 65], [50, 49], [54, 44], [64, 47], [88, 67], [71, 58], [45, 37]]], [113, 21]], ['month 17', [[[59, 59], [84, 70], [83, 63], [64, 56], [77, 66], [44, 42], [84, 62], [49, 40], [36, 36], [59, 35]]], [100, 35]], ['month 18', [[[52, 38], [66, 61], [67, 54], [87, 75], [60, 47], [58, 35], [61, 40], [79, 57], [50, 35], [54, 39]]], [108, 19]], ['month 19', [[[62, 37], [93, 74], [45, 39], [56, 53], [70, 45], [94, 75], [57, 47], [95, 72], [49, 35], [71, 66]]], [91, 62]]], [['month 9', [[[None, None], [None, None], [67, 66], [64, 51], [None, None], [None, None], [96, 73], [None, None], [75, 50], [72, 67]]], [23, 47]], ['month 17', [[[59, 59], [84, 70], [83, 63], [64, 56], [77, 66], [44, 42], [84, 62], [49, 40], [36, 36], [59, 35]]], [100, 35]], ['month 21', [[[54, 43], [73, 63], [69, 50], [76, 62], [75, 67], [49, 37], [72, 66], [55, 49], [82, 62], [58, 56]]], [64, 24]], ['month 22', [[[65, 61], [None, 60], [75, 71], [92, 75], [76, 69], [81, 75], [81, 70], [85, 65], [58, 55], [68, 59]]], [13, 69]], ['month 23', [[[46, 42], [55, 38], [73, 63], [72, 61], [62, 37], [60, 58], [55, 52], [38, 36], [82, 69], [51, 47]]], [115, 16]], ['month 24', [[[67, 65], [58, 56], [None, None], [61, 57], [84, 60], [78, 71], [56, 42], [70, 64], [None, 60], [67, 66]]], [38, 24]], ['month 25', [[[61, 43], [None, None], [57, 50], [76, 73], [38, 36], [60, 43], [78, 63], [55, 35], [64, 47], [70, 59]]], [107, 16]], ['month 26', [[[None, 60], [None, 60], [62, 41], [85, 67], [60, 58], [65, 42], [58, 54], [60, 37], [74, 60], [84, 63]]], [55, 22]]], [['month 12', [[[60, 59], [62, 55], [66, 63], [60, 56], [None, 60], [68, 45], [63, 38], [61, 55], [None, 60], [50, 50]]], [76, 0]], ['month 22', [[[65, 61], [None, 60], [75, 71], [92, 75], [76, 69], [81, 75], [81, 70], [85, 65], [58, 55], [68, 59]]], [13, 69]], ['month 28', [[[69, 55], [63, 40], [86, 63], [64, 47], [79, 69], [63, 55], [80, 67], [52, 42], [51, 46], [53, 42]]], [82, 28]], ['month 29', [[[70, 54], [68, 60], [54, 39], [None, 60], [None, None], [63, 47], [69, 63], [55, 41], [None, None], [99, 74]]], [102, 23]], ['odd sums', [[[70, 59], [66, 63], [80, 51]]], [0, 1]], ['first day missing', [[[None, None], [70, 50]]], [5, 0]], ['carry forward', [[[90, 71], [None, None], [None, 50]]], [0, 48]], ['base day', [[[65, 65]]], [0, 0]]]]
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 |
|---|---|---|---|
| month 0 | [69, 75] | [68, 76] | Failed |
| month 1 | [103, 25] | [98, 26] | Failed |
| month 2 | [73, 24] | [72, 25] | Failed |
| month 3 | [54, 33] | [51, 34] | Failed |
| month 4 | [71, 7] | [69, 7] | Failed |
| month 5 | [75, 43] | [72, 44] | Failed |
| month 6 | [19, 71] | [19, 73] | Failed |
| month 7 | [76, 39] | [73, 40] | Failed |
SHA-256 / 9b40f2f8cfb84a7ba8941ff9ad9ce2b5a96740f1a70c25a7b0695b7871916920
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(daily):
hdd = 0
cdd = 0
prev = None
for hi, lo in daily:
if hi is None or lo is None:
if prev is None:
continue
mean = prev
else:
mean = (hi + lo) / 2
prev = mean
m = math.floor(mean + 0.5)
if m < 65:
hdd += 65 - m
elif m > 65:
cdd += m - 65
return [hdd, cdd]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['month 0', [[[57, 57], [81, 68], [50, 45], [None, 60], [63, 43], [60, 41], [91, 67], [None, None], [92, 75], [None, 60]]], [68, 76]], ['month 1', [[[83, 66], [71, 50], [49, 42], [46, 43], [92, 70], [55, 54], [55, 46], [70, 55], [64, 64], [38, 36]]], [98, 26]], ['month 2', [[[86, 69], [48, 47], [63, 47], [70, 60], [63, 42], [56, 36], [59, 43], [72, 70], [74, 59], [75, 63]]], [72, 25]], ['month 3', [[[None, None], [None, 60], [65, 60], [74, 72], [93, 69], [76, 73], [58, 43], [54, 35], [74, 52], [55, 49]]], [51, 34]], ['month 4', [[[None, 60], [64, 63], [61, 54], [73, 49], [47, 38], [49, 40], [58, 46], [77, 58], [72, 54], [74, 64]]], [69, 7]], ['month 5', [[[83, 71], [69, 53], [79, 74], [80, 71], [47, 46], [83, 64], [74, 51], [52, 52], [None, None], [48, 37]]], [72, 44]], ['month 6', [[[93, 68], [80, 74], [80, 59], [71, 70], [74, 73], [59, 57], [91, 71], [60, 51], [62, 61], [74, 73]]], [19, 73]], ['month 7', [[[78, 54], [83, 68], [57, 36], [81, 75], [47, 41], [86, 63], [81, 59], [41, 37], [67, 50], [65, 60]]], [73, 40]]], [['month 3', [[[None, None], [None, 60], [65, 60], [74, 72], [93, 69], [76, 73], [58, 43], [54, 35], [74, 52], [55, 49]]], [51, 34]], ['month 6', [[[93, 68], [80, 74], [80, 59], [71, 70], [74, 73], [59, 57], [91, 71], [60, 51], [62, 61], [74, 73]]], [19, 73]], ['month 7', [[[78, 54], [83, 68], [57, 36], [81, 75], [47, 41], [86, 63], [81, 59], [41, 37], [67, 50], [65, 60]]], [73, 40]], ['month 8', [[[71, 60], [75, 67], [77, 54], [84, 71], [62, 45], [None, None], [None, None], [90, 75], [None, 60], [65, 51]]], [40, 57]], ['month 9', [[[None, None], [None, None], [67, 66], [64, 51], [None, None], [None, None], [96, 73], [None, None], [75, 50], [72, 67]]], [23, 47]], ['month 10', [[[68, 47], [71, 53], [93, 68], [78, 65], [52, 47], [53, 43], [77, 72], [84, 72], [80, 71], [67, 58]]], [44, 57]], ['month 11', [[[74, 51], [None, 60], [52, 44], [82, 69], [64, 55], [None, None], [55, 53], [81, 73], [77, 63], [45, 37]]], [66, 28]], ['month 12', [[[60, 59], [62, 55], [66, 63], [60, 56], [None, 60], [68, 45], [63, 38], [61, 55], [None, 60], [50, 50]]], [76, 0]]], [['month 6', [[[93, 68], [80, 74], [80, 59], [71, 70], [74, 73], [59, 57], [91, 71], [60, 51], [62, 61], [74, 73]]], [19, 73]], ['month 11', [[[74, 51], [None, 60], [52, 44], [82, 69], [64, 55], [None, None], [55, 53], [81, 73], [77, 63], [45, 37]]], [66, 28]], ['month 14', [[[47, 42], [None, 60], [60, 48], [64, 63], [50, 46], [None, None], [68, 50], [52, 48], [71, 55], [67, 48]]], [116, 0]], ['month 15', [[[71, 61], [None, None], [None, 60], [None, 60], [None, None], [73, 67], [61, 41], [86, 74], [None, 60], [None, 60]]], [14, 55]], ['month 16', [[[None, None], [42, 35], [49, 35], [81, 65], [50, 49], [54, 44], [64, 47], [88, 67], [71, 58], [45, 37]]], [113, 21]], ['month 17', [[[59, 59], [84, 70], [83, 63], [64, 56], [77, 66], [44, 42], [84, 62], [49, 40], [36, 36], [59, 35]]], [100, 35]], ['month 18', [[[52, 38], [66, 61], [67, 54], [87, 75], [60, 47], [58, 35], [61, 40], [79, 57], [50, 35], [54, 39]]], [108, 19]], ['month 19', [[[62, 37], [93, 74], [45, 39], [56, 53], [70, 45], [94, 75], [57, 47], [95, 72], [49, 35], [71, 66]]], [91, 62]]], [['month 9', [[[None, None], [None, None], [67, 66], [64, 51], [None, None], [None, None], [96, 73], [None, None], [75, 50], [72, 67]]], [23, 47]], ['month 17', [[[59, 59], [84, 70], [83, 63], [64, 56], [77, 66], [44, 42], [84, 62], [49, 40], [36, 36], [59, 35]]], [100, 35]], ['month 21', [[[54, 43], [73, 63], [69, 50], [76, 62], [75, 67], [49, 37], [72, 66], [55, 49], [82, 62], [58, 56]]], [64, 24]], ['month 22', [[[65, 61], [None, 60], [75, 71], [92, 75], [76, 69], [81, 75], [81, 70], [85, 65], [58, 55], [68, 59]]], [13, 69]], ['month 23', [[[46, 42], [55, 38], [73, 63], [72, 61], [62, 37], [60, 58], [55, 52], [38, 36], [82, 69], [51, 47]]], [115, 16]], ['month 24', [[[67, 65], [58, 56], [None, None], [61, 57], [84, 60], [78, 71], [56, 42], [70, 64], [None, 60], [67, 66]]], [38, 24]], ['month 25', [[[61, 43], [None, None], [57, 50], [76, 73], [38, 36], [60, 43], [78, 63], [55, 35], [64, 47], [70, 59]]], [107, 16]], ['month 26', [[[None, 60], [None, 60], [62, 41], [85, 67], [60, 58], [65, 42], [58, 54], [60, 37], [74, 60], [84, 63]]], [55, 22]]], [['month 12', [[[60, 59], [62, 55], [66, 63], [60, 56], [None, 60], [68, 45], [63, 38], [61, 55], [None, 60], [50, 50]]], [76, 0]], ['month 22', [[[65, 61], [None, 60], [75, 71], [92, 75], [76, 69], [81, 75], [81, 70], [85, 65], [58, 55], [68, 59]]], [13, 69]], ['month 28', [[[69, 55], [63, 40], [86, 63], [64, 47], [79, 69], [63, 55], [80, 67], [52, 42], [51, 46], [53, 42]]], [82, 28]], ['month 29', [[[70, 54], [68, 60], [54, 39], [None, 60], [None, None], [63, 47], [69, 63], [55, 41], [None, None], [99, 74]]], [102, 23]], ['odd sums', [[[70, 59], [66, 63], [80, 51]]], [0, 1]], ['first day missing', [[[None, None], [70, 50]]], [5, 0]], ['carry forward', [[[90, 71], [None, None], [None, 50]]], [0, 48]], ['base day', [[[65, 65]]], [0, 0]]]]
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 |
|---|---|---|---|
| month 0 | [68, 76] | [68, 76] | Passed |
| month 1 | [98, 26] | [98, 26] | Passed |
| month 2 | [72, 25] | [72, 25] | Passed |
| month 3 | [51, 34] | [51, 34] | Passed |
| month 4 | [69, 7] | [69, 7] | Passed |
| month 5 | [72, 44] | [72, 44] | Passed |
| month 6 | [19, 73] | [19, 73] | Passed |
| month 7 | [73, 40] | [73, 40] | Passed |
SHA-256 / 5eed6907fa84c6710cbcdf6f80dadf3217463e59181ea7025bb975f42842eb9f
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.975597+00:00.
Case digest / 69631cf557f220befc3bbabd01ff5035cb079f23ed7147134679b37a4eff8377