{"abstract":"Velocity output is offset by half a step, corrupting energy and contact logic.","category":"Physics integrator stability","checks":8,"contract":"solve(x0, v0, w2, g, dt, steps): acceleration -w2*x-g. The engine stores velocity at half steps: vh=v0+a(x0)*dt/2, then per step x+=vh*dt; vh+=a(x)*dt. Output synchronizes velocity back to the integer step: [x, vh-a(x)*dt/2] rounded to 6.","evaluation_group":"w2-physics_integrator_stability-leapfrog-staggered-velocity","failed_approach":"Adding the half kick synchronizes to the next half step instead.","family":"w2-physics_integrator_stability-leapfrog-staggered-velocity-output-synchronization","id":"FA-87076","implementations":{"attempt":{"sha256":"e6bf8b787a4456e31252de2abb89f676c8f5d95b09be4bde078c72a91b265a37","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(x0, v0, w2, g, dt, steps):\n    def acc(p):\n        return -w2 * p - g\n    vh = v0 + acc(x0) * dt / 2\n    x = x0\n    for _ in range(steps):\n        x = x + vh * dt\n        vh = vh + acc(x) * dt\n    v = vh + acc(x) * dt / 2\n    return [round(x, 6), round(v, 6)]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[[[1.7, 0.206, 28.764, 0.0, 0.05, 1], [1.649177, -2.202393]], [[1.673, -0.912, 25.576, 1.62, 0.01, 0], [1.673, -0.912]], [[-1.14, -0.439, 14.103, 1.62, 0.05, 7], [-0.486563, 3.598832]], [[0.546, 0.718, 9.779, 1.62, 0.01, 4], [0.569089, 0.434764]], [[-0.116, 0.63, 5.023, 1.62, 0.01, 1], [-0.109752, 0.61947]], [[-0.776, -1.002, 7.733, 0.0, 0.2, 5], [0.616431, 1.609137]], [[0.454, 1.015, 13.329, 1.62, 0.1, 8], [-0.627698, -1.413232]], [[1.929, 0.884, 10.735, -3.0, 0.1, 6], [-0.117431, -5.249921]]], [[[-0.141, -1.302, 4.434, 0.0, 0.2, 3], [-0.646031, -0.104617]], [[0.221, 0.724, 15.178, -3.0, 0.01, 4], [0.249567, 0.701111]], [[-0.398, 0.635, 6.904, 1.62, 0.2, 2], [-0.095078, 0.670473]], [[-1.537, -0.458, 19.191, 0.0, 0.1, 1], [-1.435317, 2.394087]], [[1.542, -0.412, 13.302, -3.0, 0.05, 5], [0.940546, -4.03579]], [[-1.933, 0.742, 17.091, 9.81, 0.1, 0], [-1.933, 0.742]], [[-1.3, -1.601, 29.614, 0.0, 0.01, 8], [-1.302842, 1.5311]], [[-1.39, 0.449, 7.635, 0.0, 0.1, 2], [-1.095426, 2.384282]]], [[[-1.614, -0.301, 28.452, 0.0, 0.1, 3], [0.020608, 8.302094]], [[-1.735, -0.587, 6.94, 9.81, 0.01, 1], [-1.740758, -0.564491]], [[-0.575, 0.793, 13.055, 0.0, 0.05, 9], [0.252971, 2.020225]], [[-0.73, 0.772, 21.128, 0.0, 0.01, 14], [-0.483162, 2.630496]], [[1.361, 1.476, 18.508, -3.0, 0.1, 14], [1.259752, 2.50659]], [[0.094, -1.444, 12.401, -3.0, 0.01, 1], [0.079652, -1.424767]], [[0.444, -1.128, 10.972, 1.62, 0.05, 0], [0.444, -1.128]], [[1.032, -0.358, 14.758, 9.81, 0.2, 3], [-1.946637, -3.958747]]], [[[0.12, -1.504, 16.817, 9.81, 0.2, 10], [-1.311284, -1.330163]], [[-1.412, -0.807, 16.554, 9.81, 0.01, 12], [-1.409313, 0.850886]], [[-0.848, -0.478, 27.166, 0.0, 0.1, 10], [-0.370416, -3.868163]], [[-0.361, 1.302, 18.884, 0.0, 0.2, 2], [0.405487, 1.082999]], [[-0.711, -0.993, 29.278, 0.0, 0.05, 4], [-0.495489, 2.9085]], [[-0.367, -0.664, 29.52, 9.81, 0.01, 10], [-0.425216, -0.470963]], [[0.348, -1.537, 1.936, 1.62, 0.05, 6], [-0.20195, -2.073008]], [[1.5, -1.381, 20.519, 1.62, 0.2, 16], [-1.532726, -2.845764]]], [[[0.485, -1.561, 16.759, -3.0, 0.1, 5], [-0.308777, -0.345923]], [[-1.8, -0.658, 27.149, -3.0, 0.05, 1], [-1.768065, 1.913735]], [[1.537, -0.061, 3.471, 9.81, 0.01, 14], [1.380971, -2.155206]], [[-0.623, 0.986, 1.922, -3.0, 0.1, 14], [3.018244, 2.45605]], [[-1.842, 1.748, 8.887, 9.81, 0.01, 2], [-1.805744, 1.876003]], [[-0.042, -1.542, 14.783, 0.0, 0.05, 2], [-0.190275, -1.368698]], [[-1.884, -1.434, 28.956, -3.0, 0.05, 11], [2.015248, 3.236951]], [[-0.026, -0.891, 12.663, -3.0, 0.2, 4], [0.431498, 1.067509]]]]\nfor i, (args, expected) in enumerate(fixtures[N-1]):\n    check(\"case %d\" % i, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"broken":{"sha256":"bcf5528f8f44b4fc949e60095ca6a5497a57afdf9393ce2eaf8bc42567f58686","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(x0, v0, w2, g, dt, steps):\n    def acc(p):\n        return -w2 * p - g\n    vh = v0 + acc(x0) * dt / 2\n    x = x0\n    for _ in range(steps):\n        x = x + vh * dt\n        vh = vh + acc(x) * dt\n    v = vh\n    return [round(x, 6), round(v, 6)]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[[[1.7, 0.206, 28.764, 0.0, 0.05, 1], [1.649177, -2.202393]], [[1.673, -0.912, 25.576, 1.62, 0.01, 0], [1.673, -0.912]], [[-1.14, -0.439, 14.103, 1.62, 0.05, 7], [-0.486563, 3.598832]], [[0.546, 0.718, 9.779, 1.62, 0.01, 4], [0.569089, 0.434764]], [[-0.116, 0.63, 5.023, 1.62, 0.01, 1], [-0.109752, 0.61947]], [[-0.776, -1.002, 7.733, 0.0, 0.2, 5], [0.616431, 1.609137]], [[0.454, 1.015, 13.329, 1.62, 0.1, 8], [-0.627698, -1.413232]], [[1.929, 0.884, 10.735, -3.0, 0.1, 6], [-0.117431, -5.249921]]], [[[-0.141, -1.302, 4.434, 0.0, 0.2, 3], [-0.646031, -0.104617]], [[0.221, 0.724, 15.178, -3.0, 0.01, 4], [0.249567, 0.701111]], [[-0.398, 0.635, 6.904, 1.62, 0.2, 2], [-0.095078, 0.670473]], [[-1.537, -0.458, 19.191, 0.0, 0.1, 1], [-1.435317, 2.394087]], [[1.542, -0.412, 13.302, -3.0, 0.05, 5], [0.940546, -4.03579]], [[-1.933, 0.742, 17.091, 9.81, 0.1, 0], [-1.933, 0.742]], [[-1.3, -1.601, 29.614, 0.0, 0.01, 8], [-1.302842, 1.5311]], [[-1.39, 0.449, 7.635, 0.0, 0.1, 2], [-1.095426, 2.384282]]], [[[-1.614, -0.301, 28.452, 0.0, 0.1, 3], [0.020608, 8.302094]], [[-1.735, -0.587, 6.94, 9.81, 0.01, 1], [-1.740758, -0.564491]], [[-0.575, 0.793, 13.055, 0.0, 0.05, 9], [0.252971, 2.020225]], [[-0.73, 0.772, 21.128, 0.0, 0.01, 14], [-0.483162, 2.630496]], [[1.361, 1.476, 18.508, -3.0, 0.1, 14], [1.259752, 2.50659]], [[0.094, -1.444, 12.401, -3.0, 0.01, 1], [0.079652, -1.424767]], [[0.444, -1.128, 10.972, 1.62, 0.05, 0], [0.444, -1.128]], [[1.032, -0.358, 14.758, 9.81, 0.2, 3], [-1.946637, -3.958747]]], [[[0.12, -1.504, 16.817, 9.81, 0.2, 10], [-1.311284, -1.330163]], [[-1.412, -0.807, 16.554, 9.81, 0.01, 12], [-1.409313, 0.850886]], [[-0.848, -0.478, 27.166, 0.0, 0.1, 10], [-0.370416, -3.868163]], [[-0.361, 1.302, 18.884, 0.0, 0.2, 2], [0.405487, 1.082999]], [[-0.711, -0.993, 29.278, 0.0, 0.05, 4], [-0.495489, 2.9085]], [[-0.367, -0.664, 29.52, 9.81, 0.01, 10], [-0.425216, -0.470963]], [[0.348, -1.537, 1.936, 1.62, 0.05, 6], [-0.20195, -2.073008]], [[1.5, -1.381, 20.519, 1.62, 0.2, 16], [-1.532726, -2.845764]]], [[[0.485, -1.561, 16.759, -3.0, 0.1, 5], [-0.308777, -0.345923]], [[-1.8, -0.658, 27.149, -3.0, 0.05, 1], [-1.768065, 1.913735]], [[1.537, -0.061, 3.471, 9.81, 0.01, 14], [1.380971, -2.155206]], [[-0.623, 0.986, 1.922, -3.0, 0.1, 14], [3.018244, 2.45605]], [[-1.842, 1.748, 8.887, 9.81, 0.01, 2], [-1.805744, 1.876003]], [[-0.042, -1.542, 14.783, 0.0, 0.05, 2], [-0.190275, -1.368698]], [[-1.884, -1.434, 28.956, -3.0, 0.05, 11], [2.015248, 3.236951]], [[-0.026, -0.891, 12.663, -3.0, 0.2, 4], [0.431498, 1.067509]]]]\nfor i, (args, expected) in enumerate(fixtures[N-1]):\n    check(\"case %d\" % i, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"fixed":{"sha256":"7ab00579776a5e5c267594b9e18c952f05a548c28b3ce38172e77df588c5161c","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(x0, v0, w2, g, dt, steps):\n    def acc(p):\n        return -w2 * p - g\n    vh = v0 + acc(x0) * dt / 2\n    x = x0\n    for _ in range(steps):\n        x = x + vh * dt\n        vh = vh + acc(x) * dt\n    v = vh - acc(x) * dt / 2\n    return [round(x, 6), round(v, 6)]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[[[1.7, 0.206, 28.764, 0.0, 0.05, 1], [1.649177, -2.202393]], [[1.673, -0.912, 25.576, 1.62, 0.01, 0], [1.673, -0.912]], [[-1.14, -0.439, 14.103, 1.62, 0.05, 7], [-0.486563, 3.598832]], [[0.546, 0.718, 9.779, 1.62, 0.01, 4], [0.569089, 0.434764]], [[-0.116, 0.63, 5.023, 1.62, 0.01, 1], [-0.109752, 0.61947]], [[-0.776, -1.002, 7.733, 0.0, 0.2, 5], [0.616431, 1.609137]], [[0.454, 1.015, 13.329, 1.62, 0.1, 8], [-0.627698, -1.413232]], [[1.929, 0.884, 10.735, -3.0, 0.1, 6], [-0.117431, -5.249921]]], [[[-0.141, -1.302, 4.434, 0.0, 0.2, 3], [-0.646031, -0.104617]], [[0.221, 0.724, 15.178, -3.0, 0.01, 4], [0.249567, 0.701111]], [[-0.398, 0.635, 6.904, 1.62, 0.2, 2], [-0.095078, 0.670473]], [[-1.537, -0.458, 19.191, 0.0, 0.1, 1], [-1.435317, 2.394087]], [[1.542, -0.412, 13.302, -3.0, 0.05, 5], [0.940546, -4.03579]], [[-1.933, 0.742, 17.091, 9.81, 0.1, 0], [-1.933, 0.742]], [[-1.3, -1.601, 29.614, 0.0, 0.01, 8], [-1.302842, 1.5311]], [[-1.39, 0.449, 7.635, 0.0, 0.1, 2], [-1.095426, 2.384282]]], [[[-1.614, -0.301, 28.452, 0.0, 0.1, 3], [0.020608, 8.302094]], [[-1.735, -0.587, 6.94, 9.81, 0.01, 1], [-1.740758, -0.564491]], [[-0.575, 0.793, 13.055, 0.0, 0.05, 9], [0.252971, 2.020225]], [[-0.73, 0.772, 21.128, 0.0, 0.01, 14], [-0.483162, 2.630496]], [[1.361, 1.476, 18.508, -3.0, 0.1, 14], [1.259752, 2.50659]], [[0.094, -1.444, 12.401, -3.0, 0.01, 1], [0.079652, -1.424767]], [[0.444, -1.128, 10.972, 1.62, 0.05, 0], [0.444, -1.128]], [[1.032, -0.358, 14.758, 9.81, 0.2, 3], [-1.946637, -3.958747]]], [[[0.12, -1.504, 16.817, 9.81, 0.2, 10], [-1.311284, -1.330163]], [[-1.412, -0.807, 16.554, 9.81, 0.01, 12], [-1.409313, 0.850886]], [[-0.848, -0.478, 27.166, 0.0, 0.1, 10], [-0.370416, -3.868163]], [[-0.361, 1.302, 18.884, 0.0, 0.2, 2], [0.405487, 1.082999]], [[-0.711, -0.993, 29.278, 0.0, 0.05, 4], [-0.495489, 2.9085]], [[-0.367, -0.664, 29.52, 9.81, 0.01, 10], [-0.425216, -0.470963]], [[0.348, -1.537, 1.936, 1.62, 0.05, 6], [-0.20195, -2.073008]], [[1.5, -1.381, 20.519, 1.62, 0.2, 16], [-1.532726, -2.845764]]], [[[0.485, -1.561, 16.759, -3.0, 0.1, 5], [-0.308777, -0.345923]], [[-1.8, -0.658, 27.149, -3.0, 0.05, 1], [-1.768065, 1.913735]], [[1.537, -0.061, 3.471, 9.81, 0.01, 14], [1.380971, -2.155206]], [[-0.623, 0.986, 1.922, -3.0, 0.1, 14], [3.018244, 2.45605]], [[-1.842, 1.748, 8.887, 9.81, 0.01, 2], [-1.805744, 1.876003]], [[-0.042, -1.542, 14.783, 0.0, 0.05, 2], [-0.190275, -1.368698]], [[-1.884, -1.434, 28.956, -3.0, 0.05, 11], [2.015248, 3.236951]], [[-0.026, -0.891, 12.663, -3.0, 0.2, 4], [0.431498, 1.067509]]]]\nfor i, (args, expected) in enumerate(fixtures[N-1]):\n    check(\"case %d\" % i, solve(*args), expected)\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"}},"limitations":"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.","method":"Deterministic executable model with adversarial boundary fixtures.","provenance":{"created_by":"Failure Map","dependencies":"Python standard library","family":"w2-physics_integrator_stability-leapfrog-staggered-velocity-output-synchronization","generated_at":"2026-09-29T14:50:55.371200+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"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.","repair":"Subtract a(x)*dt/2 from the staggered velocity.","root_cause":"The final velocity is returned without the back half-kick.","sha256":"b6267f7509953feb0048c32a317550bfe26e542a592bcceeb60a2263a3a29a4a","title":"Leapfrog reports the half-step velocity as the current velocity · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":40.427,"exit_code":1,"observations":[{"actual":[1.649177,-4.574238],"check":"case 0","expected":[1.649177,-2.202393],"passed":false},{"actual":[1.673,-1.356086],"check":"case 1","expected":[1.673,-0.912],"passed":false},{"actual":[-0.486563,3.860931],"check":"case 2","expected":[-0.486563,3.598832],"passed":false},{"actual":[0.569089,0.362913],"check":"case 3","expected":[0.569089,0.434764],"passed":false},{"actual":[-0.109752,0.608783],"check":"case 4","expected":[-0.109752,0.61947],"passed":false},{"actual":[0.616431,0.655764],"check":"case 5","expected":[0.616431,1.609137],"passed":false},{"actual":[-0.627698,-0.738574],"check":"case 6","expected":[-0.627698,-1.413232],"passed":false},{"actual":[-0.117431,-4.823859],"check":"case 7","expected":[-0.117431,-5.249921],"passed":false}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"case 0\", \"actual\": [1.649177, -4.574238], \"expected\": [1.649177, -2.202393], \"passed\": false}, {\"check\": \"case 1\", \"actual\": [1.673, -1.356086], \"expected\": [1.673, -0.912], \"passed\": false}, {\"check\": \"case 2\", \"actual\": [-0.486563, 3.860931], \"expected\": [-0.486563, 3.598832], \"passed\": false}, {\"check\": \"case 3\", \"actual\": [0.569089, 0.362913], \"expected\": [0.569089, 0.434764], \"passed\": false}, {\"check\": \"case 4\", \"actual\": [-0.109752, 0.608783], \"expected\": [-0.109752, 0.61947], \"passed\": false}, {\"check\": \"case 5\", \"actual\": [0.616431, 0.655764], \"expected\": [0.616431, 1.609137], \"passed\": false}, {\"check\": \"case 6\", \"actual\": [-0.627698, -0.738574], \"expected\": [-0.627698, -1.413232], \"passed\": false}, {\"check\": \"case 7\", \"actual\": [-0.117431, -4.823859], \"expected\": [-0.117431, -5.249921], \"passed\": false}], \"passed\": false}\n"},"broken":{"elapsed_ms":42.342,"exit_code":1,"observations":[{"actual":[1.649177,-3.388316],"check":"case 0","expected":[1.649177,-2.202393],"passed":false},{"actual":[1.673,-1.134043],"check":"case 1","expected":[1.673,-0.912],"passed":false},{"actual":[-0.486563,3.729882],"check":"case 2","expected":[-0.486563,3.598832],"passed":false},{"actual":[0.569089,0.398839],"check":"case 3","expected":[0.569089,0.434764],"passed":false},{"actual":[-0.109752,0.614126],"check":"case 4","expected":[-0.109752,0.61947],"passed":false},{"actual":[0.616431,1.13245],"check":"case 5","expected":[0.616431,1.609137],"passed":false},{"actual":[-0.627698,-1.075903],"check":"case 6","expected":[-0.627698,-1.413232],"passed":false},{"actual":[-0.117431,-5.03689],"check":"case 7","expected":[-0.117431,-5.249921],"passed":false}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"case 0\", \"actual\": [1.649177, -3.388316], \"expected\": [1.649177, -2.202393], \"passed\": false}, {\"check\": \"case 1\", \"actual\": [1.673, -1.134043], \"expected\": [1.673, -0.912], \"passed\": false}, {\"check\": \"case 2\", \"actual\": [-0.486563, 3.729882], \"expected\": [-0.486563, 3.598832], \"passed\": false}, {\"check\": \"case 3\", \"actual\": [0.569089, 0.398839], \"expected\": [0.569089, 0.434764], \"passed\": false}, {\"check\": \"case 4\", \"actual\": [-0.109752, 0.614126], \"expected\": [-0.109752, 0.61947], \"passed\": false}, {\"check\": \"case 5\", \"actual\": [0.616431, 1.13245], \"expected\": [0.616431, 1.609137], \"passed\": false}, {\"check\": \"case 6\", \"actual\": [-0.627698, -1.075903], \"expected\": [-0.627698, -1.413232], \"passed\": false}, {\"check\": \"case 7\", \"actual\": [-0.117431, -5.03689], \"expected\": [-0.117431, -5.249921], \"passed\": false}], \"passed\": false}\n"},"fixed":{"elapsed_ms":42.275,"exit_code":0,"observations":[{"actual":[1.649177,-2.202393],"check":"case 0","expected":[1.649177,-2.202393],"passed":true},{"actual":[1.673,-0.912],"check":"case 1","expected":[1.673,-0.912],"passed":true},{"actual":[-0.486563,3.598832],"check":"case 2","expected":[-0.486563,3.598832],"passed":true},{"actual":[0.569089,0.434764],"check":"case 3","expected":[0.569089,0.434764],"passed":true},{"actual":[-0.109752,0.61947],"check":"case 4","expected":[-0.109752,0.61947],"passed":true},{"actual":[0.616431,1.609137],"check":"case 5","expected":[0.616431,1.609137],"passed":true},{"actual":[-0.627698,-1.413232],"check":"case 6","expected":[-0.627698,-1.413232],"passed":true},{"actual":[-0.117431,-5.249921],"check":"case 7","expected":[-0.117431,-5.249921],"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"case 0\", \"actual\": [1.649177, -2.202393], \"expected\": [1.649177, -2.202393], \"passed\": true}, {\"check\": \"case 1\", \"actual\": [1.673, -0.912], \"expected\": [1.673, -0.912], \"passed\": true}, {\"check\": \"case 2\", \"actual\": [-0.486563, 3.598832], \"expected\": [-0.486563, 3.598832], \"passed\": true}, {\"check\": \"case 3\", \"actual\": [0.569089, 0.434764], \"expected\": [0.569089, 0.434764], \"passed\": true}, {\"check\": \"case 4\", \"actual\": [-0.109752, 0.61947], \"expected\": [-0.109752, 0.61947], \"passed\": true}, {\"check\": \"case 5\", \"actual\": [0.616431, 1.609137], \"expected\": [0.616431, 1.609137], \"passed\": true}, {\"check\": \"case 6\", \"actual\": [-0.627698, -1.413232], \"expected\": [-0.627698, -1.413232], \"passed\": true}, {\"check\": \"case 7\", \"actual\": [-0.117431, -5.249921], \"expected\": [-0.117431, -5.249921], \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}