FAILURE MAP
← Case archive

FA-87131 / Physics integrator stability / Open access

Variable-step Verlet uses h squared for the acceleration term · case 01

Uneven steps inject spurious forces.

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

ROOT CAUSE

The acceleration is scaled by h^2 instead of h*(h+h_prev)/2.

VERIFIED REPAIR

Use the averaged step product h*(h+h_prev)/2.

Unsuccessful approach: Using h*h_prev is still not the time-corrected form.

Case contract

solve(x0, v0, w2, g, dts): position Verlet with variable steps, acceleration -w2*x+g. First step is Taylor x1=x0+v0*h0+0.5*a(x0)*h0^2; then x_{n+1}=x_n+(x_n-x_{n-1})*(h_n/h_{n-1})+a(x_n)*h_n*(h_n+h_{n-1})/2. Velocity estimate is (x_n-x_{n-1})/h_last. Empty dts returns the initial state. Return [x, v] rounded.

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(x0, v0, w2, g, dts):
    def acc(p):
        return -w2 * p + g
    if not dts:
        return [round(x0, 6), round(v0, 6)]
    prev = x0
    x = x0 + v0 * dts[0] + 0.5 * acc(x0) * dts[0] * dts[0]
    for i in range(1, len(dts)):
        h, hp = dts[i], dts[i - 1]
        nxt = x + (x - prev) * (h / hp) + acc(x) * h * h
        prev, x = x, nxt
    v = (x - prev) / dts[-1]
    return [round(x, 6), round(v, 6)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[-1.118, 1.653, 18.431, 0.0, [0.03, 0.03]], [-0.982706, 2.547717]], [[1.93, 0.372, 11.854, -9.81, [0.01, 0.01, 0.01]], [1.926444, -0.445559]], [[-0.532, -1.331, 9.198, 2.0, [0.03, 0.05]], [-0.615744, -0.938317]], [[-0.112, 0.567, 15.803, 2.0, [0.05, 0.01, 0.01, 0.01, 0.01]], [-0.046765, 0.848706]], [[0.002, 0.745, 4.672, 0.0, [0.03, 0.01, 0.03, 0.05]], [0.090437, 0.729532]], [[-1.559, 0.132, 13.212, 0.0, [0.05, 0.05, 0.02, 0.03, 0.01, 0.01]], [-1.249546, 3.301322]], [[-1.571, -1.847, 12.561, 0.0, [0.05, 0.05]], [-1.654908, -0.324492]], [[-1.514, 1.013, 16.587, -9.81, [0.05, 0.03, 0.02]], [-1.339568, 2.290613]]], [[[1.693, 1.184, 10.982, -9.81, [0.02, 0.03, 0.05, 0.05]], [1.550068, -2.368135]], [[-0.751, -1.653, 15.366, -9.81, [0.01, 0.05, 0.01, 0.03, 0.02, 0.03, 0.01]], [-0.977779, -1.105082]], [[1.862, 1.422, 6.208, 2.0, [0.01, 0.03, 0.03, 0.01, 0.01]], [1.950431, 0.584063]], [[0.454, 0.048, 11.925, 0.0, [0.01, 0.01, 0.01]], [0.453003, -0.087359]], [[-1.613, -0.622, 8.807, -9.81, [0.02, 0.03, 0.01, 0.05, 0.03]], [-1.655241, -0.043343]], [[0.644, -0.151, 13.871, -9.81, [0.02, 0.02, 0.01, 0.01, 0.05, 0.02, 0.03]], [0.387894, -2.717601]], [[-0.524, -1.843, 1.225, 0.0, [0.05, 0.02, 0.03, 0.01]], [-0.722411, -1.763355]], [[1.972, 1.228, 18.377, 2.0, [0.01, 0.03]], [1.993612, 0.36813]]], [[[1.558, 1.408, 12.285, 2.0, [0.02, 0.05, 0.03]], [1.611423, -0.087072]], [[-1.587, -0.211, 17.367, 2.0, [0.03, 0.01, 0.02, 0.02]], [-1.509843, 1.83789]], [[-1.478, -0.428, 14.024, 2.0, [0.01, 0.02, 0.01]], [-1.476913, 0.36867]], [[1.36, 0.701, 17.189, 2.0, [0.03, 0.05, 0.01, 0.03, 0.05, 0.01, 0.03]], [1.046693, -3.241676]], [[-0.045, -0.271, 10.763, 2.0, [0.02, 0.03]], [-0.055405, -0.182724]], [[0.106, -1.937, 2.608, 0.0, [0.03, 0.01, 0.03, 0.05, 0.01, 0.05, 0.05, 0.02]], [-0.374085, -1.858207]], [[-1.655, 0.554, 15.555, -9.81, [0.03, 0.02, 0.01, 0.01, 0.03, 0.01]], [-1.500918, 2.131832]], [[0.68, 1.896, 12.013, -9.81, [0.03, 0.03, 0.03]], [0.775896, 0.500859]]], [[[-0.942, 0.774, 3.875, 0.0, [0.02, 0.02, 0.03, 0.01, 0.02, 0.03]], [-0.811751, 1.170885]], [[1.678, -1.604, 6.016, 2.0, [0.02, 0.03, 0.05, 0.02, 0.05, 0.05, 0.02]], [1.087528, -3.119149]], [[-0.516, 0.344, 13.779, -9.81, [0.01, 0.03, 0.01, 0.01, 0.03, 0.05]], [-0.495793, 0.012391]], [[-0.434, -1.688, 15.899, 0.0, [0.03, 0.05, 0.01, 0.02]], [-0.573341, -0.885589]], [[-0.101, -1.02, 19.226, 2.0, [0.05, 0.01]], [-0.154839, -0.776626]], [[-1.698, 0.325, 6.546, -9.81, [0.02, 0.02]], [-1.683974, 0.363268]], [[0.712, -1.32, 18.303, -9.81, [0.01, 0.05, 0.02, 0.02, 0.05, 0.01, 0.03, 0.01, 0.01]], [-0.001573, -4.938097]], [[-0.458, 0.539, 19.188, -9.81, [0.05, 0.03]], [-0.418741, 0.452873]]], [[[-1.649, -1.262, 17.944, 2.0, [0.05, 0.03, 0.01, 0.03, 0.03, 0.01, 0.05, 0.01, 0.05]], [-0.887193, 5.798575]], [[-0.08, 0.73, 11.393, -9.81, [0.03, 0.03, 0.05, 0.01, 0.01, 0.01, 0.01]], [-0.072953, -0.593702]], [[0.147, 1.147, 10.915, 0.0, [0.03, 0.02, 0.01]], [0.212566, 1.040528]], [[-1.434, -0.348, 10.741, -9.81, [0.03, 0.03, 0.03, 0.01, 0.05, 0.03, 0.03, 0.03, 0.01, 0.01]], [-1.336072, 1.031162]], [[1.03, 0.515, 11.074, 0.0, [0.02, 0.01, 0.02, 0.01, 0.03, 0.02]], [1.017159, -0.63278]], [[1.097, 0.642, 16.162, 2.0, [0.01, 0.03]], [1.110042, 0.246936]], [[1.461, 0.462, 16.321, 2.0, [0.01, 0.01, 0.02, 0.05, 0.01, 0.03, 0.02, 0.05, 0.01, 0.03]], [0.973124, -3.979779]], [[1.94, 0.689, 18.476, 0.0, [0.05, 0.01, 0.03, 0.01, 0.05, 0.02, 0.03, 0.02, 0.02]], [1.133627, -6.57541]]]]
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.982706, 2.547717][-0.982706, 2.547717]Passed
case 1[1.926444, -0.445559][1.926444, -0.445559]Passed
case 2[-0.612128, -0.865996][-0.615744, -0.938317]Failed
case 3[-0.049352, 0.784372][-0.046765, 0.848706]Failed
case 4[0.090294, 0.726662][0.090437, 0.729532]Failed
case 5[-1.268269, 2.939677][-1.249546, 3.301322]Failed
case 6[-1.654908, -0.324492][-1.654908, -0.324492]Passed
case 7[-1.347929, 2.084721][-1.339568, 2.290613]Failed

SHA-256 / dcaabc2a59528f766b879714a85d6e1ed81aab012f0991ebaad3ebf6f3b6ad7c

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x0, v0, w2, g, dts):
    def acc(p):
        return -w2 * p + g
    if not dts:
        return [round(x0, 6), round(v0, 6)]
    prev = x0
    x = x0 + v0 * dts[0] + 0.5 * acc(x0) * dts[0] * dts[0]
    for i in range(1, len(dts)):
        h, hp = dts[i], dts[i - 1]
        nxt = x + (x - prev) * (h / hp) + acc(x) * h * hp
        prev, x = x, nxt
    v = (x - prev) / dts[-1]
    return [round(x, 6), round(v, 6)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[-1.118, 1.653, 18.431, 0.0, [0.03, 0.03]], [-0.982706, 2.547717]], [[1.93, 0.372, 11.854, -9.81, [0.01, 0.01, 0.01]], [1.926444, -0.445559]], [[-0.532, -1.331, 9.198, 2.0, [0.03, 0.05]], [-0.615744, -0.938317]], [[-0.112, 0.567, 15.803, 2.0, [0.05, 0.01, 0.01, 0.01, 0.01]], [-0.046765, 0.848706]], [[0.002, 0.745, 4.672, 0.0, [0.03, 0.01, 0.03, 0.05]], [0.090437, 0.729532]], [[-1.559, 0.132, 13.212, 0.0, [0.05, 0.05, 0.02, 0.03, 0.01, 0.01]], [-1.249546, 3.301322]], [[-1.571, -1.847, 12.561, 0.0, [0.05, 0.05]], [-1.654908, -0.324492]], [[-1.514, 1.013, 16.587, -9.81, [0.05, 0.03, 0.02]], [-1.339568, 2.290613]]], [[[1.693, 1.184, 10.982, -9.81, [0.02, 0.03, 0.05, 0.05]], [1.550068, -2.368135]], [[-0.751, -1.653, 15.366, -9.81, [0.01, 0.05, 0.01, 0.03, 0.02, 0.03, 0.01]], [-0.977779, -1.105082]], [[1.862, 1.422, 6.208, 2.0, [0.01, 0.03, 0.03, 0.01, 0.01]], [1.950431, 0.584063]], [[0.454, 0.048, 11.925, 0.0, [0.01, 0.01, 0.01]], [0.453003, -0.087359]], [[-1.613, -0.622, 8.807, -9.81, [0.02, 0.03, 0.01, 0.05, 0.03]], [-1.655241, -0.043343]], [[0.644, -0.151, 13.871, -9.81, [0.02, 0.02, 0.01, 0.01, 0.05, 0.02, 0.03]], [0.387894, -2.717601]], [[-0.524, -1.843, 1.225, 0.0, [0.05, 0.02, 0.03, 0.01]], [-0.722411, -1.763355]], [[1.972, 1.228, 18.377, 2.0, [0.01, 0.03]], [1.993612, 0.36813]]], [[[1.558, 1.408, 12.285, 2.0, [0.02, 0.05, 0.03]], [1.611423, -0.087072]], [[-1.587, -0.211, 17.367, 2.0, [0.03, 0.01, 0.02, 0.02]], [-1.509843, 1.83789]], [[-1.478, -0.428, 14.024, 2.0, [0.01, 0.02, 0.01]], [-1.476913, 0.36867]], [[1.36, 0.701, 17.189, 2.0, [0.03, 0.05, 0.01, 0.03, 0.05, 0.01, 0.03]], [1.046693, -3.241676]], [[-0.045, -0.271, 10.763, 2.0, [0.02, 0.03]], [-0.055405, -0.182724]], [[0.106, -1.937, 2.608, 0.0, [0.03, 0.01, 0.03, 0.05, 0.01, 0.05, 0.05, 0.02]], [-0.374085, -1.858207]], [[-1.655, 0.554, 15.555, -9.81, [0.03, 0.02, 0.01, 0.01, 0.03, 0.01]], [-1.500918, 2.131832]], [[0.68, 1.896, 12.013, -9.81, [0.03, 0.03, 0.03]], [0.775896, 0.500859]]], [[[-0.942, 0.774, 3.875, 0.0, [0.02, 0.02, 0.03, 0.01, 0.02, 0.03]], [-0.811751, 1.170885]], [[1.678, -1.604, 6.016, 2.0, [0.02, 0.03, 0.05, 0.02, 0.05, 0.05, 0.02]], [1.087528, -3.119149]], [[-0.516, 0.344, 13.779, -9.81, [0.01, 0.03, 0.01, 0.01, 0.03, 0.05]], [-0.495793, 0.012391]], [[-0.434, -1.688, 15.899, 0.0, [0.03, 0.05, 0.01, 0.02]], [-0.573341, -0.885589]], [[-0.101, -1.02, 19.226, 2.0, [0.05, 0.01]], [-0.154839, -0.776626]], [[-1.698, 0.325, 6.546, -9.81, [0.02, 0.02]], [-1.683974, 0.363268]], [[0.712, -1.32, 18.303, -9.81, [0.01, 0.05, 0.02, 0.02, 0.05, 0.01, 0.03, 0.01, 0.01]], [-0.001573, -4.938097]], [[-0.458, 0.539, 19.188, -9.81, [0.05, 0.03]], [-0.418741, 0.452873]]], [[[-1.649, -1.262, 17.944, 2.0, [0.05, 0.03, 0.01, 0.03, 0.03, 0.01, 0.05, 0.01, 0.05]], [-0.887193, 5.798575]], [[-0.08, 0.73, 11.393, -9.81, [0.03, 0.03, 0.05, 0.01, 0.01, 0.01, 0.01]], [-0.072953, -0.593702]], [[0.147, 1.147, 10.915, 0.0, [0.03, 0.02, 0.01]], [0.212566, 1.040528]], [[-1.434, -0.348, 10.741, -9.81, [0.03, 0.03, 0.03, 0.01, 0.05, 0.03, 0.03, 0.03, 0.01, 0.01]], [-1.336072, 1.031162]], [[1.03, 0.515, 11.074, 0.0, [0.02, 0.01, 0.02, 0.01, 0.03, 0.02]], [1.017159, -0.63278]], [[1.097, 0.642, 16.162, 2.0, [0.01, 0.03]], [1.110042, 0.246936]], [[1.461, 0.462, 16.321, 2.0, [0.01, 0.01, 0.02, 0.05, 0.01, 0.03, 0.02, 0.05, 0.01, 0.03]], [0.973124, -3.979779]], [[1.94, 0.689, 18.476, 0.0, [0.05, 0.01, 0.03, 0.01, 0.05, 0.02, 0.03, 0.02, 0.02]], [1.133627, -6.57541]]]]
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.982706, 2.547717][-0.982706, 2.547717]Passed
case 1[1.926444, -0.445559][1.926444, -0.445559]Passed
case 2[-0.61936, -1.010638][-0.615744, -0.938317]Failed
case 3[-0.044177, 0.91304][-0.046765, 0.848706]Failed
case 4[0.090579, 0.732401][0.090437, 0.729532]Failed
case 5[-1.230846, 3.660683][-1.249546, 3.301322]Failed
case 6[-1.654908, -0.324492][-1.654908, -0.324492]Passed
case 7[-1.331221, 2.495801][-1.339568, 2.290613]Failed

SHA-256 / 3fcec2eb06c39bfde6e41843aef877b34b48a8fdd1fab7c4ce29b05ad18fd625

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x0, v0, w2, g, dts):
    def acc(p):
        return -w2 * p + g
    if not dts:
        return [round(x0, 6), round(v0, 6)]
    prev = x0
    x = x0 + v0 * dts[0] + 0.5 * acc(x0) * dts[0] * dts[0]
    for i in range(1, len(dts)):
        h, hp = dts[i], dts[i - 1]
        nxt = x + (x - prev) * (h / hp) + acc(x) * h * (h + hp) / 2
        prev, x = x, nxt
    v = (x - prev) / dts[-1]
    return [round(x, 6), round(v, 6)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[-1.118, 1.653, 18.431, 0.0, [0.03, 0.03]], [-0.982706, 2.547717]], [[1.93, 0.372, 11.854, -9.81, [0.01, 0.01, 0.01]], [1.926444, -0.445559]], [[-0.532, -1.331, 9.198, 2.0, [0.03, 0.05]], [-0.615744, -0.938317]], [[-0.112, 0.567, 15.803, 2.0, [0.05, 0.01, 0.01, 0.01, 0.01]], [-0.046765, 0.848706]], [[0.002, 0.745, 4.672, 0.0, [0.03, 0.01, 0.03, 0.05]], [0.090437, 0.729532]], [[-1.559, 0.132, 13.212, 0.0, [0.05, 0.05, 0.02, 0.03, 0.01, 0.01]], [-1.249546, 3.301322]], [[-1.571, -1.847, 12.561, 0.0, [0.05, 0.05]], [-1.654908, -0.324492]], [[-1.514, 1.013, 16.587, -9.81, [0.05, 0.03, 0.02]], [-1.339568, 2.290613]]], [[[1.693, 1.184, 10.982, -9.81, [0.02, 0.03, 0.05, 0.05]], [1.550068, -2.368135]], [[-0.751, -1.653, 15.366, -9.81, [0.01, 0.05, 0.01, 0.03, 0.02, 0.03, 0.01]], [-0.977779, -1.105082]], [[1.862, 1.422, 6.208, 2.0, [0.01, 0.03, 0.03, 0.01, 0.01]], [1.950431, 0.584063]], [[0.454, 0.048, 11.925, 0.0, [0.01, 0.01, 0.01]], [0.453003, -0.087359]], [[-1.613, -0.622, 8.807, -9.81, [0.02, 0.03, 0.01, 0.05, 0.03]], [-1.655241, -0.043343]], [[0.644, -0.151, 13.871, -9.81, [0.02, 0.02, 0.01, 0.01, 0.05, 0.02, 0.03]], [0.387894, -2.717601]], [[-0.524, -1.843, 1.225, 0.0, [0.05, 0.02, 0.03, 0.01]], [-0.722411, -1.763355]], [[1.972, 1.228, 18.377, 2.0, [0.01, 0.03]], [1.993612, 0.36813]]], [[[1.558, 1.408, 12.285, 2.0, [0.02, 0.05, 0.03]], [1.611423, -0.087072]], [[-1.587, -0.211, 17.367, 2.0, [0.03, 0.01, 0.02, 0.02]], [-1.509843, 1.83789]], [[-1.478, -0.428, 14.024, 2.0, [0.01, 0.02, 0.01]], [-1.476913, 0.36867]], [[1.36, 0.701, 17.189, 2.0, [0.03, 0.05, 0.01, 0.03, 0.05, 0.01, 0.03]], [1.046693, -3.241676]], [[-0.045, -0.271, 10.763, 2.0, [0.02, 0.03]], [-0.055405, -0.182724]], [[0.106, -1.937, 2.608, 0.0, [0.03, 0.01, 0.03, 0.05, 0.01, 0.05, 0.05, 0.02]], [-0.374085, -1.858207]], [[-1.655, 0.554, 15.555, -9.81, [0.03, 0.02, 0.01, 0.01, 0.03, 0.01]], [-1.500918, 2.131832]], [[0.68, 1.896, 12.013, -9.81, [0.03, 0.03, 0.03]], [0.775896, 0.500859]]], [[[-0.942, 0.774, 3.875, 0.0, [0.02, 0.02, 0.03, 0.01, 0.02, 0.03]], [-0.811751, 1.170885]], [[1.678, -1.604, 6.016, 2.0, [0.02, 0.03, 0.05, 0.02, 0.05, 0.05, 0.02]], [1.087528, -3.119149]], [[-0.516, 0.344, 13.779, -9.81, [0.01, 0.03, 0.01, 0.01, 0.03, 0.05]], [-0.495793, 0.012391]], [[-0.434, -1.688, 15.899, 0.0, [0.03, 0.05, 0.01, 0.02]], [-0.573341, -0.885589]], [[-0.101, -1.02, 19.226, 2.0, [0.05, 0.01]], [-0.154839, -0.776626]], [[-1.698, 0.325, 6.546, -9.81, [0.02, 0.02]], [-1.683974, 0.363268]], [[0.712, -1.32, 18.303, -9.81, [0.01, 0.05, 0.02, 0.02, 0.05, 0.01, 0.03, 0.01, 0.01]], [-0.001573, -4.938097]], [[-0.458, 0.539, 19.188, -9.81, [0.05, 0.03]], [-0.418741, 0.452873]]], [[[-1.649, -1.262, 17.944, 2.0, [0.05, 0.03, 0.01, 0.03, 0.03, 0.01, 0.05, 0.01, 0.05]], [-0.887193, 5.798575]], [[-0.08, 0.73, 11.393, -9.81, [0.03, 0.03, 0.05, 0.01, 0.01, 0.01, 0.01]], [-0.072953, -0.593702]], [[0.147, 1.147, 10.915, 0.0, [0.03, 0.02, 0.01]], [0.212566, 1.040528]], [[-1.434, -0.348, 10.741, -9.81, [0.03, 0.03, 0.03, 0.01, 0.05, 0.03, 0.03, 0.03, 0.01, 0.01]], [-1.336072, 1.031162]], [[1.03, 0.515, 11.074, 0.0, [0.02, 0.01, 0.02, 0.01, 0.03, 0.02]], [1.017159, -0.63278]], [[1.097, 0.642, 16.162, 2.0, [0.01, 0.03]], [1.110042, 0.246936]], [[1.461, 0.462, 16.321, 2.0, [0.01, 0.01, 0.02, 0.05, 0.01, 0.03, 0.02, 0.05, 0.01, 0.03]], [0.973124, -3.979779]], [[1.94, 0.689, 18.476, 0.0, [0.05, 0.01, 0.03, 0.01, 0.05, 0.02, 0.03, 0.02, 0.02]], [1.133627, -6.57541]]]]
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.982706, 2.547717][-0.982706, 2.547717]Passed
case 1[1.926444, -0.445559][1.926444, -0.445559]Passed
case 2[-0.615744, -0.938317][-0.615744, -0.938317]Passed
case 3[-0.046765, 0.848706][-0.046765, 0.848706]Passed
case 4[0.090437, 0.729532][0.090437, 0.729532]Passed
case 5[-1.249546, 3.301322][-1.249546, 3.301322]Passed
case 6[-1.654908, -0.324492][-1.654908, -0.324492]Passed
case 7[-1.339568, 2.290613][-1.339568, 2.290613]Passed

SHA-256 / 8a6fbf41bc436e9bbc27a9c6d2f5ce6763862ca54b1a3f004de6eac242ec1b3c

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

Case digest / 95d40e005c7eb68b6125e7ef3cbad6067dae004087fc4f4c2afb6584b19c4ce4