FAILURE MAP
← Case archive

FA-87336 / Physics integrator stability / Open access

Drift index reports the last exceedance · case 01

Diagnostics point at the end of the run instead of where drift began.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The first-only guard is missing so later exceedances overwrite the index.

VERIFIED REPAIR

Record only the first index with r>tol.

Unsuccessful approach: Storing i+1 gives a one-based index.

Case contract

solve(states, k, m, tol, blowup): states [[x,v],...] of a spring integrator; E=0.5 m v^2+0.5 k x^2. Relative drift r=|E-E0|/E0 (absolute when E0=0). Scan in order: first state with E>blowup*E0 (E0>0) returns ["blowup", index, its r]. Otherwise ["drift", first index with r>tol, max r] or ["ok", -1, max r].

Why this case matters

Game and robotics physics loops depend on integrator update order, step control and stabilization terms; a wrong decision point turns a stable simulation into drifting or exploding motion.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(states, k, m, tol, blowup):
    def en(s):
        return 0.5 * m * s[1] * s[1] + 0.5 * k * s[0] * s[0]
    e0 = en(states[0])
    scale = e0 if e0 > 0 else 1.0
    worst = 0.0
    first_drift = -1
    for i, s in enumerate(states):
        e = en(s)
        if e0 > 0 and e > blowup * e0:
            return ['blowup', i, round(abs(e - e0) / scale, 6)]
        r = abs(e - e0) / scale
        if r > worst:
            worst = r
        if r > tol:
            first_drift = i
    if first_drift >= 0:
        return ['drift', first_drift, round(worst, 6)]
    return ['ok', -1, round(worst, 6)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[[[0.0, 0.0], [0.0042, 0.0], [0.0082, 0.0], [0.0173, 0.0], [0.019, 0.0], [0.0272, 0.0], [0.0311, 0.0], [0.0323, 0.0]], 4.654, 2.831, 0.01, 1.5], ['ok', -1, 0.002428]], [[[[-0.783, -0.238], [-0.7094, -0.2142], [-0.6366, -0.1928], [-0.5724, -0.1735], [-0.5118, -0.1562], [-0.4515, -0.1405], [-0.4005, -0.1265], [-0.3653, -0.1138]], 0.542, 0.74, 0.01, 1.5], ['drift', 1, 0.781113]], [[[[0.958, 0.922], [0.9734, 0.9404], [0.9877, 0.9592], [1.0117, 0.9784]], 0.802, 1.416, 0.05, 3.0], ['drift', 2, 0.121974]], [[[[0.0, 0.0], [0.0003, 0.0], [0.0028, 0.0]], 2.609, 1.21, 0.05, 2.0], ['ok', -1, 1e-05]], [[[[0.77, -0.528], [0.7846, -0.5386], [0.8008, -0.5493], [0.8252, -0.5603]], 4.089, 2.468, 0.01, 1.5], ['drift', 1, 0.143558]], [[[[0.097, -0.265], [0.1105, -0.2915], [0.1255, -0.3207], [0.1439, -0.3527], [0.1604, -0.388], [0.1785, -0.4268], [0.1974, -0.4695], [0.221, -0.5164], [0.2464, -0.5681]], 4.953, 0.935, 0.01, 3.0], ['blowup', 6, 2.555081]], [[[[-0.684, 0.301], [-0.729, 0.3311], [-0.7958, 0.3642]], 4.897, 1.072, 0.01, 3.0], ['drift', 1, 0.358106]], [[[[0.354, -0.856], [0.3699, -0.8731], [0.3842, -0.8906], [0.404, -0.9084], [0.4055, -0.9266], [0.422, -0.9451], [0.4415, -0.964], [0.4623, -0.9833], [0.4764, -1.0029]], 2.622, 2.687, 0.05, 1.5], ['drift', 2, 0.435375]]], [[[[[-0.962, 0.13], [-0.8403, 0.117], [-0.7446, 0.1053], [-0.657, 0.0948]], 3.257, 1.012, 0.01, 3.0], ['drift', 1, 0.533208]], [[[[-0.274, -0.857], [-0.2679, -0.857], [-0.26, -0.857], [-0.2528, -0.857], [-0.2452, -0.857], [-0.2428, -0.857], [-0.2392, -0.857], [-0.2348, -0.857], [-0.2249, -0.857]], 3.816, 2.244, 0.1, 1.5], ['ok', -1, 0.048319]], [[[[-0.245, -0.092], [-0.247, -0.0938], [-0.2501, -0.0957], [-0.2553, -0.0976], [-0.253, -0.0996], [-0.2532, -0.1016]], 3.639, 1.24, 0.01, 1.5], ['drift', 1, 0.087664]], [[[[0.0, 0.0], [0.004, 0.0], [0.0042, 0.0], [0.0053, 0.0], [0.0122, 0.0], [0.0206, 0.0]], 3.303, 2.508, 0.01, 1.5], ['ok', -1, 0.000701]], [[[[0.967, 0.351], [0.9507, 0.3405], [0.9209, 0.3303], [0.8842, 0.3203], [0.875, 0.3107], [0.854, 0.3014], [0.8287, 0.2924], [0.8091, 0.2836]], 1.768, 2.014, 0.05, 2.0], ['drift', 2, 0.306081]], [[[[-0.451, -0.146], [-0.4364, -0.146], [-0.4224, -0.146], [-0.4062, -0.146], [-0.4008, -0.146], [-0.3962, -0.146], [-0.3907, -0.146], [-0.383, -0.146], [-0.3799, -0.146], [-0.3785, -0.146]], 1.451, 2.901, 0.05, 2.0], ['drift', 1, 0.244448]], [[[[-0.102, -0.417], [-0.0906, -0.3753], [-0.0804, -0.3378], [-0.0639, -0.304], [-0.0565, -0.2736], [-0.0427, -0.2462], [-0.0368, -0.2216], [-0.0314, -0.1994]], 1.311, 2.245, 0.05, 2.0], ['drift', 1, 0.775866]], [[[[-0.219, 0.241], [-0.2354, 0.2651], [-0.2595, 0.2916], [-0.2794, 0.3208], [-0.2964, 0.3528], [-0.3284, 0.3881], [-0.3564, 0.4269]], 0.937, 2.683, 0.1, 3.0], ['blowup', 6, 2.028221]]], [[[[[0.585, -0.43], [0.6088, -0.4386], [0.6199, -0.4474], [0.6363, -0.4563], [0.6676, -0.4654], [0.6834, -0.4748]], 3.589, 1.482, 0.01, 2.0], ['drift', 1, 0.338168]], [[[[-0.091, 0.126], [-0.0974, 0.1386], [-0.1056, 0.1525], [-0.109, 0.1677], [-0.1141, 0.1845]], 3.918, 1.984, 0.01, 1.5], ['blowup', 3, 0.600589]], [[[[0.0, 0.0], [0.0054, 0.0], [0.0108, 0.0]], 1.629, 2.221, 0.1, 2.0], ['ok', -1, 9.5e-05]], [[[[0.738, 0.96], [0.7294, 0.9312], [0.7176, 0.9033], [0.702, 0.8762]], 2.392, 2.866, 0.1, 3.0], ['drift', 3, 0.143253]], [[[[-0.068, -0.749], [-0.0597, -0.764], [-0.0581, -0.7793]], 1.572, 1.363, 0.01, 2.0], ['drift', 1, 0.079225]], [[[[0.617, 0.338], [0.6299, 0.3448], [0.6581, 0.3517], [0.6845, 0.3587], [0.7163, 0.3659], [0.7184, 0.3732], [0.7277, 0.3806]], 1.435, 0.524, 0.05, 1.5], ['drift', 2, 0.378869]], [[[[0.445, 0.184], [0.4622, 0.1877], [0.4725, 0.1914], [0.497, 0.1953], [0.5161, 0.1992], [0.5306, 0.2032]], 2.965, 2.763, 0.05, 1.5], ['drift', 1, 0.393942]], [[[[0.149, -0.408], [0.1394, -0.3672], [0.129, -0.3305], [0.1203, -0.2974], [0.1112, -0.2677], [0.1059, -0.2409], [0.0969, -0.2168], [0.0891, -0.1951]], 0.503, 1.773, 0.1, 3.0], ['drift', 1, 0.766638]]], [[[[[-0.057, -0.938], [-0.0508, -0.9099], [-0.0476, -0.8826], [-0.0384, -0.8561], [-0.0319, -0.8304], [-0.0282, -0.8055], [-0.0214, -0.7813], [-0.0139, -0.7579]], 1.511, 1.175, 0.05, 2.0], ['drift', 1, 0.349947]], [[[[0.062, -0.688], [0.0704, -0.7018], [0.0821, -0.7158], [0.0911, -0.7301], [0.1016, -0.7447], [0.1044, -0.7596], [0.1147, -0.7748], [0.1253, -0.7903]], 2.31, 1.395, 0.05, 1.5], ['drift', 2, 0.35618]], [[[[-0.944, -0.357], [-0.9235, -0.3463], [-0.9004, -0.3359], [-0.8797, -0.3258], [-0.8621, -0.316], [-0.8187, -0.3066], [-0.7942, -0.2974]], 0.792, 1.826, 0.1, 3.0], ['drift', 3, 0.295621]], [[[[0.667, -0.316], [0.6492, -0.3065], [0.6243, -0.2973], [0.6058, -0.2884]], 2.457, 2.222, 0.05, 2.0], ['drift', 1, 0.173734]], [[[[0.391, -0.178], [0.4405, -0.1958], [0.4898, -0.2154], [0.5391, -0.2369], [0.6071, -0.2606], [0.6867, -0.2867], [0.7629, -0.3153], [0.8349, -0.3469]], 4.647, 2.014, 0.01, 3.0], ['blowup', 5, 2.044069]], [[[[0.423, -0.046], [0.4239, -0.046], [0.4257, -0.046], [0.4288, -0.046], [0.4231, -0.046], [0.4219, -0.046], [0.4287, -0.046], [0.4355, -0.046]], 3.517, 0.566, 0.05, 3.0], ['drift', 7, 0.059861]], [[[[-0.069, -0.252], [-0.0624, -0.2444], [-0.0511, -0.2371], [-0.0459, -0.23], [-0.0389, -0.2231], [-0.0374, -0.2164], [-0.0336, -0.2099], [-0.0314, -0.2036], [-0.028, -0.1975]], 1.826, 1.794, 0.1, 2.0], ['drift', 2, 0.41764]], [[[[-0.431, -0.68], [-0.4341, -0.68], [-0.4283, -0.68]], 4.27, 1.291, 0.05, 3.0], ['ok', -1, 0.008237]]], [[[[[-0.339, 0.793], [-0.3323, 0.793], [-0.3359, 0.793], [-0.3369, 0.793], [-0.336, 0.793], [-0.3248, 0.793]], 0.613, 1.879, 0.1, 2.0], ['ok', -1, 0.004615]], [[[[-0.158, 0.273], [-0.1584, 0.2785], [-0.155, 0.284], [-0.1529, 0.2897], [-0.1492, 0.2955], [-0.1509, 0.3014], [-0.1437, 0.3074]], 3.45, 0.863, 0.1, 3.0], ['ok', -1, 0.043282]], [[[[0.599, -0.265], [0.6726, -0.2915], [0.7436, -0.3207], [0.8129, -0.3527], [0.9144, -0.388], [1.0101, -0.4268], [1.1116, -0.4695], [1.2193, -0.5164]], 2.659, 2.064, 0.01, 3.0], ['blowup', 6, 2.403627]], [[[[-0.121, -0.819], [-0.1224, -0.8354], [-0.1203, -0.8521], [-0.1142, -0.8691], [-0.1142, -0.8865]], 4.298, 2.862, 0.01, 1.5], ['drift', 1, 0.162713]], [[[[-0.767, 0.422], [-0.8362, 0.4642], [-0.9046, 0.5106], [-0.9919, 0.5617], [-1.0702, 0.6179]], 2.965, 2.069, 0.05, 3.0], ['drift', 1, 0.981246]], [[[[0.037, 0.336], [0.0442, 0.3696], [0.0557, 0.4066], [0.0633, 0.4472], [0.0788, 0.4919]], 2.156, 1.537, 0.01, 3.0], ['drift', 1, 1.183276]], [[[[0.091, 0.464], [0.0983, 0.4733], [0.1024, 0.4827], [0.1069, 0.4924], [0.1193, 0.5022]], 3.473, 1.231, 0.05, 1.5], ['drift', 1, 0.225006]], [[[[0.788, 0.541], [0.8584, 0.5951], [0.9528, 0.6546], [1.0365, 0.7201], [1.1562, 0.7921], [1.2724, 0.8713]], 4.609, 2.968, 0.1, 3.0], ['drift', 1, 1.604181]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("case %d" % i, 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 fixtureActualExpectedOutcome
case 0['ok', -1, 0.002428]['ok', -1, 0.002428]Passed
case 1['drift', 7, 0.781113]['drift', 1, 0.781113]Failed
case 2['drift', 3, 0.121974]['drift', 2, 0.121974]Failed
case 3['ok', -1, 1e-05]['ok', -1, 1e-05]Passed
case 4['drift', 3, 0.143558]['drift', 1, 0.143558]Failed
case 5['blowup', 6, 2.555081]['blowup', 6, 2.555081]Passed
case 6['drift', 2, 0.358106]['drift', 1, 0.358106]Failed
case 7['drift', 8, 0.435375]['drift', 2, 0.435375]Failed

SHA-256 / ed243612b194a7b492416b7f517eb20864b459c49e7cf76a256793d7f6048981

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(states, k, m, tol, blowup):
    def en(s):
        return 0.5 * m * s[1] * s[1] + 0.5 * k * s[0] * s[0]
    e0 = en(states[0])
    scale = e0 if e0 > 0 else 1.0
    worst = 0.0
    first_drift = -1
    for i, s in enumerate(states):
        e = en(s)
        if e0 > 0 and e > blowup * e0:
            return ['blowup', i, round(abs(e - e0) / scale, 6)]
        r = abs(e - e0) / scale
        if r > worst:
            worst = r
        if r > tol and first_drift < 0:
            first_drift = i + 1
    if first_drift >= 0:
        return ['drift', first_drift, round(worst, 6)]
    return ['ok', -1, round(worst, 6)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[[[0.0, 0.0], [0.0042, 0.0], [0.0082, 0.0], [0.0173, 0.0], [0.019, 0.0], [0.0272, 0.0], [0.0311, 0.0], [0.0323, 0.0]], 4.654, 2.831, 0.01, 1.5], ['ok', -1, 0.002428]], [[[[-0.783, -0.238], [-0.7094, -0.2142], [-0.6366, -0.1928], [-0.5724, -0.1735], [-0.5118, -0.1562], [-0.4515, -0.1405], [-0.4005, -0.1265], [-0.3653, -0.1138]], 0.542, 0.74, 0.01, 1.5], ['drift', 1, 0.781113]], [[[[0.958, 0.922], [0.9734, 0.9404], [0.9877, 0.9592], [1.0117, 0.9784]], 0.802, 1.416, 0.05, 3.0], ['drift', 2, 0.121974]], [[[[0.0, 0.0], [0.0003, 0.0], [0.0028, 0.0]], 2.609, 1.21, 0.05, 2.0], ['ok', -1, 1e-05]], [[[[0.77, -0.528], [0.7846, -0.5386], [0.8008, -0.5493], [0.8252, -0.5603]], 4.089, 2.468, 0.01, 1.5], ['drift', 1, 0.143558]], [[[[0.097, -0.265], [0.1105, -0.2915], [0.1255, -0.3207], [0.1439, -0.3527], [0.1604, -0.388], [0.1785, -0.4268], [0.1974, -0.4695], [0.221, -0.5164], [0.2464, -0.5681]], 4.953, 0.935, 0.01, 3.0], ['blowup', 6, 2.555081]], [[[[-0.684, 0.301], [-0.729, 0.3311], [-0.7958, 0.3642]], 4.897, 1.072, 0.01, 3.0], ['drift', 1, 0.358106]], [[[[0.354, -0.856], [0.3699, -0.8731], [0.3842, -0.8906], [0.404, -0.9084], [0.4055, -0.9266], [0.422, -0.9451], [0.4415, -0.964], [0.4623, -0.9833], [0.4764, -1.0029]], 2.622, 2.687, 0.05, 1.5], ['drift', 2, 0.435375]]], [[[[[-0.962, 0.13], [-0.8403, 0.117], [-0.7446, 0.1053], [-0.657, 0.0948]], 3.257, 1.012, 0.01, 3.0], ['drift', 1, 0.533208]], [[[[-0.274, -0.857], [-0.2679, -0.857], [-0.26, -0.857], [-0.2528, -0.857], [-0.2452, -0.857], [-0.2428, -0.857], [-0.2392, -0.857], [-0.2348, -0.857], [-0.2249, -0.857]], 3.816, 2.244, 0.1, 1.5], ['ok', -1, 0.048319]], [[[[-0.245, -0.092], [-0.247, -0.0938], [-0.2501, -0.0957], [-0.2553, -0.0976], [-0.253, -0.0996], [-0.2532, -0.1016]], 3.639, 1.24, 0.01, 1.5], ['drift', 1, 0.087664]], [[[[0.0, 0.0], [0.004, 0.0], [0.0042, 0.0], [0.0053, 0.0], [0.0122, 0.0], [0.0206, 0.0]], 3.303, 2.508, 0.01, 1.5], ['ok', -1, 0.000701]], [[[[0.967, 0.351], [0.9507, 0.3405], [0.9209, 0.3303], [0.8842, 0.3203], [0.875, 0.3107], [0.854, 0.3014], [0.8287, 0.2924], [0.8091, 0.2836]], 1.768, 2.014, 0.05, 2.0], ['drift', 2, 0.306081]], [[[[-0.451, -0.146], [-0.4364, -0.146], [-0.4224, -0.146], [-0.4062, -0.146], [-0.4008, -0.146], [-0.3962, -0.146], [-0.3907, -0.146], [-0.383, -0.146], [-0.3799, -0.146], [-0.3785, -0.146]], 1.451, 2.901, 0.05, 2.0], ['drift', 1, 0.244448]], [[[[-0.102, -0.417], [-0.0906, -0.3753], [-0.0804, -0.3378], [-0.0639, -0.304], [-0.0565, -0.2736], [-0.0427, -0.2462], [-0.0368, -0.2216], [-0.0314, -0.1994]], 1.311, 2.245, 0.05, 2.0], ['drift', 1, 0.775866]], [[[[-0.219, 0.241], [-0.2354, 0.2651], [-0.2595, 0.2916], [-0.2794, 0.3208], [-0.2964, 0.3528], [-0.3284, 0.3881], [-0.3564, 0.4269]], 0.937, 2.683, 0.1, 3.0], ['blowup', 6, 2.028221]]], [[[[[0.585, -0.43], [0.6088, -0.4386], [0.6199, -0.4474], [0.6363, -0.4563], [0.6676, -0.4654], [0.6834, -0.4748]], 3.589, 1.482, 0.01, 2.0], ['drift', 1, 0.338168]], [[[[-0.091, 0.126], [-0.0974, 0.1386], [-0.1056, 0.1525], [-0.109, 0.1677], [-0.1141, 0.1845]], 3.918, 1.984, 0.01, 1.5], ['blowup', 3, 0.600589]], [[[[0.0, 0.0], [0.0054, 0.0], [0.0108, 0.0]], 1.629, 2.221, 0.1, 2.0], ['ok', -1, 9.5e-05]], [[[[0.738, 0.96], [0.7294, 0.9312], [0.7176, 0.9033], [0.702, 0.8762]], 2.392, 2.866, 0.1, 3.0], ['drift', 3, 0.143253]], [[[[-0.068, -0.749], [-0.0597, -0.764], [-0.0581, -0.7793]], 1.572, 1.363, 0.01, 2.0], ['drift', 1, 0.079225]], [[[[0.617, 0.338], [0.6299, 0.3448], [0.6581, 0.3517], [0.6845, 0.3587], [0.7163, 0.3659], [0.7184, 0.3732], [0.7277, 0.3806]], 1.435, 0.524, 0.05, 1.5], ['drift', 2, 0.378869]], [[[[0.445, 0.184], [0.4622, 0.1877], [0.4725, 0.1914], [0.497, 0.1953], [0.5161, 0.1992], [0.5306, 0.2032]], 2.965, 2.763, 0.05, 1.5], ['drift', 1, 0.393942]], [[[[0.149, -0.408], [0.1394, -0.3672], [0.129, -0.3305], [0.1203, -0.2974], [0.1112, -0.2677], [0.1059, -0.2409], [0.0969, -0.2168], [0.0891, -0.1951]], 0.503, 1.773, 0.1, 3.0], ['drift', 1, 0.766638]]], [[[[[-0.057, -0.938], [-0.0508, -0.9099], [-0.0476, -0.8826], [-0.0384, -0.8561], [-0.0319, -0.8304], [-0.0282, -0.8055], [-0.0214, -0.7813], [-0.0139, -0.7579]], 1.511, 1.175, 0.05, 2.0], ['drift', 1, 0.349947]], [[[[0.062, -0.688], [0.0704, -0.7018], [0.0821, -0.7158], [0.0911, -0.7301], [0.1016, -0.7447], [0.1044, -0.7596], [0.1147, -0.7748], [0.1253, -0.7903]], 2.31, 1.395, 0.05, 1.5], ['drift', 2, 0.35618]], [[[[-0.944, -0.357], [-0.9235, -0.3463], [-0.9004, -0.3359], [-0.8797, -0.3258], [-0.8621, -0.316], [-0.8187, -0.3066], [-0.7942, -0.2974]], 0.792, 1.826, 0.1, 3.0], ['drift', 3, 0.295621]], [[[[0.667, -0.316], [0.6492, -0.3065], [0.6243, -0.2973], [0.6058, -0.2884]], 2.457, 2.222, 0.05, 2.0], ['drift', 1, 0.173734]], [[[[0.391, -0.178], [0.4405, -0.1958], [0.4898, -0.2154], [0.5391, -0.2369], [0.6071, -0.2606], [0.6867, -0.2867], [0.7629, -0.3153], [0.8349, -0.3469]], 4.647, 2.014, 0.01, 3.0], ['blowup', 5, 2.044069]], [[[[0.423, -0.046], [0.4239, -0.046], [0.4257, -0.046], [0.4288, -0.046], [0.4231, -0.046], [0.4219, -0.046], [0.4287, -0.046], [0.4355, -0.046]], 3.517, 0.566, 0.05, 3.0], ['drift', 7, 0.059861]], [[[[-0.069, -0.252], [-0.0624, -0.2444], [-0.0511, -0.2371], [-0.0459, -0.23], [-0.0389, -0.2231], [-0.0374, -0.2164], [-0.0336, -0.2099], [-0.0314, -0.2036], [-0.028, -0.1975]], 1.826, 1.794, 0.1, 2.0], ['drift', 2, 0.41764]], [[[[-0.431, -0.68], [-0.4341, -0.68], [-0.4283, -0.68]], 4.27, 1.291, 0.05, 3.0], ['ok', -1, 0.008237]]], [[[[[-0.339, 0.793], [-0.3323, 0.793], [-0.3359, 0.793], [-0.3369, 0.793], [-0.336, 0.793], [-0.3248, 0.793]], 0.613, 1.879, 0.1, 2.0], ['ok', -1, 0.004615]], [[[[-0.158, 0.273], [-0.1584, 0.2785], [-0.155, 0.284], [-0.1529, 0.2897], [-0.1492, 0.2955], [-0.1509, 0.3014], [-0.1437, 0.3074]], 3.45, 0.863, 0.1, 3.0], ['ok', -1, 0.043282]], [[[[0.599, -0.265], [0.6726, -0.2915], [0.7436, -0.3207], [0.8129, -0.3527], [0.9144, -0.388], [1.0101, -0.4268], [1.1116, -0.4695], [1.2193, -0.5164]], 2.659, 2.064, 0.01, 3.0], ['blowup', 6, 2.403627]], [[[[-0.121, -0.819], [-0.1224, -0.8354], [-0.1203, -0.8521], [-0.1142, -0.8691], [-0.1142, -0.8865]], 4.298, 2.862, 0.01, 1.5], ['drift', 1, 0.162713]], [[[[-0.767, 0.422], [-0.8362, 0.4642], [-0.9046, 0.5106], [-0.9919, 0.5617], [-1.0702, 0.6179]], 2.965, 2.069, 0.05, 3.0], ['drift', 1, 0.981246]], [[[[0.037, 0.336], [0.0442, 0.3696], [0.0557, 0.4066], [0.0633, 0.4472], [0.0788, 0.4919]], 2.156, 1.537, 0.01, 3.0], ['drift', 1, 1.183276]], [[[[0.091, 0.464], [0.0983, 0.4733], [0.1024, 0.4827], [0.1069, 0.4924], [0.1193, 0.5022]], 3.473, 1.231, 0.05, 1.5], ['drift', 1, 0.225006]], [[[[0.788, 0.541], [0.8584, 0.5951], [0.9528, 0.6546], [1.0365, 0.7201], [1.1562, 0.7921], [1.2724, 0.8713]], 4.609, 2.968, 0.1, 3.0], ['drift', 1, 1.604181]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("case %d" % i, 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 fixtureActualExpectedOutcome
case 0['ok', -1, 0.002428]['ok', -1, 0.002428]Passed
case 1['drift', 2, 0.781113]['drift', 1, 0.781113]Failed
case 2['drift', 3, 0.121974]['drift', 2, 0.121974]Failed
case 3['ok', -1, 1e-05]['ok', -1, 1e-05]Passed
case 4['drift', 2, 0.143558]['drift', 1, 0.143558]Failed
case 5['blowup', 6, 2.555081]['blowup', 6, 2.555081]Passed
case 6['drift', 2, 0.358106]['drift', 1, 0.358106]Failed
case 7['drift', 3, 0.435375]['drift', 2, 0.435375]Failed

SHA-256 / 487f46fb31ea55c427ebe8a85829fa90f7f1e73fee1c52c27d942760b04d1702

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(states, k, m, tol, blowup):
    def en(s):
        return 0.5 * m * s[1] * s[1] + 0.5 * k * s[0] * s[0]
    e0 = en(states[0])
    scale = e0 if e0 > 0 else 1.0
    worst = 0.0
    first_drift = -1
    for i, s in enumerate(states):
        e = en(s)
        if e0 > 0 and e > blowup * e0:
            return ['blowup', i, round(abs(e - e0) / scale, 6)]
        r = abs(e - e0) / scale
        if r > worst:
            worst = r
        if r > tol and first_drift < 0:
            first_drift = i
    if first_drift >= 0:
        return ['drift', first_drift, round(worst, 6)]
    return ['ok', -1, round(worst, 6)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[[[0.0, 0.0], [0.0042, 0.0], [0.0082, 0.0], [0.0173, 0.0], [0.019, 0.0], [0.0272, 0.0], [0.0311, 0.0], [0.0323, 0.0]], 4.654, 2.831, 0.01, 1.5], ['ok', -1, 0.002428]], [[[[-0.783, -0.238], [-0.7094, -0.2142], [-0.6366, -0.1928], [-0.5724, -0.1735], [-0.5118, -0.1562], [-0.4515, -0.1405], [-0.4005, -0.1265], [-0.3653, -0.1138]], 0.542, 0.74, 0.01, 1.5], ['drift', 1, 0.781113]], [[[[0.958, 0.922], [0.9734, 0.9404], [0.9877, 0.9592], [1.0117, 0.9784]], 0.802, 1.416, 0.05, 3.0], ['drift', 2, 0.121974]], [[[[0.0, 0.0], [0.0003, 0.0], [0.0028, 0.0]], 2.609, 1.21, 0.05, 2.0], ['ok', -1, 1e-05]], [[[[0.77, -0.528], [0.7846, -0.5386], [0.8008, -0.5493], [0.8252, -0.5603]], 4.089, 2.468, 0.01, 1.5], ['drift', 1, 0.143558]], [[[[0.097, -0.265], [0.1105, -0.2915], [0.1255, -0.3207], [0.1439, -0.3527], [0.1604, -0.388], [0.1785, -0.4268], [0.1974, -0.4695], [0.221, -0.5164], [0.2464, -0.5681]], 4.953, 0.935, 0.01, 3.0], ['blowup', 6, 2.555081]], [[[[-0.684, 0.301], [-0.729, 0.3311], [-0.7958, 0.3642]], 4.897, 1.072, 0.01, 3.0], ['drift', 1, 0.358106]], [[[[0.354, -0.856], [0.3699, -0.8731], [0.3842, -0.8906], [0.404, -0.9084], [0.4055, -0.9266], [0.422, -0.9451], [0.4415, -0.964], [0.4623, -0.9833], [0.4764, -1.0029]], 2.622, 2.687, 0.05, 1.5], ['drift', 2, 0.435375]]], [[[[[-0.962, 0.13], [-0.8403, 0.117], [-0.7446, 0.1053], [-0.657, 0.0948]], 3.257, 1.012, 0.01, 3.0], ['drift', 1, 0.533208]], [[[[-0.274, -0.857], [-0.2679, -0.857], [-0.26, -0.857], [-0.2528, -0.857], [-0.2452, -0.857], [-0.2428, -0.857], [-0.2392, -0.857], [-0.2348, -0.857], [-0.2249, -0.857]], 3.816, 2.244, 0.1, 1.5], ['ok', -1, 0.048319]], [[[[-0.245, -0.092], [-0.247, -0.0938], [-0.2501, -0.0957], [-0.2553, -0.0976], [-0.253, -0.0996], [-0.2532, -0.1016]], 3.639, 1.24, 0.01, 1.5], ['drift', 1, 0.087664]], [[[[0.0, 0.0], [0.004, 0.0], [0.0042, 0.0], [0.0053, 0.0], [0.0122, 0.0], [0.0206, 0.0]], 3.303, 2.508, 0.01, 1.5], ['ok', -1, 0.000701]], [[[[0.967, 0.351], [0.9507, 0.3405], [0.9209, 0.3303], [0.8842, 0.3203], [0.875, 0.3107], [0.854, 0.3014], [0.8287, 0.2924], [0.8091, 0.2836]], 1.768, 2.014, 0.05, 2.0], ['drift', 2, 0.306081]], [[[[-0.451, -0.146], [-0.4364, -0.146], [-0.4224, -0.146], [-0.4062, -0.146], [-0.4008, -0.146], [-0.3962, -0.146], [-0.3907, -0.146], [-0.383, -0.146], [-0.3799, -0.146], [-0.3785, -0.146]], 1.451, 2.901, 0.05, 2.0], ['drift', 1, 0.244448]], [[[[-0.102, -0.417], [-0.0906, -0.3753], [-0.0804, -0.3378], [-0.0639, -0.304], [-0.0565, -0.2736], [-0.0427, -0.2462], [-0.0368, -0.2216], [-0.0314, -0.1994]], 1.311, 2.245, 0.05, 2.0], ['drift', 1, 0.775866]], [[[[-0.219, 0.241], [-0.2354, 0.2651], [-0.2595, 0.2916], [-0.2794, 0.3208], [-0.2964, 0.3528], [-0.3284, 0.3881], [-0.3564, 0.4269]], 0.937, 2.683, 0.1, 3.0], ['blowup', 6, 2.028221]]], [[[[[0.585, -0.43], [0.6088, -0.4386], [0.6199, -0.4474], [0.6363, -0.4563], [0.6676, -0.4654], [0.6834, -0.4748]], 3.589, 1.482, 0.01, 2.0], ['drift', 1, 0.338168]], [[[[-0.091, 0.126], [-0.0974, 0.1386], [-0.1056, 0.1525], [-0.109, 0.1677], [-0.1141, 0.1845]], 3.918, 1.984, 0.01, 1.5], ['blowup', 3, 0.600589]], [[[[0.0, 0.0], [0.0054, 0.0], [0.0108, 0.0]], 1.629, 2.221, 0.1, 2.0], ['ok', -1, 9.5e-05]], [[[[0.738, 0.96], [0.7294, 0.9312], [0.7176, 0.9033], [0.702, 0.8762]], 2.392, 2.866, 0.1, 3.0], ['drift', 3, 0.143253]], [[[[-0.068, -0.749], [-0.0597, -0.764], [-0.0581, -0.7793]], 1.572, 1.363, 0.01, 2.0], ['drift', 1, 0.079225]], [[[[0.617, 0.338], [0.6299, 0.3448], [0.6581, 0.3517], [0.6845, 0.3587], [0.7163, 0.3659], [0.7184, 0.3732], [0.7277, 0.3806]], 1.435, 0.524, 0.05, 1.5], ['drift', 2, 0.378869]], [[[[0.445, 0.184], [0.4622, 0.1877], [0.4725, 0.1914], [0.497, 0.1953], [0.5161, 0.1992], [0.5306, 0.2032]], 2.965, 2.763, 0.05, 1.5], ['drift', 1, 0.393942]], [[[[0.149, -0.408], [0.1394, -0.3672], [0.129, -0.3305], [0.1203, -0.2974], [0.1112, -0.2677], [0.1059, -0.2409], [0.0969, -0.2168], [0.0891, -0.1951]], 0.503, 1.773, 0.1, 3.0], ['drift', 1, 0.766638]]], [[[[[-0.057, -0.938], [-0.0508, -0.9099], [-0.0476, -0.8826], [-0.0384, -0.8561], [-0.0319, -0.8304], [-0.0282, -0.8055], [-0.0214, -0.7813], [-0.0139, -0.7579]], 1.511, 1.175, 0.05, 2.0], ['drift', 1, 0.349947]], [[[[0.062, -0.688], [0.0704, -0.7018], [0.0821, -0.7158], [0.0911, -0.7301], [0.1016, -0.7447], [0.1044, -0.7596], [0.1147, -0.7748], [0.1253, -0.7903]], 2.31, 1.395, 0.05, 1.5], ['drift', 2, 0.35618]], [[[[-0.944, -0.357], [-0.9235, -0.3463], [-0.9004, -0.3359], [-0.8797, -0.3258], [-0.8621, -0.316], [-0.8187, -0.3066], [-0.7942, -0.2974]], 0.792, 1.826, 0.1, 3.0], ['drift', 3, 0.295621]], [[[[0.667, -0.316], [0.6492, -0.3065], [0.6243, -0.2973], [0.6058, -0.2884]], 2.457, 2.222, 0.05, 2.0], ['drift', 1, 0.173734]], [[[[0.391, -0.178], [0.4405, -0.1958], [0.4898, -0.2154], [0.5391, -0.2369], [0.6071, -0.2606], [0.6867, -0.2867], [0.7629, -0.3153], [0.8349, -0.3469]], 4.647, 2.014, 0.01, 3.0], ['blowup', 5, 2.044069]], [[[[0.423, -0.046], [0.4239, -0.046], [0.4257, -0.046], [0.4288, -0.046], [0.4231, -0.046], [0.4219, -0.046], [0.4287, -0.046], [0.4355, -0.046]], 3.517, 0.566, 0.05, 3.0], ['drift', 7, 0.059861]], [[[[-0.069, -0.252], [-0.0624, -0.2444], [-0.0511, -0.2371], [-0.0459, -0.23], [-0.0389, -0.2231], [-0.0374, -0.2164], [-0.0336, -0.2099], [-0.0314, -0.2036], [-0.028, -0.1975]], 1.826, 1.794, 0.1, 2.0], ['drift', 2, 0.41764]], [[[[-0.431, -0.68], [-0.4341, -0.68], [-0.4283, -0.68]], 4.27, 1.291, 0.05, 3.0], ['ok', -1, 0.008237]]], [[[[[-0.339, 0.793], [-0.3323, 0.793], [-0.3359, 0.793], [-0.3369, 0.793], [-0.336, 0.793], [-0.3248, 0.793]], 0.613, 1.879, 0.1, 2.0], ['ok', -1, 0.004615]], [[[[-0.158, 0.273], [-0.1584, 0.2785], [-0.155, 0.284], [-0.1529, 0.2897], [-0.1492, 0.2955], [-0.1509, 0.3014], [-0.1437, 0.3074]], 3.45, 0.863, 0.1, 3.0], ['ok', -1, 0.043282]], [[[[0.599, -0.265], [0.6726, -0.2915], [0.7436, -0.3207], [0.8129, -0.3527], [0.9144, -0.388], [1.0101, -0.4268], [1.1116, -0.4695], [1.2193, -0.5164]], 2.659, 2.064, 0.01, 3.0], ['blowup', 6, 2.403627]], [[[[-0.121, -0.819], [-0.1224, -0.8354], [-0.1203, -0.8521], [-0.1142, -0.8691], [-0.1142, -0.8865]], 4.298, 2.862, 0.01, 1.5], ['drift', 1, 0.162713]], [[[[-0.767, 0.422], [-0.8362, 0.4642], [-0.9046, 0.5106], [-0.9919, 0.5617], [-1.0702, 0.6179]], 2.965, 2.069, 0.05, 3.0], ['drift', 1, 0.981246]], [[[[0.037, 0.336], [0.0442, 0.3696], [0.0557, 0.4066], [0.0633, 0.4472], [0.0788, 0.4919]], 2.156, 1.537, 0.01, 3.0], ['drift', 1, 1.183276]], [[[[0.091, 0.464], [0.0983, 0.4733], [0.1024, 0.4827], [0.1069, 0.4924], [0.1193, 0.5022]], 3.473, 1.231, 0.05, 1.5], ['drift', 1, 0.225006]], [[[[0.788, 0.541], [0.8584, 0.5951], [0.9528, 0.6546], [1.0365, 0.7201], [1.1562, 0.7921], [1.2724, 0.8713]], 4.609, 2.968, 0.1, 3.0], ['drift', 1, 1.604181]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("case %d" % i, 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 fixtureActualExpectedOutcome
case 0['ok', -1, 0.002428]['ok', -1, 0.002428]Passed
case 1['drift', 1, 0.781113]['drift', 1, 0.781113]Passed
case 2['drift', 2, 0.121974]['drift', 2, 0.121974]Passed
case 3['ok', -1, 1e-05]['ok', -1, 1e-05]Passed
case 4['drift', 1, 0.143558]['drift', 1, 0.143558]Passed
case 5['blowup', 6, 2.555081]['blowup', 6, 2.555081]Passed
case 6['drift', 1, 0.358106]['drift', 1, 0.358106]Passed
case 7['drift', 2, 0.435375]['drift', 2, 0.435375]Passed

SHA-256 / 28e99ddc79855e190e220142a104f440713044715f12a8f51eaa20be4360e568

Verification & scope

A deterministic bounded teaching model with stipulated toy conventions and rounded float output; not a production physics engine or a proof of numerical stability. 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:50:57.888644+00:00.

Case digest / f17095086f61cc4fda743f40b949a1276e41d5eb55c4c217906336025c932d16