FAILURE MAP
← Case archive

FA-87311 / Physics integrator stability / Open access

Energy drift is measured step-to-step instead of against the initial energy · case 01

Slow monotone drift never trips the monitor.

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

ROOT CAUSE

r compares E with the previous state energy.

VERIFIED REPAIR

Compare against E0 captured at the first state.

Unsuccessful approach: Guarding the first index still compares consecutive states.

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 - en(states[i - 1])) / 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.933, -0.478], [-0.924, -0.478], [-0.9346, -0.478], [-0.9287, -0.478], [-0.9234, -0.478], [-0.9121, -0.478], [-0.9169, -0.478], [-0.9056, -0.478]], 2.311, 1.174, 0.01, 2.0], ['drift', 1, 0.051064]], [[[[0.004, -0.409], [0.0094, -0.3967], [0.0097, -0.3848], [0.0192, -0.3733], [0.0192, -0.3621]], 0.581, 1.351, 0.1, 3.0], ['drift', 2, 0.215275]], [[[[-0.19, 0.976], [-0.17, 0.8784], [-0.1439, 0.7906], [-0.1237, 0.7115], [-0.1063, 0.6404], [-0.087, 0.5763], [-0.0692, 0.5187], [-0.0545, 0.4668]], 4.04, 1.371, 0.01, 1.5], ['drift', 1, 0.785963]], [[[[0.0, 0.0], [0.0033, 0.0], [0.0081, 0.0], [0.0083, 0.0], [0.0094, 0.0], [0.011, 0.0]], 4.869, 0.774, 0.01, 3.0], ['ok', -1, 0.000295]], [[[[0.329, 0.997], [0.3288, 0.9671], [0.318, 0.9381], [0.3095, 0.9099]], 2.385, 2.477, 0.1, 1.5], ['drift', 2, 0.162151]], [[[[-0.138, 0.988], [-0.1281, 0.988], [-0.1264, 0.988]], 2.839, 1.096, 0.1, 3.0], ['ok', -1, 0.007747]], [[[[0.0, 0.0], [0.0088, 0.0], [0.0184, 0.0], [0.0249, 0.0], [0.0337, 0.0], [0.0376, 0.0]], 4.601, 1.731, 0.01, 2.0], ['ok', -1, 0.003252]], [[[[0.786, -0.334], [0.8678, -0.3674], [0.9819, -0.4041], [1.0759, -0.4446]], 2.209, 1.196, 0.01, 3.0], ['drift', 1, 0.864631]]], [[[[[-0.327, -0.693], [-0.315, -0.693], [-0.3047, -0.693], [-0.3009, -0.693], [-0.2863, -0.693], [-0.2895, -0.693], [-0.2877, -0.693]], 2.356, 0.963, 0.05, 2.0], ['drift', 3, 0.082319]], [[[[0.19, 0.403], [0.1949, 0.403], [0.1964, 0.403]], 2.101, 1.785, 0.1, 2.0], ['ok', -1, 0.014206]], [[[[0.13, -0.686], [0.1254, -0.6654], [0.1254, -0.6455], [0.1254, -0.6261], [0.126, -0.6073], [0.1227, -0.5891], [0.1219, -0.5714], [0.1204, -0.5543], [0.1221, -0.5376]], 1.046, 1.507, 0.01, 2.0], ['drift', 1, 0.379338]], [[[[0.0, 0.0], [0.0066, 0.0], [0.0158, 0.0], [0.0191, 0.0], [0.0228, 0.0], [0.023, 0.0]], 1.146, 1.18, 0.1, 1.5], ['ok', -1, 0.000303]], [[[[0.292, 0.94], [0.2659, 0.846], [0.2472, 0.7614], [0.231, 0.6853], [0.2114, 0.6167], [0.1933, 0.5551]], 0.502, 1.346, 0.1, 1.5], ['drift', 1, 0.648163]], [[[[0.407, 0.95], [0.391, 0.9215], [0.3835, 0.8939], [0.3857, 0.867], [0.3808, 0.841], [0.3731, 0.8158]], 3.837, 0.892, 0.1, 2.0], ['drift', 2, 0.217162]], [[[[0.861, 0.935], [0.9739, 1.0285], [1.0965, 1.1314], [1.229, 1.2445], [1.3651, 1.3689], [1.4921, 1.5058]], 2.861, 2.192, 0.1, 1.5], ['blowup', 2, 0.547035]], [[[[-0.009, 0.479], [-0.0002, 0.479], [0.0045, 0.479], [0.0118, 0.479], [0.0156, 0.479]], 4.602, 1.292, 0.01, 2.0], ['ok', -1, 0.002517]]], [[[[[-0.844, -0.85], [-0.8281, -0.85], [-0.8348, -0.85], [-0.8267, -0.85], [-0.8342, -0.85]], 1.842, 1.328, 0.01, 1.5], ['drift', 1, 0.023437]], [[[[0.556, -0.102], [0.5094, -0.0918], [0.4634, -0.0826], [0.4181, -0.0744], [0.3873, -0.0669]], 1.845, 2.753, 0.1, 1.5], ['drift', 1, 0.517405]], [[[[-0.864, -0.368], [-0.8698, -0.3754], [-0.8662, -0.3829], [-0.8745, -0.3905]], 1.369, 0.756, 0.05, 1.5], ['ok', -1, 0.033702]], [[[[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.999, -0.103], [0.9738, -0.0999], [0.9396, -0.0969]], 3.014, 0.888, 0.01, 1.5], ['drift', 1, 0.115382]], [[[[-0.453, 0.276], [-0.4548, 0.2815], [-0.4609, 0.2872], [-0.4596, 0.2929], [-0.458, 0.2988], [-0.4719, 0.3047], [-0.4807, 0.3108], [-0.4846, 0.317]], 0.835, 1.204, 0.05, 2.0], ['drift', 2, 0.205319]], [[[[0.955, 0.743], [0.9477, 0.743], [0.9408, 0.743], [0.9342, 0.743]], 2.622, 2.919, 0.05, 2.0], ['ok', -1, 0.02574]], [[[[0.692, 0.818], [0.6854, 0.818], [0.6936, 0.818], [0.6942, 0.818], [0.6932, 0.818], [0.6868, 0.818], [0.6915, 0.818]], 1.059, 1.362, 0.1, 1.5], ['ok', -1, 0.006787]]], [[[[[0.0, 0.0], [0.0056, 0.0], [0.0137, 0.0], [0.0234, 0.0], [0.0241, 0.0], [0.0298, 0.0], [0.0383, 0.0], [0.0446, 0.0], [0.0544, 0.0]], 1.23, 1.703, 0.05, 1.5], ['ok', -1, 0.00182]], [[[[0.216, 0.571], [0.216, 0.5539], [0.2149, 0.5373], [0.2096, 0.5211], [0.2103, 0.5055], [0.2136, 0.4903], [0.2168, 0.4756], [0.217, 0.4614]], 0.806, 1.788, 0.01, 1.5], ['drift', 1, 0.325453]], [[[[-0.842, -0.267], [-0.9252, -0.2937], [-1.0242, -0.3231], [-1.1, -0.3554], [-1.2174, -0.3909]], 1.329, 0.961, 0.1, 2.0], ['blowup', 4, 1.094053]], [[[[0.616, 0.531], [0.6092, 0.5151], [0.5862, 0.4996], [0.5701, 0.4846], [0.5641, 0.4701], [0.5606, 0.456], [0.5539, 0.4423], [0.5418, 0.429], [0.5384, 0.4162], [0.5267, 0.4037]], 4.512, 1.221, 0.01, 2.0], ['drift', 1, 0.294548]], [[[[0.699, -0.578], [0.707, -0.578], [0.7158, -0.578], [0.7171, -0.578]], 4.155, 2.539, 0.05, 1.5], ['ok', -1, 0.037]], [[[[0.935, 0.607], [0.9784, 0.6191], [0.9876, 0.6315], [0.9907, 0.6442]], 1.868, 0.979, 0.1, 2.0], ['drift', 2, 0.12335]], [[[[-0.595, 0.526], [-0.6641, 0.5786], [-0.7188, 0.6365], [-0.7676, 0.7001]], 1.903, 1.374, 0.05, 2.0], ['drift', 1, 0.702991]], [[[[-0.451, 0.619], [-0.3955, 0.5571], [-0.3575, 0.5014], [-0.3162, 0.4513], [-0.2794, 0.4061]], 1.63, 0.681, 0.01, 2.0], ['drift', 1, 0.595674]]], [[[[[0.164, -0.748], [0.1494, -0.6732], [0.1418, -0.6059]], 3.326, 0.646, 0.01, 1.5], ['drift', 1, 0.325714]], [[[[-0.29, -0.647], [-0.2771, -0.6276], [-0.2679, -0.6088], [-0.2463, -0.5905], [-0.234, -0.5728], [-0.222, -0.5556], [-0.2137, -0.5389], [-0.2016, -0.5228]], 0.876, 1.467, 0.01, 2.0], ['drift', 1, 0.365249]], [[[[-0.27, -0.874], [-0.2335, -0.7866], [-0.1987, -0.7079]], 2.689, 1.393, 0.05, 2.0], ['drift', 1, 0.361777]], [[[[0.0, 0.0], [0.0055, 0.0], [0.0081, 0.0], [0.0095, 0.0], [0.0163, 0.0], [0.0203, 0.0], [0.0279, 0.0], [0.0288, 0.0], [0.0327, 0.0], [0.0328, 0.0]], 0.585, 2.269, 0.05, 1.5], ['ok', -1, 0.000315]], [[[[0.951, 0.313], [1.0604, 0.3443], [1.1582, 0.3787], [1.27, 0.4166], [1.3919, 0.4583], [1.5273, 0.5041], [1.6949, 0.5545], [1.8851, 0.6099], [2.1058, 0.6709]], 3.16, 1.484, 0.05, 1.5], ['blowup', 3, 0.782816]], [[[[0.174, -0.48], [0.1771, -0.4896], [0.1863, -0.4994], [0.1987, -0.5094], [0.2011, -0.5196]], 1.179, 1.294, 0.01, 1.5], ['drift', 1, 0.189336]], [[[[0.0, 0.0], [0.0076, 0.0], [0.0119, 0.0]], 3.375, 0.919, 0.1, 3.0], ['ok', -1, 0.000239]], [[[[0.304, 0.926], [0.2951, 0.8982], [0.2913, 0.8713], [0.2845, 0.8451], [0.273, 0.8198]], 4.318, 0.794, 0.01, 2.0], ['drift', 1, 0.207843]]]]
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['drift', 0, 0.051064]['drift', 1, 0.051064]Failed
case 1['drift', 0, 0.215275]['drift', 2, 0.215275]Failed
case 2['drift', 0, 0.785963]['drift', 1, 0.785963]Failed
case 3['ok', -1, 0.000295]['ok', -1, 0.000295]Passed
case 4['drift', 0, 0.162151]['drift', 2, 0.162151]Failed
case 5['ok', -1, 0.007747]['ok', -1, 0.007747]Passed
case 6['ok', -1, 0.003252]['ok', -1, 0.003252]Passed
case 7['drift', 0, 0.864631]['drift', 1, 0.864631]Failed

SHA-256 / 6f41a2ae44cb460b5d6adcf876ee609d1063282fa5040f24bbc88da14e451e85

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 - en(states[max(i - 1, 0)])) / 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.933, -0.478], [-0.924, -0.478], [-0.9346, -0.478], [-0.9287, -0.478], [-0.9234, -0.478], [-0.9121, -0.478], [-0.9169, -0.478], [-0.9056, -0.478]], 2.311, 1.174, 0.01, 2.0], ['drift', 1, 0.051064]], [[[[0.004, -0.409], [0.0094, -0.3967], [0.0097, -0.3848], [0.0192, -0.3733], [0.0192, -0.3621]], 0.581, 1.351, 0.1, 3.0], ['drift', 2, 0.215275]], [[[[-0.19, 0.976], [-0.17, 0.8784], [-0.1439, 0.7906], [-0.1237, 0.7115], [-0.1063, 0.6404], [-0.087, 0.5763], [-0.0692, 0.5187], [-0.0545, 0.4668]], 4.04, 1.371, 0.01, 1.5], ['drift', 1, 0.785963]], [[[[0.0, 0.0], [0.0033, 0.0], [0.0081, 0.0], [0.0083, 0.0], [0.0094, 0.0], [0.011, 0.0]], 4.869, 0.774, 0.01, 3.0], ['ok', -1, 0.000295]], [[[[0.329, 0.997], [0.3288, 0.9671], [0.318, 0.9381], [0.3095, 0.9099]], 2.385, 2.477, 0.1, 1.5], ['drift', 2, 0.162151]], [[[[-0.138, 0.988], [-0.1281, 0.988], [-0.1264, 0.988]], 2.839, 1.096, 0.1, 3.0], ['ok', -1, 0.007747]], [[[[0.0, 0.0], [0.0088, 0.0], [0.0184, 0.0], [0.0249, 0.0], [0.0337, 0.0], [0.0376, 0.0]], 4.601, 1.731, 0.01, 2.0], ['ok', -1, 0.003252]], [[[[0.786, -0.334], [0.8678, -0.3674], [0.9819, -0.4041], [1.0759, -0.4446]], 2.209, 1.196, 0.01, 3.0], ['drift', 1, 0.864631]]], [[[[[-0.327, -0.693], [-0.315, -0.693], [-0.3047, -0.693], [-0.3009, -0.693], [-0.2863, -0.693], [-0.2895, -0.693], [-0.2877, -0.693]], 2.356, 0.963, 0.05, 2.0], ['drift', 3, 0.082319]], [[[[0.19, 0.403], [0.1949, 0.403], [0.1964, 0.403]], 2.101, 1.785, 0.1, 2.0], ['ok', -1, 0.014206]], [[[[0.13, -0.686], [0.1254, -0.6654], [0.1254, -0.6455], [0.1254, -0.6261], [0.126, -0.6073], [0.1227, -0.5891], [0.1219, -0.5714], [0.1204, -0.5543], [0.1221, -0.5376]], 1.046, 1.507, 0.01, 2.0], ['drift', 1, 0.379338]], [[[[0.0, 0.0], [0.0066, 0.0], [0.0158, 0.0], [0.0191, 0.0], [0.0228, 0.0], [0.023, 0.0]], 1.146, 1.18, 0.1, 1.5], ['ok', -1, 0.000303]], [[[[0.292, 0.94], [0.2659, 0.846], [0.2472, 0.7614], [0.231, 0.6853], [0.2114, 0.6167], [0.1933, 0.5551]], 0.502, 1.346, 0.1, 1.5], ['drift', 1, 0.648163]], [[[[0.407, 0.95], [0.391, 0.9215], [0.3835, 0.8939], [0.3857, 0.867], [0.3808, 0.841], [0.3731, 0.8158]], 3.837, 0.892, 0.1, 2.0], ['drift', 2, 0.217162]], [[[[0.861, 0.935], [0.9739, 1.0285], [1.0965, 1.1314], [1.229, 1.2445], [1.3651, 1.3689], [1.4921, 1.5058]], 2.861, 2.192, 0.1, 1.5], ['blowup', 2, 0.547035]], [[[[-0.009, 0.479], [-0.0002, 0.479], [0.0045, 0.479], [0.0118, 0.479], [0.0156, 0.479]], 4.602, 1.292, 0.01, 2.0], ['ok', -1, 0.002517]]], [[[[[-0.844, -0.85], [-0.8281, -0.85], [-0.8348, -0.85], [-0.8267, -0.85], [-0.8342, -0.85]], 1.842, 1.328, 0.01, 1.5], ['drift', 1, 0.023437]], [[[[0.556, -0.102], [0.5094, -0.0918], [0.4634, -0.0826], [0.4181, -0.0744], [0.3873, -0.0669]], 1.845, 2.753, 0.1, 1.5], ['drift', 1, 0.517405]], [[[[-0.864, -0.368], [-0.8698, -0.3754], [-0.8662, -0.3829], [-0.8745, -0.3905]], 1.369, 0.756, 0.05, 1.5], ['ok', -1, 0.033702]], [[[[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.999, -0.103], [0.9738, -0.0999], [0.9396, -0.0969]], 3.014, 0.888, 0.01, 1.5], ['drift', 1, 0.115382]], [[[[-0.453, 0.276], [-0.4548, 0.2815], [-0.4609, 0.2872], [-0.4596, 0.2929], [-0.458, 0.2988], [-0.4719, 0.3047], [-0.4807, 0.3108], [-0.4846, 0.317]], 0.835, 1.204, 0.05, 2.0], ['drift', 2, 0.205319]], [[[[0.955, 0.743], [0.9477, 0.743], [0.9408, 0.743], [0.9342, 0.743]], 2.622, 2.919, 0.05, 2.0], ['ok', -1, 0.02574]], [[[[0.692, 0.818], [0.6854, 0.818], [0.6936, 0.818], [0.6942, 0.818], [0.6932, 0.818], [0.6868, 0.818], [0.6915, 0.818]], 1.059, 1.362, 0.1, 1.5], ['ok', -1, 0.006787]]], [[[[[0.0, 0.0], [0.0056, 0.0], [0.0137, 0.0], [0.0234, 0.0], [0.0241, 0.0], [0.0298, 0.0], [0.0383, 0.0], [0.0446, 0.0], [0.0544, 0.0]], 1.23, 1.703, 0.05, 1.5], ['ok', -1, 0.00182]], [[[[0.216, 0.571], [0.216, 0.5539], [0.2149, 0.5373], [0.2096, 0.5211], [0.2103, 0.5055], [0.2136, 0.4903], [0.2168, 0.4756], [0.217, 0.4614]], 0.806, 1.788, 0.01, 1.5], ['drift', 1, 0.325453]], [[[[-0.842, -0.267], [-0.9252, -0.2937], [-1.0242, -0.3231], [-1.1, -0.3554], [-1.2174, -0.3909]], 1.329, 0.961, 0.1, 2.0], ['blowup', 4, 1.094053]], [[[[0.616, 0.531], [0.6092, 0.5151], [0.5862, 0.4996], [0.5701, 0.4846], [0.5641, 0.4701], [0.5606, 0.456], [0.5539, 0.4423], [0.5418, 0.429], [0.5384, 0.4162], [0.5267, 0.4037]], 4.512, 1.221, 0.01, 2.0], ['drift', 1, 0.294548]], [[[[0.699, -0.578], [0.707, -0.578], [0.7158, -0.578], [0.7171, -0.578]], 4.155, 2.539, 0.05, 1.5], ['ok', -1, 0.037]], [[[[0.935, 0.607], [0.9784, 0.6191], [0.9876, 0.6315], [0.9907, 0.6442]], 1.868, 0.979, 0.1, 2.0], ['drift', 2, 0.12335]], [[[[-0.595, 0.526], [-0.6641, 0.5786], [-0.7188, 0.6365], [-0.7676, 0.7001]], 1.903, 1.374, 0.05, 2.0], ['drift', 1, 0.702991]], [[[[-0.451, 0.619], [-0.3955, 0.5571], [-0.3575, 0.5014], [-0.3162, 0.4513], [-0.2794, 0.4061]], 1.63, 0.681, 0.01, 2.0], ['drift', 1, 0.595674]]], [[[[[0.164, -0.748], [0.1494, -0.6732], [0.1418, -0.6059]], 3.326, 0.646, 0.01, 1.5], ['drift', 1, 0.325714]], [[[[-0.29, -0.647], [-0.2771, -0.6276], [-0.2679, -0.6088], [-0.2463, -0.5905], [-0.234, -0.5728], [-0.222, -0.5556], [-0.2137, -0.5389], [-0.2016, -0.5228]], 0.876, 1.467, 0.01, 2.0], ['drift', 1, 0.365249]], [[[[-0.27, -0.874], [-0.2335, -0.7866], [-0.1987, -0.7079]], 2.689, 1.393, 0.05, 2.0], ['drift', 1, 0.361777]], [[[[0.0, 0.0], [0.0055, 0.0], [0.0081, 0.0], [0.0095, 0.0], [0.0163, 0.0], [0.0203, 0.0], [0.0279, 0.0], [0.0288, 0.0], [0.0327, 0.0], [0.0328, 0.0]], 0.585, 2.269, 0.05, 1.5], ['ok', -1, 0.000315]], [[[[0.951, 0.313], [1.0604, 0.3443], [1.1582, 0.3787], [1.27, 0.4166], [1.3919, 0.4583], [1.5273, 0.5041], [1.6949, 0.5545], [1.8851, 0.6099], [2.1058, 0.6709]], 3.16, 1.484, 0.05, 1.5], ['blowup', 3, 0.782816]], [[[[0.174, -0.48], [0.1771, -0.4896], [0.1863, -0.4994], [0.1987, -0.5094], [0.2011, -0.5196]], 1.179, 1.294, 0.01, 1.5], ['drift', 1, 0.189336]], [[[[0.0, 0.0], [0.0076, 0.0], [0.0119, 0.0]], 3.375, 0.919, 0.1, 3.0], ['ok', -1, 0.000239]], [[[[0.304, 0.926], [0.2951, 0.8982], [0.2913, 0.8713], [0.2845, 0.8451], [0.273, 0.8198]], 4.318, 0.794, 0.01, 2.0], ['drift', 1, 0.207843]]]]
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['drift', 1, 0.021024]['drift', 1, 0.051064]Failed
case 1['ok', -1, 0.059054]['drift', 2, 0.215275]Failed
case 2['drift', 1, 0.190949]['drift', 1, 0.785963]Failed
case 3['ok', -1, 0.000133]['ok', -1, 0.000295]Failed
case 4['ok', -1, 0.056433]['drift', 2, 0.162151]Failed
case 5['ok', -1, 0.006654]['ok', -1, 0.007747]Failed
case 6['ok', -1, 0.001186]['ok', -1, 0.003252]Failed
case 7['drift', 1, 0.333799]['drift', 1, 0.864631]Failed

SHA-256 / d5b7302b8ddc257dba40ec6ec9d1dabbcdfbcfd974decae1606cff096c07db2e

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.933, -0.478], [-0.924, -0.478], [-0.9346, -0.478], [-0.9287, -0.478], [-0.9234, -0.478], [-0.9121, -0.478], [-0.9169, -0.478], [-0.9056, -0.478]], 2.311, 1.174, 0.01, 2.0], ['drift', 1, 0.051064]], [[[[0.004, -0.409], [0.0094, -0.3967], [0.0097, -0.3848], [0.0192, -0.3733], [0.0192, -0.3621]], 0.581, 1.351, 0.1, 3.0], ['drift', 2, 0.215275]], [[[[-0.19, 0.976], [-0.17, 0.8784], [-0.1439, 0.7906], [-0.1237, 0.7115], [-0.1063, 0.6404], [-0.087, 0.5763], [-0.0692, 0.5187], [-0.0545, 0.4668]], 4.04, 1.371, 0.01, 1.5], ['drift', 1, 0.785963]], [[[[0.0, 0.0], [0.0033, 0.0], [0.0081, 0.0], [0.0083, 0.0], [0.0094, 0.0], [0.011, 0.0]], 4.869, 0.774, 0.01, 3.0], ['ok', -1, 0.000295]], [[[[0.329, 0.997], [0.3288, 0.9671], [0.318, 0.9381], [0.3095, 0.9099]], 2.385, 2.477, 0.1, 1.5], ['drift', 2, 0.162151]], [[[[-0.138, 0.988], [-0.1281, 0.988], [-0.1264, 0.988]], 2.839, 1.096, 0.1, 3.0], ['ok', -1, 0.007747]], [[[[0.0, 0.0], [0.0088, 0.0], [0.0184, 0.0], [0.0249, 0.0], [0.0337, 0.0], [0.0376, 0.0]], 4.601, 1.731, 0.01, 2.0], ['ok', -1, 0.003252]], [[[[0.786, -0.334], [0.8678, -0.3674], [0.9819, -0.4041], [1.0759, -0.4446]], 2.209, 1.196, 0.01, 3.0], ['drift', 1, 0.864631]]], [[[[[-0.327, -0.693], [-0.315, -0.693], [-0.3047, -0.693], [-0.3009, -0.693], [-0.2863, -0.693], [-0.2895, -0.693], [-0.2877, -0.693]], 2.356, 0.963, 0.05, 2.0], ['drift', 3, 0.082319]], [[[[0.19, 0.403], [0.1949, 0.403], [0.1964, 0.403]], 2.101, 1.785, 0.1, 2.0], ['ok', -1, 0.014206]], [[[[0.13, -0.686], [0.1254, -0.6654], [0.1254, -0.6455], [0.1254, -0.6261], [0.126, -0.6073], [0.1227, -0.5891], [0.1219, -0.5714], [0.1204, -0.5543], [0.1221, -0.5376]], 1.046, 1.507, 0.01, 2.0], ['drift', 1, 0.379338]], [[[[0.0, 0.0], [0.0066, 0.0], [0.0158, 0.0], [0.0191, 0.0], [0.0228, 0.0], [0.023, 0.0]], 1.146, 1.18, 0.1, 1.5], ['ok', -1, 0.000303]], [[[[0.292, 0.94], [0.2659, 0.846], [0.2472, 0.7614], [0.231, 0.6853], [0.2114, 0.6167], [0.1933, 0.5551]], 0.502, 1.346, 0.1, 1.5], ['drift', 1, 0.648163]], [[[[0.407, 0.95], [0.391, 0.9215], [0.3835, 0.8939], [0.3857, 0.867], [0.3808, 0.841], [0.3731, 0.8158]], 3.837, 0.892, 0.1, 2.0], ['drift', 2, 0.217162]], [[[[0.861, 0.935], [0.9739, 1.0285], [1.0965, 1.1314], [1.229, 1.2445], [1.3651, 1.3689], [1.4921, 1.5058]], 2.861, 2.192, 0.1, 1.5], ['blowup', 2, 0.547035]], [[[[-0.009, 0.479], [-0.0002, 0.479], [0.0045, 0.479], [0.0118, 0.479], [0.0156, 0.479]], 4.602, 1.292, 0.01, 2.0], ['ok', -1, 0.002517]]], [[[[[-0.844, -0.85], [-0.8281, -0.85], [-0.8348, -0.85], [-0.8267, -0.85], [-0.8342, -0.85]], 1.842, 1.328, 0.01, 1.5], ['drift', 1, 0.023437]], [[[[0.556, -0.102], [0.5094, -0.0918], [0.4634, -0.0826], [0.4181, -0.0744], [0.3873, -0.0669]], 1.845, 2.753, 0.1, 1.5], ['drift', 1, 0.517405]], [[[[-0.864, -0.368], [-0.8698, -0.3754], [-0.8662, -0.3829], [-0.8745, -0.3905]], 1.369, 0.756, 0.05, 1.5], ['ok', -1, 0.033702]], [[[[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.999, -0.103], [0.9738, -0.0999], [0.9396, -0.0969]], 3.014, 0.888, 0.01, 1.5], ['drift', 1, 0.115382]], [[[[-0.453, 0.276], [-0.4548, 0.2815], [-0.4609, 0.2872], [-0.4596, 0.2929], [-0.458, 0.2988], [-0.4719, 0.3047], [-0.4807, 0.3108], [-0.4846, 0.317]], 0.835, 1.204, 0.05, 2.0], ['drift', 2, 0.205319]], [[[[0.955, 0.743], [0.9477, 0.743], [0.9408, 0.743], [0.9342, 0.743]], 2.622, 2.919, 0.05, 2.0], ['ok', -1, 0.02574]], [[[[0.692, 0.818], [0.6854, 0.818], [0.6936, 0.818], [0.6942, 0.818], [0.6932, 0.818], [0.6868, 0.818], [0.6915, 0.818]], 1.059, 1.362, 0.1, 1.5], ['ok', -1, 0.006787]]], [[[[[0.0, 0.0], [0.0056, 0.0], [0.0137, 0.0], [0.0234, 0.0], [0.0241, 0.0], [0.0298, 0.0], [0.0383, 0.0], [0.0446, 0.0], [0.0544, 0.0]], 1.23, 1.703, 0.05, 1.5], ['ok', -1, 0.00182]], [[[[0.216, 0.571], [0.216, 0.5539], [0.2149, 0.5373], [0.2096, 0.5211], [0.2103, 0.5055], [0.2136, 0.4903], [0.2168, 0.4756], [0.217, 0.4614]], 0.806, 1.788, 0.01, 1.5], ['drift', 1, 0.325453]], [[[[-0.842, -0.267], [-0.9252, -0.2937], [-1.0242, -0.3231], [-1.1, -0.3554], [-1.2174, -0.3909]], 1.329, 0.961, 0.1, 2.0], ['blowup', 4, 1.094053]], [[[[0.616, 0.531], [0.6092, 0.5151], [0.5862, 0.4996], [0.5701, 0.4846], [0.5641, 0.4701], [0.5606, 0.456], [0.5539, 0.4423], [0.5418, 0.429], [0.5384, 0.4162], [0.5267, 0.4037]], 4.512, 1.221, 0.01, 2.0], ['drift', 1, 0.294548]], [[[[0.699, -0.578], [0.707, -0.578], [0.7158, -0.578], [0.7171, -0.578]], 4.155, 2.539, 0.05, 1.5], ['ok', -1, 0.037]], [[[[0.935, 0.607], [0.9784, 0.6191], [0.9876, 0.6315], [0.9907, 0.6442]], 1.868, 0.979, 0.1, 2.0], ['drift', 2, 0.12335]], [[[[-0.595, 0.526], [-0.6641, 0.5786], [-0.7188, 0.6365], [-0.7676, 0.7001]], 1.903, 1.374, 0.05, 2.0], ['drift', 1, 0.702991]], [[[[-0.451, 0.619], [-0.3955, 0.5571], [-0.3575, 0.5014], [-0.3162, 0.4513], [-0.2794, 0.4061]], 1.63, 0.681, 0.01, 2.0], ['drift', 1, 0.595674]]], [[[[[0.164, -0.748], [0.1494, -0.6732], [0.1418, -0.6059]], 3.326, 0.646, 0.01, 1.5], ['drift', 1, 0.325714]], [[[[-0.29, -0.647], [-0.2771, -0.6276], [-0.2679, -0.6088], [-0.2463, -0.5905], [-0.234, -0.5728], [-0.222, -0.5556], [-0.2137, -0.5389], [-0.2016, -0.5228]], 0.876, 1.467, 0.01, 2.0], ['drift', 1, 0.365249]], [[[[-0.27, -0.874], [-0.2335, -0.7866], [-0.1987, -0.7079]], 2.689, 1.393, 0.05, 2.0], ['drift', 1, 0.361777]], [[[[0.0, 0.0], [0.0055, 0.0], [0.0081, 0.0], [0.0095, 0.0], [0.0163, 0.0], [0.0203, 0.0], [0.0279, 0.0], [0.0288, 0.0], [0.0327, 0.0], [0.0328, 0.0]], 0.585, 2.269, 0.05, 1.5], ['ok', -1, 0.000315]], [[[[0.951, 0.313], [1.0604, 0.3443], [1.1582, 0.3787], [1.27, 0.4166], [1.3919, 0.4583], [1.5273, 0.5041], [1.6949, 0.5545], [1.8851, 0.6099], [2.1058, 0.6709]], 3.16, 1.484, 0.05, 1.5], ['blowup', 3, 0.782816]], [[[[0.174, -0.48], [0.1771, -0.4896], [0.1863, -0.4994], [0.1987, -0.5094], [0.2011, -0.5196]], 1.179, 1.294, 0.01, 1.5], ['drift', 1, 0.189336]], [[[[0.0, 0.0], [0.0076, 0.0], [0.0119, 0.0]], 3.375, 0.919, 0.1, 3.0], ['ok', -1, 0.000239]], [[[[0.304, 0.926], [0.2951, 0.8982], [0.2913, 0.8713], [0.2845, 0.8451], [0.273, 0.8198]], 4.318, 0.794, 0.01, 2.0], ['drift', 1, 0.207843]]]]
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['drift', 1, 0.051064]['drift', 1, 0.051064]Passed
case 1['drift', 2, 0.215275]['drift', 2, 0.215275]Passed
case 2['drift', 1, 0.785963]['drift', 1, 0.785963]Passed
case 3['ok', -1, 0.000295]['ok', -1, 0.000295]Passed
case 4['drift', 2, 0.162151]['drift', 2, 0.162151]Passed
case 5['ok', -1, 0.007747]['ok', -1, 0.007747]Passed
case 6['ok', -1, 0.003252]['ok', -1, 0.003252]Passed
case 7['drift', 1, 0.864631]['drift', 1, 0.864631]Passed

SHA-256 / 38158bf746f91ec81c3f12a3428db063de614d66da6826374c5fc480b05973c2

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.659442+00:00.

Case digest / 0faead972e8a2b9ffdcfc9c908e17ea2327c2ac574142faa06a7352135499b7b