{"abstract":"Rotation angles look random for any axis orientation.","category":"Solar tracker geometry","checks":7,"contract":"Sun azimuth clockwise from north and elevation in degrees. The horizontal axis points to axis_az; rotation is positive toward azimuth axis_az+90. Sun vector east=cos(el)sin(az), north=cos(el)cos(az), up=sin(el). Rotation = atan2(component along axis_az+90, up). Clamp to +-max_angle (status 'limited', else 'tracking'); sun_el <= 0 returns [0.0, 'night']. Round to 3 decimals.","evaluation_group":"w2-solar_tracker_geometry-horizontal-axis-true-tracking","failed_approach":"Adding 90 after converting mixes radians with degrees.","family":"w2-solar_tracker_geometry-horizontal-axis-true-tracking-axis-azimuth-units","id":"FA-93366","implementations":{"attempt":{"sha256":"364f29ca008e9f25c156509a9b25722e73182c9951241fc41cfb0483feda3c34","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(sun_az, sun_el, axis_az, max_angle):\n    if sun_el <= 0:\n        return [0.0, 'night']\n    az = math.radians(sun_az)\n    el = math.radians(sun_el)\n    e = math.cos(el) * math.sin(az)\n    n = math.cos(el) * math.cos(az)\n    u = math.sin(el)\n    pa = math.radians(axis_az) + 90\n    perp = e * math.sin(pa) + n * math.cos(pa)\n    rot = math.degrees(math.atan2(perp, u))\n    status = 'tracking'\n    if abs(rot) > max_angle:\n        rot = math.copysign(max_angle, rot)\n        status = 'limited'\n    return [round(rot, 3), status]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],\n  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],\n  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],\n  ['regression: axis azimuth units', [30, 10, 180, 55], [-55.0, 'limited']],\n  ['regression: axis azimuth units (partial repair)', [315, 75, 20, 45], [-13.65, 'tracking']],\n  ['control 1', [150, 10, 190, 45], [-45.0, 'limited']],\n  ['control 2', [180, 89, 0, 55], [0.0, 'tracking']]],\n [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],\n  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],\n  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],\n  ['regression: axis azimuth units', [90, 60, 0, 60], [30.0, 'tracking']],\n  ['regression: axis azimuth units (partial repair)', [200, 10, 190, 55], [44.561, 'tracking']],\n  ['control 1', [60, 0, 20, 45], [0.0, 'night']],\n  ['control 2', [340, 60, 170, 45], [5.725, 'tracking']]],\n [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],\n  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],\n  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],\n  ['regression: axis azimuth units', [0, 10, 190, 60], [44.561, 'tracking']],\n  ['regression: axis azimuth units (partial repair)', [300, 45, 20, 45], [-44.561, 'tracking']],\n  ['control 1', [135, 0, 0, 60], [0.0, 'night']],\n  ['control 2', [60, 20, 170, 55], [-55.0, 'limited']]],\n [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],\n  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],\n  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],\n  ['regression: axis azimuth units', [45, 10, 20, 45], [45.0, 'limited']],\n  ['regression: axis azimuth units (partial repair)', [270, 75, 0, 60], [-15.0, 'tracking']],\n  ['control 1', [90, 20, 0, 60], [60.0, 'limited']],\n  ['control 2', [30, 3, 190, 45], [-45.0, 'limited']]],\n [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],\n  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],\n  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],\n  ['regression: axis azimuth units', [30, 20, 170, 45], [-45.0, 'limited']],\n  ['regression: axis azimuth units (partial repair)', [150, 89, 180, 60], [-0.5, 'tracking']],\n  ['control 1', [100, 3, 190, 60], [-60.0, 'limited']],\n  ['control 2', [90, 75, 170, 55], [-14.782, 'tracking']]]]\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":"2c34214a89f7b364ef10cffec5607a8170722880679a3615858183905d039cab","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(sun_az, sun_el, axis_az, max_angle):\n    if sun_el <= 0:\n        return [0.0, 'night']\n    az = math.radians(sun_az)\n    el = math.radians(sun_el)\n    e = math.cos(el) * math.sin(az)\n    n = math.cos(el) * math.cos(az)\n    u = math.sin(el)\n    pa = axis_az + 90\n    perp = e * math.sin(pa) + n * math.cos(pa)\n    rot = math.degrees(math.atan2(perp, u))\n    status = 'tracking'\n    if abs(rot) > max_angle:\n        rot = math.copysign(max_angle, rot)\n        status = 'limited'\n    return [round(rot, 3), status]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],\n  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],\n  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],\n  ['regression: axis azimuth units', [30, 10, 180, 55], [-55.0, 'limited']],\n  ['regression: axis azimuth units (partial repair)', [315, 75, 20, 45], [-13.65, 'tracking']],\n  ['control 1', [150, 10, 190, 45], [-45.0, 'limited']],\n  ['control 2', [180, 89, 0, 55], [0.0, 'tracking']]],\n [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],\n  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],\n  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],\n  ['regression: axis azimuth units', [90, 60, 0, 60], [30.0, 'tracking']],\n  ['regression: axis azimuth units (partial repair)', [200, 10, 190, 55], [44.561, 'tracking']],\n  ['control 1', [60, 0, 20, 45], [0.0, 'night']],\n  ['control 2', [340, 60, 170, 45], [5.725, 'tracking']]],\n [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],\n  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],\n  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],\n  ['regression: axis azimuth units', [0, 10, 190, 60], [44.561, 'tracking']],\n  ['regression: axis azimuth units (partial repair)', [300, 45, 20, 45], [-44.561, 'tracking']],\n  ['control 1', [135, 0, 0, 60], [0.0, 'night']],\n  ['control 2', [60, 20, 170, 55], [-55.0, 'limited']]],\n [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],\n  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],\n  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],\n  ['regression: axis azimuth units', [45, 10, 20, 45], [45.0, 'limited']],\n  ['regression: axis azimuth units (partial repair)', [270, 75, 0, 60], [-15.0, 'tracking']],\n  ['control 1', [90, 20, 0, 60], [60.0, 'limited']],\n  ['control 2', [30, 3, 190, 45], [-45.0, 'limited']]],\n [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],\n  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],\n  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],\n  ['regression: axis azimuth units', [30, 20, 170, 45], [-45.0, 'limited']],\n  ['regression: axis azimuth units (partial repair)', [150, 89, 180, 60], [-0.5, 'tracking']],\n  ['control 1', [100, 3, 190, 60], [-60.0, 'limited']],\n  ['control 2', [90, 75, 170, 55], [-14.782, 'tracking']]]]\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":"5ec1a9a648bb3c9d05a77b4fe4c1bc75ae694d1f8d22ededdea16cf0b9ea01cb","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(sun_az, sun_el, axis_az, max_angle):\n    if sun_el <= 0:\n        return [0.0, 'night']\n    az = math.radians(sun_az)\n    el = math.radians(sun_el)\n    e = math.cos(el) * math.sin(az)\n    n = math.cos(el) * math.cos(az)\n    u = math.sin(el)\n    pa = math.radians(axis_az + 90)\n    perp = e * math.sin(pa) + n * math.cos(pa)\n    rot = math.degrees(math.atan2(perp, u))\n    status = 'tracking'\n    if abs(rot) > max_angle:\n        rot = math.copysign(max_angle, rot)\n        status = 'limited'\n    return [round(rot, 3), status]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],\n  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],\n  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],\n  ['regression: axis azimuth units', [30, 10, 180, 55], [-55.0, 'limited']],\n  ['regression: axis azimuth units (partial repair)', [315, 75, 20, 45], [-13.65, 'tracking']],\n  ['control 1', [150, 10, 190, 45], [-45.0, 'limited']],\n  ['control 2', [180, 89, 0, 55], [0.0, 'tracking']]],\n [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],\n  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],\n  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],\n  ['regression: axis azimuth units', [90, 60, 0, 60], [30.0, 'tracking']],\n  ['regression: axis azimuth units (partial repair)', [200, 10, 190, 55], [44.561, 'tracking']],\n  ['control 1', [60, 0, 20, 45], [0.0, 'night']],\n  ['control 2', [340, 60, 170, 45], [5.725, 'tracking']]],\n [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],\n  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],\n  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],\n  ['regression: axis azimuth units', [0, 10, 190, 60], [44.561, 'tracking']],\n  ['regression: axis azimuth units (partial repair)', [300, 45, 20, 45], [-44.561, 'tracking']],\n  ['control 1', [135, 0, 0, 60], [0.0, 'night']],\n  ['control 2', [60, 20, 170, 55], [-55.0, 'limited']]],\n [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],\n  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],\n  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],\n  ['regression: axis azimuth units', [45, 10, 20, 45], [45.0, 'limited']],\n  ['regression: axis azimuth units (partial repair)', [270, 75, 0, 60], [-15.0, 'tracking']],\n  ['control 1', [90, 20, 0, 60], [60.0, 'limited']],\n  ['control 2', [30, 3, 190, 45], [-45.0, 'limited']]],\n [['boundary: sun on the horizon', [90, 0, 180, 60], [0.0, 'night']],\n  ['normal: solar noon on N-S axis', [180, 60, 180, 60], [0.0, 'tracking']],\n  ['boundary: low morning sun hits east limit', [90, 10, 180, 60], [-60.0, 'limited']],\n  ['regression: axis azimuth units', [30, 20, 170, 45], [-45.0, 'limited']],\n  ['regression: axis azimuth units (partial repair)', [150, 89, 180, 60], [-0.5, 'tracking']],\n  ['control 1', [100, 3, 190, 60], [-60.0, 'limited']],\n  ['control 2', [90, 75, 170, 55], [-14.782, 'tracking']]]]\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-horizontal-axis-true-tracking-axis-azimuth-units","generated_at":"2026-09-29T14:51:54.438434+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":"Convert axis_az + 90 to radians.","root_cause":"The axis azimuth in degrees is used as radians.","sha256":"ca850425076fab103bdcdf419a32358df8f830e2ebb6f9b0ba8b7f9ceb01d205","title":"Horizontal single-axis true tracking: axis azimuth units · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":37.825,"exit_code":1,"observations":[{"actual":[0.0,"night"],"check":"boundary: sun on the horizon","expected":[0.0,"night"],"passed":true},{"actual":[-14.504,"tracking"],"check":"normal: solar noon on N-S axis","expected":[0.0,"tracking"],"passed":false},{"actual":[-60.0,"limited"],"check":"boundary: low morning sun hits east limit","expected":[-60.0,"limited"],"passed":true},{"actual":[-18.487,"tracking"],"check":"regression: axis azimuth units","expected":[-55.0,"limited"],"passed":false},{"actual":[-14.994,"tracking"],"check":"regression: axis azimuth units (partial repair)","expected":[-13.65,"tracking"],"passed":false},{"actual":[-45.0,"limited"],"check":"control 1","expected":[-45.0,"limited"],"passed":true},{"actual":[0.448,"tracking"],"check":"control 2","expected":[0.0,"tracking"],"passed":false}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"boundary: sun on the horizon\", \"actual\": [0.0, \"night\"], \"expected\": [0.0, \"night\"], \"passed\": true}, {\"check\": \"normal: solar noon on N-S axis\", \"actual\": [-14.504, \"tracking\"], \"expected\": [0.0, \"tracking\"], \"passed\": false}, {\"check\": \"boundary: low morning sun hits east limit\", \"actual\": [-60.0, \"limited\"], \"expected\": [-60.0, \"limited\"], \"passed\": true}, {\"check\": \"regression: axis azimuth units\", \"actual\": [-18.487, \"tracking\"], \"expected\": [-55.0, \"limited\"], \"passed\": false}, {\"check\": \"regression: axis azimuth units (partial repair)\", \"actual\": [-14.994, \"tracking\"], \"expected\": [-13.65, \"tracking\"], \"passed\": false}, {\"check\": \"control 1\", \"actual\": [-45.0, \"limited\"], \"expected\": [-45.0, \"limited\"], \"passed\": true}, {\"check\": \"control 2\", \"actual\": [0.448, \"tracking\"], \"expected\": [0.0, \"tracking\"], \"passed\": false}], \"passed\": false}\n"},"broken":{"elapsed_ms":40.631,"exit_code":1,"observations":[{"actual":[0.0,"night"],"check":"boundary: sun on the horizon","expected":[0.0,"night"],"passed":true},{"actual":[-29.611,"tracking"],"check":"normal: solar noon on N-S axis","expected":[0.0,"tracking"],"passed":false},{"actual":[-44.954,"tracking"],"check":"boundary: low morning sun hits east limit","expected":[-60.0,"limited"],"passed":false},{"actual":[55.0,"limited"],"check":"regression: axis azimuth units","expected":[-55.0,"limited"],"passed":false},{"actual":[-10.254,"tracking"],"check":"regression: axis azimuth units (partial repair)","expected":[-13.65,"tracking"],"passed":false},{"actual":[45.0,"limited"],"check":"control 1","expected":[-45.0,"limited"],"passed":false},{"actual":[0.448,"tracking"],"check":"control 2","expected":[0.0,"tracking"],"passed":false}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"boundary: sun on the horizon\", \"actual\": [0.0, \"night\"], \"expected\": [0.0, \"night\"], \"passed\": true}, {\"check\": \"normal: solar noon on N-S axis\", \"actual\": [-29.611, \"tracking\"], \"expected\": [0.0, \"tracking\"], \"passed\": false}, {\"check\": \"boundary: low morning sun hits east limit\", \"actual\": [-44.954, \"tracking\"], \"expected\": [-60.0, \"limited\"], \"passed\": false}, {\"check\": \"regression: axis azimuth units\", \"actual\": [55.0, \"limited\"], \"expected\": [-55.0, \"limited\"], \"passed\": false}, {\"check\": \"regression: axis azimuth units (partial repair)\", \"actual\": [-10.254, \"tracking\"], \"expected\": [-13.65, \"tracking\"], \"passed\": false}, {\"check\": \"control 1\", \"actual\": [45.0, \"limited\"], \"expected\": [-45.0, \"limited\"], \"passed\": false}, {\"check\": \"control 2\", \"actual\": [0.448, \"tracking\"], \"expected\": [0.0, \"tracking\"], \"passed\": false}], \"passed\": false}\n"},"fixed":{"elapsed_ms":40.443,"exit_code":0,"observations":[{"actual":[0.0,"night"],"check":"boundary: sun on the horizon","expected":[0.0,"night"],"passed":true},{"actual":[0.0,"tracking"],"check":"normal: solar noon on N-S axis","expected":[0.0,"tracking"],"passed":true},{"actual":[-60.0,"limited"],"check":"boundary: low morning sun hits east limit","expected":[-60.0,"limited"],"passed":true},{"actual":[-55.0,"limited"],"check":"regression: axis azimuth units","expected":[-55.0,"limited"],"passed":true},{"actual":[-13.65,"tracking"],"check":"regression: axis azimuth units (partial repair)","expected":[-13.65,"tracking"],"passed":true},{"actual":[-45.0,"limited"],"check":"control 1","expected":[-45.0,"limited"],"passed":true},{"actual":[0.0,"tracking"],"check":"control 2","expected":[0.0,"tracking"],"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"boundary: sun on the horizon\", \"actual\": [0.0, \"night\"], \"expected\": [0.0, \"night\"], \"passed\": true}, {\"check\": \"normal: solar noon on N-S axis\", \"actual\": [0.0, \"tracking\"], \"expected\": [0.0, \"tracking\"], \"passed\": true}, {\"check\": \"boundary: low morning sun hits east limit\", \"actual\": [-60.0, \"limited\"], \"expected\": [-60.0, \"limited\"], \"passed\": true}, {\"check\": \"regression: axis azimuth units\", \"actual\": [-55.0, \"limited\"], \"expected\": [-55.0, \"limited\"], \"passed\": true}, {\"check\": \"regression: axis azimuth units (partial repair)\", \"actual\": [-13.65, \"tracking\"], \"expected\": [-13.65, \"tracking\"], \"passed\": true}, {\"check\": \"control 1\", \"actual\": [-45.0, \"limited\"], \"expected\": [-45.0, \"limited\"], \"passed\": true}, {\"check\": \"control 2\", \"actual\": [0.0, \"tracking\"], \"expected\": [0.0, \"tracking\"], \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}