{"abstract":"Eastward moves overshoot the slew limit by one motor step.","category":"Solar tracker geometry","checks":7,"contract":"Angles in millidegrees. The target is clamped to [lo, hi]. If |target - current| < deadband no move is made. Otherwise the move is limited to +-max_step, converted to whole motor steps of dps millidegrees truncated toward zero. Return [new position, signed steps].","evaluation_group":"w2-solar_tracker_geometry-actuator-step-command","failed_approach":"Rounding to nearest can exceed the slew limit in both directions.","family":"w2-solar_tracker_geometry-actuator-step-command-step-truncation-direction","id":"FA-93531","implementations":{"attempt":{"sha256":"6af45ef7d68f86f4cf010618838167592c8fdfc1ae0f19d2f41ec34dafbb5438","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(target, current, deadband, max_step, dps, lo, hi):\n    tgt = min(max(target, lo), hi)\n    err = tgt - current\n    if abs(err) < deadband:\n        return [current, 0]\n    move = max(-max_step, min(max_step, err))\n    steps = round(abs(move) / dps)\n    if move < 0:\n        steps = -steps\n    return [current + steps * dps, steps]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['boundary: error equal to deadband', [1500, 1000, 500, 2000, 125, -60000, 60000], [1500, 4]],\n  ['boundary: target past west stop', [80000, 59000, 250, 5000, 7, -60000, 60000], [59994, 142]],\n  ['normal: negative move truncation', [-10000, 0, 250, 2000, 300, -60000, 60000], [-1800, -6]],\n  ['regression: step truncation direction', [87, 3902, 250, 500, 90, -52000, 55000], [3452, -5]],\n  ['regression: step truncation direction (partial repair)',\n   [1899, -3811, 250, 5000, 300, -60000, 60000], [989, 16]],\n  ['control 1', [-57417, -56117, 500, 2000, 300, -52000, 60000], [-54317, 6]],\n  ['control 2', [-62089, -29689, 500, 5000, 300, -55000, 60000], [-34489, -16]]],\n [['boundary: error equal to deadband', [1500, 1000, 500, 2000, 125, -60000, 60000], [1500, 4]],\n  ['boundary: target past west stop', [80000, 59000, 250, 5000, 7, -60000, 60000], [59994, 142]],\n  ['normal: negative move truncation', [-10000, 0, 250, 2000, 300, -60000, 60000], [-1800, -6]],\n  ['regression: step truncation direction', [-54271, -9833, 0, 2000, 90, -52000, 52000],\n   [-11813, -22]],\n  ['regression: step truncation direction (partial repair)',\n   [-47305, -34773, 1000, 5000, 300, -60000, 55000], [-39573, -16]],\n  ['control 1', [48241, -7501, 500, 500, 125, -55000, 60000], [-7001, 4]],\n  ['control 2', [53151, 50604, 0, 5000, 7, -55000, 55000], [53145, 363]]],\n [['boundary: error equal to deadband', [1500, 1000, 500, 2000, 125, -60000, 60000], [1500, 4]],\n  ['boundary: target past west stop', [80000, 59000, 250, 5000, 7, -60000, 60000], [59994, 142]],\n  ['normal: negative move truncation', [-10000, 0, 250, 2000, 300, -60000, 60000], [-1800, -6]],\n  ['regression: step truncation direction', [25571, 48224, 500, 2000, 90, -52000, 55000],\n   [46244, -22]],\n  ['regression: step truncation direction (partial repair)',\n   [-24432, -36322, 1000, 5000, 300, -60000, 52000], [-31522, 16]],\n  ['control 1', [-63679, -20673, 250, 5000, 125, -52000, 60000], [-25673, -40]],\n  ['control 2', [13642, -49671, 1000, 5000, 7, -52000, 55000], [-44673, 714]]],\n [['boundary: error equal to deadband', [1500, 1000, 500, 2000, 125, -60000, 60000], [1500, 4]],\n  ['boundary: target past west stop', [80000, 59000, 250, 5000, 7, -60000, 60000], [59994, 142]],\n  ['normal: negative move truncation', [-10000, 0, 250, 2000, 300, -60000, 60000], [-1800, -6]],\n  ['regression: step truncation direction', [-50922, -33896, 1000, 2000, 7, -52000, 60000],\n   [-35891, -285]],\n  ['regression: step truncation direction (partial repair)',\n   [56539, -49336, 500, 2000, 7, -60000, 55000], [-47341, 285]],\n  ['control 1', [-66913, 56864, 250, 5000, 125, -52000, 52000], [51864, -40]],\n  ['control 2', [19310, -10964, 250, 5000, 125, -52000, 52000], [-5964, 40]]],\n [['boundary: error equal to deadband', [1500, 1000, 500, 2000, 125, -60000, 60000], [1500, 4]],\n  ['boundary: target past west stop', [80000, 59000, 250, 5000, 7, -60000, 60000], [59994, 142]],\n  ['normal: negative move truncation', [-10000, 0, 250, 2000, 300, -60000, 60000], [-1800, -6]],\n  ['regression: step truncation direction', [3491, 18980, 250, 2000, 7, -55000, 60000],\n   [16985, -285]],\n  ['regression: step truncation direction (partial repair)',\n   [60232, -13012, 500, 500, 300, -60000, 55000], [-12712, 1]],\n  ['control 1', [22704, 24328, 1000, 5000, 300, -60000, 55000], [22828, -5]],\n  ['control 2', [56539, -49336, 500, 2000, 7, -60000, 55000], [-47341, 285]]]]\nfor label, args, expected in fixtures[N-1]:\n    check(label, 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":"cdcabf9aef4070ec237f260c443ccaa1736061a6ba047c8d03f1c6483ac1adf3","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(target, current, deadband, max_step, dps, lo, hi):\n    tgt = min(max(target, lo), hi)\n    err = tgt - current\n    if abs(err) < deadband:\n        return [current, 0]\n    move = max(-max_step, min(max_step, err))\n    steps = move // dps\n    return [current + steps * dps, steps]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['boundary: error equal to deadband', [1500, 1000, 500, 2000, 125, -60000, 60000], [1500, 4]],\n  ['boundary: target past west stop', [80000, 59000, 250, 5000, 7, -60000, 60000], [59994, 142]],\n  ['normal: negative move truncation', [-10000, 0, 250, 2000, 300, -60000, 60000], [-1800, -6]],\n  ['regression: step truncation direction', [87, 3902, 250, 500, 90, -52000, 55000], [3452, -5]],\n  ['regression: step truncation direction (partial repair)',\n   [1899, -3811, 250, 5000, 300, -60000, 60000], [989, 16]],\n  ['control 1', [-57417, -56117, 500, 2000, 300, -52000, 60000], [-54317, 6]],\n  ['control 2', [-62089, -29689, 500, 5000, 300, -55000, 60000], [-34489, -16]]],\n [['boundary: error equal to deadband', [1500, 1000, 500, 2000, 125, -60000, 60000], [1500, 4]],\n  ['boundary: target past west stop', [80000, 59000, 250, 5000, 7, -60000, 60000], [59994, 142]],\n  ['normal: negative move truncation', [-10000, 0, 250, 2000, 300, -60000, 60000], [-1800, -6]],\n  ['regression: step truncation direction', [-54271, -9833, 0, 2000, 90, -52000, 52000],\n   [-11813, -22]],\n  ['regression: step truncation direction (partial repair)',\n   [-47305, -34773, 1000, 5000, 300, -60000, 55000], [-39573, -16]],\n  ['control 1', [48241, -7501, 500, 500, 125, -55000, 60000], [-7001, 4]],\n  ['control 2', [53151, 50604, 0, 5000, 7, -55000, 55000], [53145, 363]]],\n [['boundary: error equal to deadband', [1500, 1000, 500, 2000, 125, -60000, 60000], [1500, 4]],\n  ['boundary: target past west stop', [80000, 59000, 250, 5000, 7, -60000, 60000], [59994, 142]],\n  ['normal: negative move truncation', [-10000, 0, 250, 2000, 300, -60000, 60000], [-1800, -6]],\n  ['regression: step truncation direction', [25571, 48224, 500, 2000, 90, -52000, 55000],\n   [46244, -22]],\n  ['regression: step truncation direction (partial repair)',\n   [-24432, -36322, 1000, 5000, 300, -60000, 52000], [-31522, 16]],\n  ['control 1', [-63679, -20673, 250, 5000, 125, -52000, 60000], [-25673, -40]],\n  ['control 2', [13642, -49671, 1000, 5000, 7, -52000, 55000], [-44673, 714]]],\n [['boundary: error equal to deadband', [1500, 1000, 500, 2000, 125, -60000, 60000], [1500, 4]],\n  ['boundary: target past west stop', [80000, 59000, 250, 5000, 7, -60000, 60000], [59994, 142]],\n  ['normal: negative move truncation', [-10000, 0, 250, 2000, 300, -60000, 60000], [-1800, -6]],\n  ['regression: step truncation direction', [-50922, -33896, 1000, 2000, 7, -52000, 60000],\n   [-35891, -285]],\n  ['regression: step truncation direction (partial repair)',\n   [56539, -49336, 500, 2000, 7, -60000, 55000], [-47341, 285]],\n  ['control 1', [-66913, 56864, 250, 5000, 125, -52000, 52000], [51864, -40]],\n  ['control 2', [19310, -10964, 250, 5000, 125, -52000, 52000], [-5964, 40]]],\n [['boundary: error equal to deadband', [1500, 1000, 500, 2000, 125, -60000, 60000], [1500, 4]],\n  ['boundary: target past west stop', [80000, 59000, 250, 5000, 7, -60000, 60000], [59994, 142]],\n  ['normal: negative move truncation', [-10000, 0, 250, 2000, 300, -60000, 60000], [-1800, -6]],\n  ['regression: step truncation direction', [3491, 18980, 250, 2000, 7, -55000, 60000],\n   [16985, -285]],\n  ['regression: step truncation direction (partial repair)',\n   [60232, -13012, 500, 500, 300, -60000, 55000], [-12712, 1]],\n  ['control 1', [22704, 24328, 1000, 5000, 300, -60000, 55000], [22828, -5]],\n  ['control 2', [56539, -49336, 500, 2000, 7, -60000, 55000], [-47341, 285]]]]\nfor label, args, expected in fixtures[N-1]:\n    check(label, 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":"347a4e041f03e82829a5ed59082d82ba908ab91c1a4b4fa082f1bacc5b3bd9ab","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(target, current, deadband, max_step, dps, lo, hi):\n    tgt = min(max(target, lo), hi)\n    err = tgt - current\n    if abs(err) < deadband:\n        return [current, 0]\n    move = max(-max_step, min(max_step, err))\n    steps = abs(move) // dps\n    if move < 0:\n        steps = -steps\n    return [current + steps * dps, steps]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['boundary: error equal to deadband', [1500, 1000, 500, 2000, 125, -60000, 60000], [1500, 4]],\n  ['boundary: target past west stop', [80000, 59000, 250, 5000, 7, -60000, 60000], [59994, 142]],\n  ['normal: negative move truncation', [-10000, 0, 250, 2000, 300, -60000, 60000], [-1800, -6]],\n  ['regression: step truncation direction', [87, 3902, 250, 500, 90, -52000, 55000], [3452, -5]],\n  ['regression: step truncation direction (partial repair)',\n   [1899, -3811, 250, 5000, 300, -60000, 60000], [989, 16]],\n  ['control 1', [-57417, -56117, 500, 2000, 300, -52000, 60000], [-54317, 6]],\n  ['control 2', [-62089, -29689, 500, 5000, 300, -55000, 60000], [-34489, -16]]],\n [['boundary: error equal to deadband', [1500, 1000, 500, 2000, 125, -60000, 60000], [1500, 4]],\n  ['boundary: target past west stop', [80000, 59000, 250, 5000, 7, -60000, 60000], [59994, 142]],\n  ['normal: negative move truncation', [-10000, 0, 250, 2000, 300, -60000, 60000], [-1800, -6]],\n  ['regression: step truncation direction', [-54271, -9833, 0, 2000, 90, -52000, 52000],\n   [-11813, -22]],\n  ['regression: step truncation direction (partial repair)',\n   [-47305, -34773, 1000, 5000, 300, -60000, 55000], [-39573, -16]],\n  ['control 1', [48241, -7501, 500, 500, 125, -55000, 60000], [-7001, 4]],\n  ['control 2', [53151, 50604, 0, 5000, 7, -55000, 55000], [53145, 363]]],\n [['boundary: error equal to deadband', [1500, 1000, 500, 2000, 125, -60000, 60000], [1500, 4]],\n  ['boundary: target past west stop', [80000, 59000, 250, 5000, 7, -60000, 60000], [59994, 142]],\n  ['normal: negative move truncation', [-10000, 0, 250, 2000, 300, -60000, 60000], [-1800, -6]],\n  ['regression: step truncation direction', [25571, 48224, 500, 2000, 90, -52000, 55000],\n   [46244, -22]],\n  ['regression: step truncation direction (partial repair)',\n   [-24432, -36322, 1000, 5000, 300, -60000, 52000], [-31522, 16]],\n  ['control 1', [-63679, -20673, 250, 5000, 125, -52000, 60000], [-25673, -40]],\n  ['control 2', [13642, -49671, 1000, 5000, 7, -52000, 55000], [-44673, 714]]],\n [['boundary: error equal to deadband', [1500, 1000, 500, 2000, 125, -60000, 60000], [1500, 4]],\n  ['boundary: target past west stop', [80000, 59000, 250, 5000, 7, -60000, 60000], [59994, 142]],\n  ['normal: negative move truncation', [-10000, 0, 250, 2000, 300, -60000, 60000], [-1800, -6]],\n  ['regression: step truncation direction', [-50922, -33896, 1000, 2000, 7, -52000, 60000],\n   [-35891, -285]],\n  ['regression: step truncation direction (partial repair)',\n   [56539, -49336, 500, 2000, 7, -60000, 55000], [-47341, 285]],\n  ['control 1', [-66913, 56864, 250, 5000, 125, -52000, 52000], [51864, -40]],\n  ['control 2', [19310, -10964, 250, 5000, 125, -52000, 52000], [-5964, 40]]],\n [['boundary: error equal to deadband', [1500, 1000, 500, 2000, 125, -60000, 60000], [1500, 4]],\n  ['boundary: target past west stop', [80000, 59000, 250, 5000, 7, -60000, 60000], [59994, 142]],\n  ['normal: negative move truncation', [-10000, 0, 250, 2000, 300, -60000, 60000], [-1800, -6]],\n  ['regression: step truncation direction', [3491, 18980, 250, 2000, 7, -55000, 60000],\n   [16985, -285]],\n  ['regression: step truncation direction (partial repair)',\n   [60232, -13012, 500, 500, 300, -60000, 55000], [-12712, 1]],\n  ['control 1', [22704, 24328, 1000, 5000, 300, -60000, 55000], [22828, -5]],\n  ['control 2', [56539, -49336, 500, 2000, 7, -60000, 55000], [-47341, 285]]]]\nfor label, args, expected in fixtures[N-1]:\n    check(label, 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":"Deterministic stipulated toy contract for teaching; no claim of conformance with any standard, vendor protocol or production controller. 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-solar_tracker_geometry-actuator-step-command-step-truncation-direction","generated_at":"2026-09-29T14:51:56.152532+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Single-axis and dual-axis solar trackers turn a sun direction into actuator commands; a sign, frame or limit mistake points a whole plant away from the sun or into a mechanical stop.","repair":"Truncate the step count toward zero.","root_cause":"Floor division rounds negative moves away from zero.","sha256":"b0e79c9d6639198b817863db04d6e91c65d224e3e00a38ab5555c3071d6f40cf","title":"Tracker actuator step command: step truncation direction · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":40.225,"exit_code":1,"observations":[{"actual":[1500,4],"check":"boundary: error equal to deadband","expected":[1500,4],"passed":true},{"actual":[60001,143],"check":"boundary: target past west stop","expected":[59994,142],"passed":false},{"actual":[-2100,-7],"check":"normal: negative move truncation","expected":[-1800,-6],"passed":false},{"actual":[3362,-6],"check":"regression: step truncation direction","expected":[3452,-5],"passed":false},{"actual":[1289,17],"check":"regression: step truncation direction (partial repair)","expected":[989,16],"passed":false},{"actual":[-54017,7],"check":"control 1","expected":[-54317,6],"passed":false},{"actual":[-34789,-17],"check":"control 2","expected":[-34489,-16],"passed":false}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"boundary: error equal to deadband\", \"actual\": [1500, 4], \"expected\": [1500, 4], \"passed\": true}, {\"check\": \"boundary: target past west stop\", \"actual\": [60001, 143], \"expected\": [59994, 142], \"passed\": false}, {\"check\": \"normal: negative move truncation\", \"actual\": [-2100, -7], \"expected\": [-1800, -6], \"passed\": false}, {\"check\": \"regression: step truncation direction\", \"actual\": [3362, -6], \"expected\": [3452, -5], \"passed\": false}, {\"check\": \"regression: step truncation direction (partial repair)\", \"actual\": [1289, 17], \"expected\": [989, 16], \"passed\": false}, {\"check\": \"control 1\", \"actual\": [-54017, 7], \"expected\": [-54317, 6], \"passed\": false}, {\"check\": \"control 2\", \"actual\": [-34789, -17], \"expected\": [-34489, -16], \"passed\": false}], \"passed\": false}\n"},"broken":{"elapsed_ms":41.752,"exit_code":1,"observations":[{"actual":[1500,4],"check":"boundary: error equal to deadband","expected":[1500,4],"passed":true},{"actual":[59994,142],"check":"boundary: target past west stop","expected":[59994,142],"passed":true},{"actual":[-2100,-7],"check":"normal: negative move truncation","expected":[-1800,-6],"passed":false},{"actual":[3362,-6],"check":"regression: step truncation direction","expected":[3452,-5],"passed":false},{"actual":[989,16],"check":"regression: step truncation direction (partial repair)","expected":[989,16],"passed":true},{"actual":[-54317,6],"check":"control 1","expected":[-54317,6],"passed":true},{"actual":[-34789,-17],"check":"control 2","expected":[-34489,-16],"passed":false}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"boundary: error equal to deadband\", \"actual\": [1500, 4], \"expected\": [1500, 4], \"passed\": true}, {\"check\": \"boundary: target past west stop\", \"actual\": [59994, 142], \"expected\": [59994, 142], \"passed\": true}, {\"check\": \"normal: negative move truncation\", \"actual\": [-2100, -7], \"expected\": [-1800, -6], \"passed\": false}, {\"check\": \"regression: step truncation direction\", \"actual\": [3362, -6], \"expected\": [3452, -5], \"passed\": false}, {\"check\": \"regression: step truncation direction (partial repair)\", \"actual\": [989, 16], \"expected\": [989, 16], \"passed\": true}, {\"check\": \"control 1\", \"actual\": [-54317, 6], \"expected\": [-54317, 6], \"passed\": true}, {\"check\": \"control 2\", \"actual\": [-34789, -17], \"expected\": [-34489, -16], \"passed\": false}], \"passed\": false}\n"},"fixed":{"elapsed_ms":38.86,"exit_code":0,"observations":[{"actual":[1500,4],"check":"boundary: error equal to deadband","expected":[1500,4],"passed":true},{"actual":[59994,142],"check":"boundary: target past west stop","expected":[59994,142],"passed":true},{"actual":[-1800,-6],"check":"normal: negative move truncation","expected":[-1800,-6],"passed":true},{"actual":[3452,-5],"check":"regression: step truncation direction","expected":[3452,-5],"passed":true},{"actual":[989,16],"check":"regression: step truncation direction (partial repair)","expected":[989,16],"passed":true},{"actual":[-54317,6],"check":"control 1","expected":[-54317,6],"passed":true},{"actual":[-34489,-16],"check":"control 2","expected":[-34489,-16],"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"boundary: error equal to deadband\", \"actual\": [1500, 4], \"expected\": [1500, 4], \"passed\": true}, {\"check\": \"boundary: target past west stop\", \"actual\": [59994, 142], \"expected\": [59994, 142], \"passed\": true}, {\"check\": \"normal: negative move truncation\", \"actual\": [-1800, -6], \"expected\": [-1800, -6], \"passed\": true}, {\"check\": \"regression: step truncation direction\", \"actual\": [3452, -5], \"expected\": [3452, -5], \"passed\": true}, {\"check\": \"regression: step truncation direction (partial repair)\", \"actual\": [989, 16], \"expected\": [989, 16], \"passed\": true}, {\"check\": \"control 1\", \"actual\": [-54317, 6], \"expected\": [-54317, 6], \"passed\": true}, {\"check\": \"control 2\", \"actual\": [-34489, -16], \"expected\": [-34489, -16], \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}