FAILURE MAP
← Case archive

FA-87171 / Physics integrator stability / Open access

Integrated quaternion is never renormalized · case 01

Orientation magnitude grows each step and scales transformed geometry.

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

ROOT CAUSE

The unit-length projection after each step is missing.

VERIFIED REPAIR

Divide by the Euclidean norm every step.

Unsuccessful approach: Dividing by the squared norm does not produce a unit quaternion.

Case contract

solve(q, omega, dt, steps): orientation quaternion [w,x,y,z], world-frame angular velocity omega. Each step q += 0.5*dt*(0,omega) (x) q (Hamilton product, omega on the left), then renormalize to unit length. Return q with w>=0 (negate all components otherwise), 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(q, omega, dt, steps):
    def mul(a, b):
        aw, ax, ay, az = a
        bw, bx, by, bz = b
        return [aw * bw - ax * bx - ay * by - az * bz,
                aw * bx + ax * bw + ay * bz - az * by,
                aw * by - ax * bz + ay * bw + az * bx,
                aw * bz + ax * by - ay * bx + az * bw]
    w = [0.0, omega[0], omega[1], omega[2]]
    q = list(q)
    for _ in range(steps):
        d = mul(w, q)
        q = [q[i] + 0.5 * dt * d[i] for i in range(4)]
    if q[0] < 0:
        q = [-c for c in q]
    return [round(c, 6) for c in q]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[[-0.1116, -0.6859, -0.2807, 0.6621], [-1.367, -3.32, -3.869], 0.05, 1], [0.093483, 0.757592, 0.180891, -0.620156]], [[[0.1693, 0.5991, -0.3007, 0.7225], [-0.846, 0.203, 2.272], 0.1, 5], [0.11186, -0.653252, -0.222024, -0.71516]], [[[0.6563, -0.5379, 0.1174, 0.516], [0.015, -0.619, 1.039], 0.01, 5], [0.644583, -0.548412, 0.093024, 0.524503]], [[[0.5997, 0.4148, -0.4199, 0.5403], [-3.739, 3.361, 1.097], 0.05, 2], [0.696741, 0.402993, -0.185348, 0.563732]], [[[-0.598, -0.3686, -0.6674, 0.2471], [0.254, 3.454, 0.811], 0.1, 2], [0.348236, 0.225528, 0.861772, -0.291922]], [[[-0.0952, -0.5664, 0.6301, 0.5226], [-2.128, -1.292, -0.851], 0.1, 5], [0.063181, 0.434826, -0.89713, 0.045751]], [[[-0.0519, 0.3724, -0.6259, 0.6833], [-3.675, 2.343, 0.559], 0.1, 4], [0.391258, 0.612492, 0.044021, 0.685444]], [[[0.5438, 0.3302, -0.6582, 0.4024], [-2.872, -3.023, 2.126], 0.05, 4], [0.303775, 0.162656, -0.567546, 0.747767]]], [[[[-0.615, -0.0218, 0.3915, 0.6841], [-1.942, 2.597, 2.686], 0.1, 6], [0.848549, -0.424885, -0.051674, 0.311074]], [[[0.8268, -0.0559, 0.3935, 0.398], [-0.387, 0.922, 1.986], 0.1, 7], [0.220922, -0.271091, 0.534556, 0.769385]], [[[-0.0016, -0.616, -0.6804, -0.397], [3.345, 1.581, 1.376], 0.01, 8], [0.145089, -0.596259, -0.652903, -0.444007]], [[[0.0263, -0.6798, 0.6943, 0.2347], [-2.851, -1.309, 1.331], 0.01, 4], [0.000571, 0.704341, -0.687306, -0.177522]], [[[0.3798, 0.547, -0.2244, -0.7115], [3.095, -0.908, 3.375], 0.01, 7], [0.392314, 0.629546, -0.092392, -0.664248]], [[[-0.4028, 0.5372, 0.3775, -0.6377], [-2.487, -2.209, -0.784], 0.05, 1], [0.359741, -0.602665, -0.348298, 0.621346]], [[[0.6623, -0.6015, -0.0252, 0.4461], [1.478, -3.402, -2.007], 0.05, 6], [0.772394, -0.568265, -0.258655, -0.116536]], [[[-0.5078, 0.518, 0.6345, -0.2667], [-3.853, 1.735, 2.833], 0.1, 8], [0.503958, -0.266597, -0.338951, -0.748375]]], [[[[0.2553, 0.3766, -0.4571, -0.7642], [1.912, -1.512, -1.112], 0.1, 5], [0.320534, -0.557926, 0.208136, 0.736652]], [[[-0.3438, -0.8064, 0.2793, -0.3918], [0.487, -0.414, 0.563], 0.05, 6], [0.231973, 0.824132, -0.258947, 0.447149]], [[[-0.571, 0.1155, 0.5121, 0.6312], [2.085, -1.83, -1.285], 0.01, 1], [0.563386, -0.107047, -0.509932, -0.641176]], [[[-0.5469, -0.6064, -0.5509, 0.1724], [-3.255, -3.579, 1.694], 0.1, 5], [0.955808, -0.200037, -0.105114, 0.188061]], [[[-0.2619, -0.6055, 0.5056, -0.556], [1.718, -1.974, -2.105], 0.05, 7], [0.075157, 0.222316, -0.873701, 0.426115]], [[[-0.5755, -0.1729, 0.1896, -0.7765], [-1.564, 1.954, -3.317], 0.01, 5], [0.652658, 0.171677, -0.144528, 0.723655]], [[[0.2096, 0.287, 0.2469, -0.9015], [-2.616, 2.979, -3.201], 0.1, 7], [0.591276, 0.5223, 0.555698, 0.262288]], [[[-0.2338, 0.4828, -0.4189, -0.7326], [-3.705, 3.149, -0.943], 0.1, 5], [0.375548, -0.17857, -0.885262, -0.208297]]], [[[[0.1051, -0.3513, -0.8754, 0.315], [-3.413, -0.15, -1.074], 0.05, 1], [0.07998, -0.383418, -0.836137, 0.384017]], [[[0.5249, -0.2848, -0.7987, -0.0739], [-0.123, 1.363, 2.448], 0.01, 8], [0.57087, -0.211566, -0.793309, -0.002734]], [[[0.1401, -0.0998, 0.7197, 0.6726], [-3.242, -3.373, -3.717], 0.01, 11], [0.381235, -0.097044, 0.793491, 0.464343]], [[[0.5736, 0.5961, -0.0324, -0.5609], [-0.513, -1.203, 2.932], 0.01, 10], [0.661374, 0.612106, 0.006347, -0.43344]], [[[0.2307, 0.3931, 0.7631, -0.4581], [2.174, 2.113, 3.444], 0.05, 10], [0.080385, 0.450009, -0.879659, -0.131262]], [[[0.7871, -0.5898, 0.1277, -0.1277], [-2.159, -3.665, 2.669], 0.05, 1], [0.769445, -0.624203, 0.009262, -0.135053]], [[[0.2873, -0.6346, 0.6402, -0.324], [3.029, -0.324, 1.16], 0.1, 8], [0.817944, -0.105726, 0.220751, 0.520633]], [[[0.0973, -0.8318, 0.0918, 0.5388], [3.534, -0.597, -1.04], 0.1, 5], [0.817921, -0.477199, -0.178869, 0.267005]]], [[[[-0.5464, 0.5076, -0.6205, -0.2426], [-3.943, 2.274, 1.451], 0.05, 14], [0.835474, 0.474296, -0.246914, 0.126728]], [[[0.5273, 0.4224, -0.4746, 0.5641], [-2.08, 3.628, 3.896], 0.01, 13], [0.516939, 0.571342, -0.141768, 0.621485]], [[[-0.0187, -0.2899, 0.2867, 0.9129], [-0.8, 2.868, -3.73], 0.1, 5], [0.446521, 0.601922, 0.450869, 0.484794]], [[[-0.3686, 0.5299, -0.5118, -0.567], [2.775, -3.522, 1.081], 0.01, 1], [0.381782, -0.53737, 0.494424, 0.566586]], [[[0.1094, 0.2843, 0.727, 0.6154], [3.004, -3.908, 3.399], 0.05, 2], [0.099484, 0.04945, 0.631065, 0.767733]], [[[-0.4927, -0.5827, 0.6256, -0.1623], [-0.106, 0.433, 1.641], 0.01, 11], [0.494187, 0.637522, -0.557689, 0.195778]], [[[0.0332, -0.1691, -0.7704, -0.6138], [2.17, 2.479, 1.5], 0.1, 9], [0.881211, -0.074251, 0.351735, -0.30698]], [[[0.1785, -0.1228, -0.7653, 0.6061], [2.105, 0.281, 2.09], 0.01, 8], [0.145584, -0.036317, -0.819027, 0.553788]]]]
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.094297, 0.764191, 0.182466, -0.625558][0.093483, 0.757592, 0.180891, -0.620156]Failed
case 1[0.116045, -0.67769, -0.23033, -0.741914][0.11186, -0.653252, -0.222024, -0.71516]Failed
case 2[0.644676, -0.548491, 0.093037, 0.524578][0.644583, -0.548412, 0.093024, 0.524503]Failed
case 3[0.708251, 0.40965, -0.18841, 0.573045][0.696741, 0.402993, -0.185348, 0.563732]Failed
case 4[0.359242, 0.232656, 0.889009, -0.301149][0.348236, 0.225528, 0.861772, -0.291922]Failed
case 5[0.06595, 0.453884, -0.93645, 0.047756][0.063181, 0.434826, -0.89713, 0.045751]Failed
case 6[0.429946, 0.673056, 0.048374, 0.753222][0.391258, 0.612492, 0.044021, 0.685444]Failed
case 7[0.312135, 0.167132, -0.583166, 0.768347][0.303775, 0.162656, -0.567546, 0.747767]Failed

SHA-256 / f77f9d24ab1d5a293eead104911dcaa4f11226d3267d5c5cdb174793b8bf4617

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(q, omega, dt, steps):
    def mul(a, b):
        aw, ax, ay, az = a
        bw, bx, by, bz = b
        return [aw * bw - ax * bx - ay * by - az * bz,
                aw * bx + ax * bw + ay * bz - az * by,
                aw * by - ax * bz + ay * bw + az * bx,
                aw * bz + ax * by - ay * bx + az * bw]
    w = [0.0, omega[0], omega[1], omega[2]]
    q = list(q)
    for _ in range(steps):
        d = mul(w, q)
        q = [q[i] + 0.5 * dt * d[i] for i in range(4)]
        n = sum(c * c for c in q)
        q = [c / n for c in q]
    if q[0] < 0:
        q = [-c for c in q]
    return [round(c, 6) for c in q]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[[-0.1116, -0.6859, -0.2807, 0.6621], [-1.367, -3.32, -3.869], 0.05, 1], [0.093483, 0.757592, 0.180891, -0.620156]], [[[0.1693, 0.5991, -0.3007, 0.7225], [-0.846, 0.203, 2.272], 0.1, 5], [0.11186, -0.653252, -0.222024, -0.71516]], [[[0.6563, -0.5379, 0.1174, 0.516], [0.015, -0.619, 1.039], 0.01, 5], [0.644583, -0.548412, 0.093024, 0.524503]], [[[0.5997, 0.4148, -0.4199, 0.5403], [-3.739, 3.361, 1.097], 0.05, 2], [0.696741, 0.402993, -0.185348, 0.563732]], [[[-0.598, -0.3686, -0.6674, 0.2471], [0.254, 3.454, 0.811], 0.1, 2], [0.348236, 0.225528, 0.861772, -0.291922]], [[[-0.0952, -0.5664, 0.6301, 0.5226], [-2.128, -1.292, -0.851], 0.1, 5], [0.063181, 0.434826, -0.89713, 0.045751]], [[[-0.0519, 0.3724, -0.6259, 0.6833], [-3.675, 2.343, 0.559], 0.1, 4], [0.391258, 0.612492, 0.044021, 0.685444]], [[[0.5438, 0.3302, -0.6582, 0.4024], [-2.872, -3.023, 2.126], 0.05, 4], [0.303775, 0.162656, -0.567546, 0.747767]]], [[[[-0.615, -0.0218, 0.3915, 0.6841], [-1.942, 2.597, 2.686], 0.1, 6], [0.848549, -0.424885, -0.051674, 0.311074]], [[[0.8268, -0.0559, 0.3935, 0.398], [-0.387, 0.922, 1.986], 0.1, 7], [0.220922, -0.271091, 0.534556, 0.769385]], [[[-0.0016, -0.616, -0.6804, -0.397], [3.345, 1.581, 1.376], 0.01, 8], [0.145089, -0.596259, -0.652903, -0.444007]], [[[0.0263, -0.6798, 0.6943, 0.2347], [-2.851, -1.309, 1.331], 0.01, 4], [0.000571, 0.704341, -0.687306, -0.177522]], [[[0.3798, 0.547, -0.2244, -0.7115], [3.095, -0.908, 3.375], 0.01, 7], [0.392314, 0.629546, -0.092392, -0.664248]], [[[-0.4028, 0.5372, 0.3775, -0.6377], [-2.487, -2.209, -0.784], 0.05, 1], [0.359741, -0.602665, -0.348298, 0.621346]], [[[0.6623, -0.6015, -0.0252, 0.4461], [1.478, -3.402, -2.007], 0.05, 6], [0.772394, -0.568265, -0.258655, -0.116536]], [[[-0.5078, 0.518, 0.6345, -0.2667], [-3.853, 1.735, 2.833], 0.1, 8], [0.503958, -0.266597, -0.338951, -0.748375]]], [[[[0.2553, 0.3766, -0.4571, -0.7642], [1.912, -1.512, -1.112], 0.1, 5], [0.320534, -0.557926, 0.208136, 0.736652]], [[[-0.3438, -0.8064, 0.2793, -0.3918], [0.487, -0.414, 0.563], 0.05, 6], [0.231973, 0.824132, -0.258947, 0.447149]], [[[-0.571, 0.1155, 0.5121, 0.6312], [2.085, -1.83, -1.285], 0.01, 1], [0.563386, -0.107047, -0.509932, -0.641176]], [[[-0.5469, -0.6064, -0.5509, 0.1724], [-3.255, -3.579, 1.694], 0.1, 5], [0.955808, -0.200037, -0.105114, 0.188061]], [[[-0.2619, -0.6055, 0.5056, -0.556], [1.718, -1.974, -2.105], 0.05, 7], [0.075157, 0.222316, -0.873701, 0.426115]], [[[-0.5755, -0.1729, 0.1896, -0.7765], [-1.564, 1.954, -3.317], 0.01, 5], [0.652658, 0.171677, -0.144528, 0.723655]], [[[0.2096, 0.287, 0.2469, -0.9015], [-2.616, 2.979, -3.201], 0.1, 7], [0.591276, 0.5223, 0.555698, 0.262288]], [[[-0.2338, 0.4828, -0.4189, -0.7326], [-3.705, 3.149, -0.943], 0.1, 5], [0.375548, -0.17857, -0.885262, -0.208297]]], [[[[0.1051, -0.3513, -0.8754, 0.315], [-3.413, -0.15, -1.074], 0.05, 1], [0.07998, -0.383418, -0.836137, 0.384017]], [[[0.5249, -0.2848, -0.7987, -0.0739], [-0.123, 1.363, 2.448], 0.01, 8], [0.57087, -0.211566, -0.793309, -0.002734]], [[[0.1401, -0.0998, 0.7197, 0.6726], [-3.242, -3.373, -3.717], 0.01, 11], [0.381235, -0.097044, 0.793491, 0.464343]], [[[0.5736, 0.5961, -0.0324, -0.5609], [-0.513, -1.203, 2.932], 0.01, 10], [0.661374, 0.612106, 0.006347, -0.43344]], [[[0.2307, 0.3931, 0.7631, -0.4581], [2.174, 2.113, 3.444], 0.05, 10], [0.080385, 0.450009, -0.879659, -0.131262]], [[[0.7871, -0.5898, 0.1277, -0.1277], [-2.159, -3.665, 2.669], 0.05, 1], [0.769445, -0.624203, 0.009262, -0.135053]], [[[0.2873, -0.6346, 0.6402, -0.324], [3.029, -0.324, 1.16], 0.1, 8], [0.817944, -0.105726, 0.220751, 0.520633]], [[[0.0973, -0.8318, 0.0918, 0.5388], [3.534, -0.597, -1.04], 0.1, 5], [0.817921, -0.477199, -0.178869, 0.267005]]], [[[[-0.5464, 0.5076, -0.6205, -0.2426], [-3.943, 2.274, 1.451], 0.05, 14], [0.835474, 0.474296, -0.246914, 0.126728]], [[[0.5273, 0.4224, -0.4746, 0.5641], [-2.08, 3.628, 3.896], 0.01, 13], [0.516939, 0.571342, -0.141768, 0.621485]], [[[-0.0187, -0.2899, 0.2867, 0.9129], [-0.8, 2.868, -3.73], 0.1, 5], [0.446521, 0.601922, 0.450869, 0.484794]], [[[-0.3686, 0.5299, -0.5118, -0.567], [2.775, -3.522, 1.081], 0.01, 1], [0.381782, -0.53737, 0.494424, 0.566586]], [[[0.1094, 0.2843, 0.727, 0.6154], [3.004, -3.908, 3.399], 0.05, 2], [0.099484, 0.04945, 0.631065, 0.767733]], [[[-0.4927, -0.5827, 0.6256, -0.1623], [-0.106, 0.433, 1.641], 0.01, 11], [0.494187, 0.637522, -0.557689, 0.195778]], [[[0.0332, -0.1691, -0.7704, -0.6138], [2.17, 2.479, 1.5], 0.1, 9], [0.881211, -0.074251, 0.351735, -0.30698]], [[[0.1785, -0.1228, -0.7653, 0.6061], [2.105, 0.281, 2.09], 0.01, 8], [0.145584, -0.036317, -0.819027, 0.553788]]]]
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.092676, 0.75105, 0.179329, -0.614801][0.093483, 0.757592, 0.180891, -0.620156]Failed
case 1[0.111041, -0.648469, -0.220399, -0.709923][0.11186, -0.653252, -0.222024, -0.71516]Failed
case 2[0.644538, -0.548373, 0.093017, 0.524466][0.644583, -0.548412, 0.093024, 0.524503]Failed
case 3[0.69672, 0.402981, -0.185343, 0.563715][0.696741, 0.402993, -0.185348, 0.563732]Failed
case 4[0.348227, 0.225522, 0.861751, -0.291915][0.348236, 0.225528, 0.861772, -0.291922]Failed
case 5[0.062641, 0.43111, -0.889463, 0.04536][0.063181, 0.434826, -0.89713, 0.045751]Failed
case 6[0.391263, 0.612499, 0.044022, 0.685453][0.391258, 0.612492, 0.044021, 0.685444]Failed
case 7[0.30376, 0.162648, -0.567519, 0.747731][0.303775, 0.162656, -0.567546, 0.747767]Failed

SHA-256 / bb6c5fa88826dfd4277d59e9c3fa27d5a97fbebc3bb01a77aa451c68cc1a8f28

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(q, omega, dt, steps):
    def mul(a, b):
        aw, ax, ay, az = a
        bw, bx, by, bz = b
        return [aw * bw - ax * bx - ay * by - az * bz,
                aw * bx + ax * bw + ay * bz - az * by,
                aw * by - ax * bz + ay * bw + az * bx,
                aw * bz + ax * by - ay * bx + az * bw]
    w = [0.0, omega[0], omega[1], omega[2]]
    q = list(q)
    for _ in range(steps):
        d = mul(w, q)
        q = [q[i] + 0.5 * dt * d[i] for i in range(4)]
        n = math.sqrt(sum(c * c for c in q))
        q = [c / n for c in q]
    if q[0] < 0:
        q = [-c for c in q]
    return [round(c, 6) for c in q]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[[-0.1116, -0.6859, -0.2807, 0.6621], [-1.367, -3.32, -3.869], 0.05, 1], [0.093483, 0.757592, 0.180891, -0.620156]], [[[0.1693, 0.5991, -0.3007, 0.7225], [-0.846, 0.203, 2.272], 0.1, 5], [0.11186, -0.653252, -0.222024, -0.71516]], [[[0.6563, -0.5379, 0.1174, 0.516], [0.015, -0.619, 1.039], 0.01, 5], [0.644583, -0.548412, 0.093024, 0.524503]], [[[0.5997, 0.4148, -0.4199, 0.5403], [-3.739, 3.361, 1.097], 0.05, 2], [0.696741, 0.402993, -0.185348, 0.563732]], [[[-0.598, -0.3686, -0.6674, 0.2471], [0.254, 3.454, 0.811], 0.1, 2], [0.348236, 0.225528, 0.861772, -0.291922]], [[[-0.0952, -0.5664, 0.6301, 0.5226], [-2.128, -1.292, -0.851], 0.1, 5], [0.063181, 0.434826, -0.89713, 0.045751]], [[[-0.0519, 0.3724, -0.6259, 0.6833], [-3.675, 2.343, 0.559], 0.1, 4], [0.391258, 0.612492, 0.044021, 0.685444]], [[[0.5438, 0.3302, -0.6582, 0.4024], [-2.872, -3.023, 2.126], 0.05, 4], [0.303775, 0.162656, -0.567546, 0.747767]]], [[[[-0.615, -0.0218, 0.3915, 0.6841], [-1.942, 2.597, 2.686], 0.1, 6], [0.848549, -0.424885, -0.051674, 0.311074]], [[[0.8268, -0.0559, 0.3935, 0.398], [-0.387, 0.922, 1.986], 0.1, 7], [0.220922, -0.271091, 0.534556, 0.769385]], [[[-0.0016, -0.616, -0.6804, -0.397], [3.345, 1.581, 1.376], 0.01, 8], [0.145089, -0.596259, -0.652903, -0.444007]], [[[0.0263, -0.6798, 0.6943, 0.2347], [-2.851, -1.309, 1.331], 0.01, 4], [0.000571, 0.704341, -0.687306, -0.177522]], [[[0.3798, 0.547, -0.2244, -0.7115], [3.095, -0.908, 3.375], 0.01, 7], [0.392314, 0.629546, -0.092392, -0.664248]], [[[-0.4028, 0.5372, 0.3775, -0.6377], [-2.487, -2.209, -0.784], 0.05, 1], [0.359741, -0.602665, -0.348298, 0.621346]], [[[0.6623, -0.6015, -0.0252, 0.4461], [1.478, -3.402, -2.007], 0.05, 6], [0.772394, -0.568265, -0.258655, -0.116536]], [[[-0.5078, 0.518, 0.6345, -0.2667], [-3.853, 1.735, 2.833], 0.1, 8], [0.503958, -0.266597, -0.338951, -0.748375]]], [[[[0.2553, 0.3766, -0.4571, -0.7642], [1.912, -1.512, -1.112], 0.1, 5], [0.320534, -0.557926, 0.208136, 0.736652]], [[[-0.3438, -0.8064, 0.2793, -0.3918], [0.487, -0.414, 0.563], 0.05, 6], [0.231973, 0.824132, -0.258947, 0.447149]], [[[-0.571, 0.1155, 0.5121, 0.6312], [2.085, -1.83, -1.285], 0.01, 1], [0.563386, -0.107047, -0.509932, -0.641176]], [[[-0.5469, -0.6064, -0.5509, 0.1724], [-3.255, -3.579, 1.694], 0.1, 5], [0.955808, -0.200037, -0.105114, 0.188061]], [[[-0.2619, -0.6055, 0.5056, -0.556], [1.718, -1.974, -2.105], 0.05, 7], [0.075157, 0.222316, -0.873701, 0.426115]], [[[-0.5755, -0.1729, 0.1896, -0.7765], [-1.564, 1.954, -3.317], 0.01, 5], [0.652658, 0.171677, -0.144528, 0.723655]], [[[0.2096, 0.287, 0.2469, -0.9015], [-2.616, 2.979, -3.201], 0.1, 7], [0.591276, 0.5223, 0.555698, 0.262288]], [[[-0.2338, 0.4828, -0.4189, -0.7326], [-3.705, 3.149, -0.943], 0.1, 5], [0.375548, -0.17857, -0.885262, -0.208297]]], [[[[0.1051, -0.3513, -0.8754, 0.315], [-3.413, -0.15, -1.074], 0.05, 1], [0.07998, -0.383418, -0.836137, 0.384017]], [[[0.5249, -0.2848, -0.7987, -0.0739], [-0.123, 1.363, 2.448], 0.01, 8], [0.57087, -0.211566, -0.793309, -0.002734]], [[[0.1401, -0.0998, 0.7197, 0.6726], [-3.242, -3.373, -3.717], 0.01, 11], [0.381235, -0.097044, 0.793491, 0.464343]], [[[0.5736, 0.5961, -0.0324, -0.5609], [-0.513, -1.203, 2.932], 0.01, 10], [0.661374, 0.612106, 0.006347, -0.43344]], [[[0.2307, 0.3931, 0.7631, -0.4581], [2.174, 2.113, 3.444], 0.05, 10], [0.080385, 0.450009, -0.879659, -0.131262]], [[[0.7871, -0.5898, 0.1277, -0.1277], [-2.159, -3.665, 2.669], 0.05, 1], [0.769445, -0.624203, 0.009262, -0.135053]], [[[0.2873, -0.6346, 0.6402, -0.324], [3.029, -0.324, 1.16], 0.1, 8], [0.817944, -0.105726, 0.220751, 0.520633]], [[[0.0973, -0.8318, 0.0918, 0.5388], [3.534, -0.597, -1.04], 0.1, 5], [0.817921, -0.477199, -0.178869, 0.267005]]], [[[[-0.5464, 0.5076, -0.6205, -0.2426], [-3.943, 2.274, 1.451], 0.05, 14], [0.835474, 0.474296, -0.246914, 0.126728]], [[[0.5273, 0.4224, -0.4746, 0.5641], [-2.08, 3.628, 3.896], 0.01, 13], [0.516939, 0.571342, -0.141768, 0.621485]], [[[-0.0187, -0.2899, 0.2867, 0.9129], [-0.8, 2.868, -3.73], 0.1, 5], [0.446521, 0.601922, 0.450869, 0.484794]], [[[-0.3686, 0.5299, -0.5118, -0.567], [2.775, -3.522, 1.081], 0.01, 1], [0.381782, -0.53737, 0.494424, 0.566586]], [[[0.1094, 0.2843, 0.727, 0.6154], [3.004, -3.908, 3.399], 0.05, 2], [0.099484, 0.04945, 0.631065, 0.767733]], [[[-0.4927, -0.5827, 0.6256, -0.1623], [-0.106, 0.433, 1.641], 0.01, 11], [0.494187, 0.637522, -0.557689, 0.195778]], [[[0.0332, -0.1691, -0.7704, -0.6138], [2.17, 2.479, 1.5], 0.1, 9], [0.881211, -0.074251, 0.351735, -0.30698]], [[[0.1785, -0.1228, -0.7653, 0.6061], [2.105, 0.281, 2.09], 0.01, 8], [0.145584, -0.036317, -0.819027, 0.553788]]]]
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.093483, 0.757592, 0.180891, -0.620156][0.093483, 0.757592, 0.180891, -0.620156]Passed
case 1[0.11186, -0.653252, -0.222024, -0.71516][0.11186, -0.653252, -0.222024, -0.71516]Passed
case 2[0.644583, -0.548412, 0.093024, 0.524503][0.644583, -0.548412, 0.093024, 0.524503]Passed
case 3[0.696741, 0.402993, -0.185348, 0.563732][0.696741, 0.402993, -0.185348, 0.563732]Passed
case 4[0.348236, 0.225528, 0.861772, -0.291922][0.348236, 0.225528, 0.861772, -0.291922]Passed
case 5[0.063181, 0.434826, -0.89713, 0.045751][0.063181, 0.434826, -0.89713, 0.045751]Passed
case 6[0.391258, 0.612492, 0.044021, 0.685444][0.391258, 0.612492, 0.044021, 0.685444]Passed
case 7[0.303775, 0.162656, -0.567546, 0.747767][0.303775, 0.162656, -0.567546, 0.747767]Passed

SHA-256 / 7e02e5faf1103f93a3d5e9df9b042a9bae84aee8e6c43000a547e57f7a2be15a

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

Case digest / 064e071c6b5c361d8f579767268f509cd4d7a603f61baecb49b129e927892a8b