FAILURE MAP
← Case archive

FA-87206 / Physics integrator stability / Open access

Contact impulse multiplies by the inverse mass sum · case 01

Light bodies get tiny impulses and heavy bodies are over-corrected.

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

ROOT CAUSE

lam = (target-vn)*w instead of dividing by w.

VERIFIED REPAIR

Effective mass is 1/(ima+imb).

Unsuccessful approach: Dividing by only the larger inverse mass ignores the other body.

Case contract

solve(vn, depth, ima, imb, beta, slop, dt, e, e_thresh): one normal contact, vn<0 approaching. bias=(beta/dt)*(depth-slop) if positive; bounce=-e*vn when vn<-e_thresh. Target separating speed is max(bias,bounce); impulse=(target-vn)/(ima+imb) clamped at 0 (no pulling). Zero summed inverse mass gives [0, vn]. Return [impulse, post velocity] rounded to 6.

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(vn, depth, ima, imb, beta, slop, dt, e, e_thresh):
    w = ima + imb
    if w == 0:
        return [0.0, round(vn, 6)]
    pen = depth - slop
    bias = beta / dt * pen if pen > 0 else 0.0
    bounce = -e * vn if vn < -e_thresh else 0.0
    target = max(bias, bounce)
    lam = (target - vn) * w
    if lam < 0:
        lam = 0.0
    return [round(lam, 6), round(vn + lam * w, 6)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[-4.177, 0.112, 0.0, 0.0, 0.1, 0.005, 0.016666666666666666, 0.3, 1.0], [0.0, -4.177]], [[1.41, 0.135, 0.151, 1.614, 0.3, 0.01, 0.016666666666666666, 0.0, 0.5], [0.475921, 2.25]], [[-3.935, -0.001, 0.725, 0.0, 0.2, 0.01, 0.016666666666666666, 0.0, 1.0], [5.427586, 0.0]], [[-1.967, 0.032, 0.824, 0.115, 0.1, 0.01, 0.016666666666666666, 0.3, 1.0], [2.723216, 0.5901]], [[0.508, 0.146, 0.0, 0.354, 0.2, 0.01, 0.03333333333333333, 0.8, 1.0], [0.870056, 0.816]], [[1.262, 0.19, 1.184, 1.117, 0.1, 0.005, 0.03333333333333333, 0.8, 1.0], [0.0, 1.262]], [[-0.308, 0.163, 0.198, 1.287, 0.3, 0.02, 0.03333333333333333, 0.8, 0.5], [1.074074, 1.287]], [[-1.72, 0.144, 0.0, 0.0, 0.2, 0.01, 0.016666666666666666, 0.3, 1.0], [0.0, -1.72]]], [[[0.591, 0.063, 0.548, 0.151, 0.1, 0.005, 0.016666666666666666, 0.0, 1.0], [0.0, 0.591]], [[-1.309, 0.06, 0.588, 0.3, 0.3, 0.005, 0.016666666666666666, 0.8, 0.5], [2.653378, 1.0472]], [[-1.029, 0.163, 0.695, 0.376, 0.3, 0.01, 0.016666666666666666, 0.3, 1.0], [3.532213, 2.754]], [[0.387, 0.038, 1.153, 0.0, 0.1, 0.01, 0.016666666666666666, 0.8, 0.5], [0.0, 0.387]], [[0.579, 0.19, 1.545, 1.81, 0.2, 0.02, 0.03333333333333333, 0.8, 0.5], [0.131446, 1.02]], [[-0.08, 0.034, 0.0, 1.484, 0.3, 0.005, 0.03333333333333333, 0.0, 0.5], [0.229784, 0.261]], [[-2.861, 0.183, 0.0, 1.604, 0.2, 0.02, 0.03333333333333333, 0.0, 1.0], [2.393392, 0.978]], [[1.423, 0.017, 0.0, 0.597, 0.2, 0.005, 0.03333333333333333, 0.3, 1.0], [0.0, 1.423]]], [[[-3.757, 0.012, 1.496, 1.54, 0.3, 0.01, 0.03333333333333333, 0.3, 0.5], [1.608729, 1.1271]], [[-3.134, 0.061, 0.847, 1.706, 0.3, 0.005, 0.03333333333333333, 0.3, 1.0], [1.595848, 0.9402]], [[-2.036, -0.001, 1.318, 0.182, 0.3, 0.01, 0.03333333333333333, 0.3, 0.5], [1.764533, 0.6108]], [[-0.903, 0.047, 0.0, 0.0, 0.1, 0.02, 0.03333333333333333, 0.0, 1.0], [0.0, -0.903]], [[-1.453, 0.06, 0.0, 0.0, 0.2, 0.01, 0.016666666666666666, 0.0, 0.5], [0.0, -1.453]], [[-1.057, 0.121, 1.527, 0.0, 0.1, 0.01, 0.03333333333333333, 0.8, 0.5], [1.245972, 0.8456]], [[-3.223, 0.016, 0.0, 0.775, 0.3, 0.02, 0.03333333333333333, 0.0, 0.5], [4.15871, 0.0]], [[0.409, 0.029, 0.104, 0.0, 0.1, 0.01, 0.016666666666666666, 0.3, 1.0], [0.0, 0.409]]], [[[1.004, 0.112, 0.796, 0.0, 0.1, 0.01, 0.03333333333333333, 0.8, 1.0], [0.0, 1.004]], [[-4.647, 0.009, 0.0, 0.0, 0.3, 0.005, 0.03333333333333333, 0.3, 1.0], [0.0, -4.647]], [[-4.992, 0.109, 1.939, 1.518, 0.1, 0.005, 0.03333333333333333, 0.0, 0.5], [1.534278, 0.312]], [[0.08, 0.097, 0.146, 0.0, 0.3, 0.005, 0.016666666666666666, 0.8, 0.5], [10.794521, 1.656]], [[-1.618, 0.083, 0.255, 0.217, 0.3, 0.01, 0.03333333333333333, 0.8, 0.5], [6.170339, 1.2944]], [[-4.633, 0.14, 0.0, 0.0, 0.1, 0.02, 0.016666666666666666, 0.0, 1.0], [0.0, -4.633]], [[-4.858, 0.174, 1.743, 0.441, 0.3, 0.005, 0.03333333333333333, 0.0, 1.0], [2.920788, 1.521]], [[-4.768, 0.04, 1.908, 1.371, 0.3, 0.01, 0.016666666666666666, 0.8, 1.0], [2.617383, 3.8144]]], [[[-2.096, 0.099, 1.34, 1.141, 0.3, 0.02, 0.03333333333333333, 0.3, 0.5], [1.131399, 0.711]], [[-2.365, 0.109, 1.976, 0.0, 0.3, 0.02, 0.03333333333333333, 0.8, 1.0], [2.154352, 1.892]], [[-2.015, 0.144, 1.236, 0.634, 0.2, 0.02, 0.03333333333333333, 0.8, 1.0], [1.939572, 1.612]], [[-0.664, 0.157, 0.422, 1.429, 0.1, 0.02, 0.03333333333333333, 0.0, 0.5], [0.580767, 0.411]], [[-2.77, 0.145, 0.0, 0.0, 0.3, 0.005, 0.016666666666666666, 0.8, 0.5], [0.0, -2.77]], [[-3.183, 0.12, 0.0, 0.0, 0.2, 0.005, 0.016666666666666666, 0.0, 0.5], [0.0, -3.183]], [[0.78, 0.12, 1.491, 1.397, 0.2, 0.01, 0.016666666666666666, 0.0, 0.5], [0.186981, 1.32]], [[1.967, 0.183, 0.871, 0.109, 0.1, 0.01, 0.016666666666666666, 0.3, 0.5], [0.0, 1.967]]]]
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[0.0, -4.177][0.0, -4.177]Passed
case 1[1.4826, 4.026789][0.475921, 2.25]Failed
case 2[2.852875, -1.866666][5.427586, 0.0]Failed
case 3[2.401117, 0.287649][2.723216, 0.5901]Failed
case 4[0.109032, 0.546597][0.870056, 0.816]Failed
case 5[0.0, 1.262][0.0, 1.262]Passed
case 6[2.368575, 3.209334][1.074074, 1.287]Failed
case 7[0.0, -1.72][0.0, -1.72]Passed

SHA-256 / 272d9ace52c6739b2acb3559730cb946c334bedd2955d842f61782f84fe1a9cb

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(vn, depth, ima, imb, beta, slop, dt, e, e_thresh):
    w = ima + imb
    if w == 0:
        return [0.0, round(vn, 6)]
    pen = depth - slop
    bias = beta / dt * pen if pen > 0 else 0.0
    bounce = -e * vn if vn < -e_thresh else 0.0
    target = max(bias, bounce)
    lam = (target - vn) / max(ima, imb)
    if lam < 0:
        lam = 0.0
    return [round(lam, 6), round(vn + lam * w, 6)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[-4.177, 0.112, 0.0, 0.0, 0.1, 0.005, 0.016666666666666666, 0.3, 1.0], [0.0, -4.177]], [[1.41, 0.135, 0.151, 1.614, 0.3, 0.01, 0.016666666666666666, 0.0, 0.5], [0.475921, 2.25]], [[-3.935, -0.001, 0.725, 0.0, 0.2, 0.01, 0.016666666666666666, 0.0, 1.0], [5.427586, 0.0]], [[-1.967, 0.032, 0.824, 0.115, 0.1, 0.01, 0.016666666666666666, 0.3, 1.0], [2.723216, 0.5901]], [[0.508, 0.146, 0.0, 0.354, 0.2, 0.01, 0.03333333333333333, 0.8, 1.0], [0.870056, 0.816]], [[1.262, 0.19, 1.184, 1.117, 0.1, 0.005, 0.03333333333333333, 0.8, 1.0], [0.0, 1.262]], [[-0.308, 0.163, 0.198, 1.287, 0.3, 0.02, 0.03333333333333333, 0.8, 0.5], [1.074074, 1.287]], [[-1.72, 0.144, 0.0, 0.0, 0.2, 0.01, 0.016666666666666666, 0.3, 1.0], [0.0, -1.72]]], [[[0.591, 0.063, 0.548, 0.151, 0.1, 0.005, 0.016666666666666666, 0.0, 1.0], [0.0, 0.591]], [[-1.309, 0.06, 0.588, 0.3, 0.3, 0.005, 0.016666666666666666, 0.8, 0.5], [2.653378, 1.0472]], [[-1.029, 0.163, 0.695, 0.376, 0.3, 0.01, 0.016666666666666666, 0.3, 1.0], [3.532213, 2.754]], [[0.387, 0.038, 1.153, 0.0, 0.1, 0.01, 0.016666666666666666, 0.8, 0.5], [0.0, 0.387]], [[0.579, 0.19, 1.545, 1.81, 0.2, 0.02, 0.03333333333333333, 0.8, 0.5], [0.131446, 1.02]], [[-0.08, 0.034, 0.0, 1.484, 0.3, 0.005, 0.03333333333333333, 0.0, 0.5], [0.229784, 0.261]], [[-2.861, 0.183, 0.0, 1.604, 0.2, 0.02, 0.03333333333333333, 0.0, 1.0], [2.393392, 0.978]], [[1.423, 0.017, 0.0, 0.597, 0.2, 0.005, 0.03333333333333333, 0.3, 1.0], [0.0, 1.423]]], [[[-3.757, 0.012, 1.496, 1.54, 0.3, 0.01, 0.03333333333333333, 0.3, 0.5], [1.608729, 1.1271]], [[-3.134, 0.061, 0.847, 1.706, 0.3, 0.005, 0.03333333333333333, 0.3, 1.0], [1.595848, 0.9402]], [[-2.036, -0.001, 1.318, 0.182, 0.3, 0.01, 0.03333333333333333, 0.3, 0.5], [1.764533, 0.6108]], [[-0.903, 0.047, 0.0, 0.0, 0.1, 0.02, 0.03333333333333333, 0.0, 1.0], [0.0, -0.903]], [[-1.453, 0.06, 0.0, 0.0, 0.2, 0.01, 0.016666666666666666, 0.0, 0.5], [0.0, -1.453]], [[-1.057, 0.121, 1.527, 0.0, 0.1, 0.01, 0.03333333333333333, 0.8, 0.5], [1.245972, 0.8456]], [[-3.223, 0.016, 0.0, 0.775, 0.3, 0.02, 0.03333333333333333, 0.0, 0.5], [4.15871, 0.0]], [[0.409, 0.029, 0.104, 0.0, 0.1, 0.01, 0.016666666666666666, 0.3, 1.0], [0.0, 0.409]]], [[[1.004, 0.112, 0.796, 0.0, 0.1, 0.01, 0.03333333333333333, 0.8, 1.0], [0.0, 1.004]], [[-4.647, 0.009, 0.0, 0.0, 0.3, 0.005, 0.03333333333333333, 0.3, 1.0], [0.0, -4.647]], [[-4.992, 0.109, 1.939, 1.518, 0.1, 0.005, 0.03333333333333333, 0.0, 0.5], [1.534278, 0.312]], [[0.08, 0.097, 0.146, 0.0, 0.3, 0.005, 0.016666666666666666, 0.8, 0.5], [10.794521, 1.656]], [[-1.618, 0.083, 0.255, 0.217, 0.3, 0.01, 0.03333333333333333, 0.8, 0.5], [6.170339, 1.2944]], [[-4.633, 0.14, 0.0, 0.0, 0.1, 0.02, 0.016666666666666666, 0.0, 1.0], [0.0, -4.633]], [[-4.858, 0.174, 1.743, 0.441, 0.3, 0.005, 0.03333333333333333, 0.0, 1.0], [2.920788, 1.521]], [[-4.768, 0.04, 1.908, 1.371, 0.3, 0.01, 0.016666666666666666, 0.8, 1.0], [2.617383, 3.8144]]], [[[-2.096, 0.099, 1.34, 1.141, 0.3, 0.02, 0.03333333333333333, 0.3, 0.5], [1.131399, 0.711]], [[-2.365, 0.109, 1.976, 0.0, 0.3, 0.02, 0.03333333333333333, 0.8, 1.0], [2.154352, 1.892]], [[-2.015, 0.144, 1.236, 0.634, 0.2, 0.02, 0.03333333333333333, 0.8, 1.0], [1.939572, 1.612]], [[-0.664, 0.157, 0.422, 1.429, 0.1, 0.02, 0.03333333333333333, 0.0, 0.5], [0.580767, 0.411]], [[-2.77, 0.145, 0.0, 0.0, 0.3, 0.005, 0.016666666666666666, 0.8, 0.5], [0.0, -2.77]], [[-3.183, 0.12, 0.0, 0.0, 0.2, 0.005, 0.016666666666666666, 0.0, 0.5], [0.0, -3.183]], [[0.78, 0.12, 1.491, 1.397, 0.2, 0.01, 0.016666666666666666, 0.0, 0.5], [0.186981, 1.32]], [[1.967, 0.183, 0.871, 0.109, 0.1, 0.01, 0.016666666666666666, 0.3, 0.5], [0.0, 1.967]]]]
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[0.0, -4.177][0.0, -4.177]Passed
case 1[0.520446, 2.328587][0.475921, 2.25]Failed
case 2[5.427586, 0.0][5.427586, 0.0]Passed
case 3[3.103277, 0.946977][2.723216, 0.5901]Failed
case 4[0.870056, 0.816][0.870056, 0.816]Passed
case 5[0.0, 1.262][0.0, 1.262]Passed
case 6[1.239316, 1.532385][1.074074, 1.287]Failed
case 7[0.0, -1.72][0.0, -1.72]Passed

SHA-256 / cd8731eda3df48aca54c647b98116be832ddb5872542708c23fb7d564821d7be

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(vn, depth, ima, imb, beta, slop, dt, e, e_thresh):
    w = ima + imb
    if w == 0:
        return [0.0, round(vn, 6)]
    pen = depth - slop
    bias = beta / dt * pen if pen > 0 else 0.0
    bounce = -e * vn if vn < -e_thresh else 0.0
    target = max(bias, bounce)
    lam = (target - vn) / w
    if lam < 0:
        lam = 0.0
    return [round(lam, 6), round(vn + lam * w, 6)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[-4.177, 0.112, 0.0, 0.0, 0.1, 0.005, 0.016666666666666666, 0.3, 1.0], [0.0, -4.177]], [[1.41, 0.135, 0.151, 1.614, 0.3, 0.01, 0.016666666666666666, 0.0, 0.5], [0.475921, 2.25]], [[-3.935, -0.001, 0.725, 0.0, 0.2, 0.01, 0.016666666666666666, 0.0, 1.0], [5.427586, 0.0]], [[-1.967, 0.032, 0.824, 0.115, 0.1, 0.01, 0.016666666666666666, 0.3, 1.0], [2.723216, 0.5901]], [[0.508, 0.146, 0.0, 0.354, 0.2, 0.01, 0.03333333333333333, 0.8, 1.0], [0.870056, 0.816]], [[1.262, 0.19, 1.184, 1.117, 0.1, 0.005, 0.03333333333333333, 0.8, 1.0], [0.0, 1.262]], [[-0.308, 0.163, 0.198, 1.287, 0.3, 0.02, 0.03333333333333333, 0.8, 0.5], [1.074074, 1.287]], [[-1.72, 0.144, 0.0, 0.0, 0.2, 0.01, 0.016666666666666666, 0.3, 1.0], [0.0, -1.72]]], [[[0.591, 0.063, 0.548, 0.151, 0.1, 0.005, 0.016666666666666666, 0.0, 1.0], [0.0, 0.591]], [[-1.309, 0.06, 0.588, 0.3, 0.3, 0.005, 0.016666666666666666, 0.8, 0.5], [2.653378, 1.0472]], [[-1.029, 0.163, 0.695, 0.376, 0.3, 0.01, 0.016666666666666666, 0.3, 1.0], [3.532213, 2.754]], [[0.387, 0.038, 1.153, 0.0, 0.1, 0.01, 0.016666666666666666, 0.8, 0.5], [0.0, 0.387]], [[0.579, 0.19, 1.545, 1.81, 0.2, 0.02, 0.03333333333333333, 0.8, 0.5], [0.131446, 1.02]], [[-0.08, 0.034, 0.0, 1.484, 0.3, 0.005, 0.03333333333333333, 0.0, 0.5], [0.229784, 0.261]], [[-2.861, 0.183, 0.0, 1.604, 0.2, 0.02, 0.03333333333333333, 0.0, 1.0], [2.393392, 0.978]], [[1.423, 0.017, 0.0, 0.597, 0.2, 0.005, 0.03333333333333333, 0.3, 1.0], [0.0, 1.423]]], [[[-3.757, 0.012, 1.496, 1.54, 0.3, 0.01, 0.03333333333333333, 0.3, 0.5], [1.608729, 1.1271]], [[-3.134, 0.061, 0.847, 1.706, 0.3, 0.005, 0.03333333333333333, 0.3, 1.0], [1.595848, 0.9402]], [[-2.036, -0.001, 1.318, 0.182, 0.3, 0.01, 0.03333333333333333, 0.3, 0.5], [1.764533, 0.6108]], [[-0.903, 0.047, 0.0, 0.0, 0.1, 0.02, 0.03333333333333333, 0.0, 1.0], [0.0, -0.903]], [[-1.453, 0.06, 0.0, 0.0, 0.2, 0.01, 0.016666666666666666, 0.0, 0.5], [0.0, -1.453]], [[-1.057, 0.121, 1.527, 0.0, 0.1, 0.01, 0.03333333333333333, 0.8, 0.5], [1.245972, 0.8456]], [[-3.223, 0.016, 0.0, 0.775, 0.3, 0.02, 0.03333333333333333, 0.0, 0.5], [4.15871, 0.0]], [[0.409, 0.029, 0.104, 0.0, 0.1, 0.01, 0.016666666666666666, 0.3, 1.0], [0.0, 0.409]]], [[[1.004, 0.112, 0.796, 0.0, 0.1, 0.01, 0.03333333333333333, 0.8, 1.0], [0.0, 1.004]], [[-4.647, 0.009, 0.0, 0.0, 0.3, 0.005, 0.03333333333333333, 0.3, 1.0], [0.0, -4.647]], [[-4.992, 0.109, 1.939, 1.518, 0.1, 0.005, 0.03333333333333333, 0.0, 0.5], [1.534278, 0.312]], [[0.08, 0.097, 0.146, 0.0, 0.3, 0.005, 0.016666666666666666, 0.8, 0.5], [10.794521, 1.656]], [[-1.618, 0.083, 0.255, 0.217, 0.3, 0.01, 0.03333333333333333, 0.8, 0.5], [6.170339, 1.2944]], [[-4.633, 0.14, 0.0, 0.0, 0.1, 0.02, 0.016666666666666666, 0.0, 1.0], [0.0, -4.633]], [[-4.858, 0.174, 1.743, 0.441, 0.3, 0.005, 0.03333333333333333, 0.0, 1.0], [2.920788, 1.521]], [[-4.768, 0.04, 1.908, 1.371, 0.3, 0.01, 0.016666666666666666, 0.8, 1.0], [2.617383, 3.8144]]], [[[-2.096, 0.099, 1.34, 1.141, 0.3, 0.02, 0.03333333333333333, 0.3, 0.5], [1.131399, 0.711]], [[-2.365, 0.109, 1.976, 0.0, 0.3, 0.02, 0.03333333333333333, 0.8, 1.0], [2.154352, 1.892]], [[-2.015, 0.144, 1.236, 0.634, 0.2, 0.02, 0.03333333333333333, 0.8, 1.0], [1.939572, 1.612]], [[-0.664, 0.157, 0.422, 1.429, 0.1, 0.02, 0.03333333333333333, 0.0, 0.5], [0.580767, 0.411]], [[-2.77, 0.145, 0.0, 0.0, 0.3, 0.005, 0.016666666666666666, 0.8, 0.5], [0.0, -2.77]], [[-3.183, 0.12, 0.0, 0.0, 0.2, 0.005, 0.016666666666666666, 0.0, 0.5], [0.0, -3.183]], [[0.78, 0.12, 1.491, 1.397, 0.2, 0.01, 0.016666666666666666, 0.0, 0.5], [0.186981, 1.32]], [[1.967, 0.183, 0.871, 0.109, 0.1, 0.01, 0.016666666666666666, 0.3, 0.5], [0.0, 1.967]]]]
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[0.0, -4.177][0.0, -4.177]Passed
case 1[0.475921, 2.25][0.475921, 2.25]Passed
case 2[5.427586, 0.0][5.427586, 0.0]Passed
case 3[2.723216, 0.5901][2.723216, 0.5901]Passed
case 4[0.870056, 0.816][0.870056, 0.816]Passed
case 5[0.0, 1.262][0.0, 1.262]Passed
case 6[1.074074, 1.287][1.074074, 1.287]Passed
case 7[0.0, -1.72][0.0, -1.72]Passed

SHA-256 / 9dbd2c8c4563462591590d010b9ca3849f9b58ebbb1b94bb95997ad955a8112f

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

Case digest / 5a4e08fb62a72b72cf9b3ae2289823cc5a2e056edc00cda6b76c808b5f983c5d