{"abstract":"Elbow angles are wrong everywhere except at unit radius.","category":"Inverse kinematics solvers","checks":7,"contract":"Input [l1,l2,d0,stroke,px,py,pz,yaw,arm]. The quill extends downward: d3=d0-pz must lie in [0,stroke] else \"out-of-stroke\" (checked first). Planar reach uses cos t2=(px^2+py^2-l1^2-l2^2)/(2 l1 l2); |cos|>1 returns \"unreachable\". arm \"right\" takes t2<=0. Tool yaw (degrees) equals t1+t2+t4. Return [t1,t2,d3,t4] with angles in degrees wrapped to (-180,180], all rounded to 4 places.","contract_signature":"x","evaluation_group":"w2-inverse_kinematics_solvers-scara-arm","failed_approach":"Including pz^2 in the radius treats the vertical axis as part of the planar reach.","family":"w2-inverse_kinematics_solvers-scara-arm-planar-radius-squared","id":"FA-88046","implementations":{"attempt":{"sha256":"1b318910ec5b80942d4d6a7d00e97dcf2da592d94b37cf6d2d1f1c2b9a55bb63","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(x):\n    l1,l2,d0,stroke,px,py,pz,yaw,arm=x\n    d3=d0-pz\n    if d3<0 or d3>stroke: return 'out-of-stroke'\n    r2=px*px+py*py+pz*pz\n    c=(r2-l1*l1-l2*l2)/(2.0*l1*l2)\n    if c>1.0 or c<-1.0: return 'unreachable'\n    s=math.sqrt(1.0-c*c)\n    if arm=='right': s=-s\n    t2=math.atan2(s,c)\n    t1=math.atan2(py,px)-math.atan2(l2*s,l1+l2*c)\n    t4=math.radians(yaw)-t1-t2\n    res=[]\n    for t in (t1,t2,t4):\n        d=math.degrees(t)\n        while d>180.0: d-=360.0\n        while d<=-180.0: d+=360.0\n        res.append(round(d,4))\n    return [res[0],res[1],round(d3,4),res[2]]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['left arm nominal', [[4, 3, 10, 8, 5, 2, 6, 30, 'left']], [-11.5172, 80.4059, 4, -38.8887]], ['right arm nominal', [[4, 3, 10, 8, 5, 2, 6, 30, 'right']], [55.12, -80.4059, 4, 55.2859]], ['quill fully retracted', [[4, 3, 10, 8, 3, 4, 10, 0, 'left']], [16.2602, 90.0, 0, -106.2602]], ['quill fully extended', [[4, 3, 10, 8, 3, 4, 2, 0, 'right']], [90.0, -90.0, 8, 0.0]], ['target above quill home', [[4, 3, 10, 8, 3, 4, 12, 0, 'left']], 'out-of-stroke'], ['below stroke', [[4, 3, 10, 8, 3, 4, 1, 0, 'left']], 'out-of-stroke'], ['out of stroke and reach', [[4, 3, 10, 8, 9, 0, 12, 0, 'left']], 'out-of-stroke']], [['right arm nominal', [[4, 3, 10, 8, 5, 2, 6, 30, 'right']], [55.12, -80.4059, 4, 55.2859]], ['target above quill home', [[4, 3, 10, 8, 3, 4, 12, 0, 'left']], 'out-of-stroke'], ['below stroke', [[4, 3, 10, 8, 3, 4, 1, 0, 'left']], 'out-of-stroke'], ['out of stroke and reach', [[4, 3, 10, 8, 9, 0, 12, 0, 'left']], 'out-of-stroke'], ['out of reach only', [[4, 3, 10, 8, 9, 0, 5, 0, 'left']], 'unreachable'], ['fully stretched', [[4, 3, 10, 8, 7, 0, 5, 45, 'left']], [0.0, 0.0, 5, 45.0]], ['multi-turn yaw', [[4, 3, 10, 8, -2, 5, 4, 720, 'right']], [145.12, -80.4059, 6, -64.7141]]], [['quill fully retracted', [[4, 3, 10, 8, 3, 4, 10, 0, 'left']], [16.2602, 90.0, 0, -106.2602]], ['out of reach only', [[4, 3, 10, 8, 9, 0, 5, 0, 'left']], 'unreachable'], ['fully stretched', [[4, 3, 10, 8, 7, 0, 5, 45, 'left']], [0.0, 0.0, 5, 45.0]], ['multi-turn yaw', [[4, 3, 10, 8, -2, 5, 4, 720, 'right']], [145.12, -80.4059, 6, -64.7141]], ['negative yaw', [[4, 3, 10, 8, -4, -3, 4, -170, 'left']], [180.0, 90.0, 6, -80.0]], ['yaw 180 seam', [[4, 3, 10, 8, 0, 6, 7, 180, 'right']], [116.3843, -62.7204, 3, 126.3361]], ['reach between r and r2', [[1, 1, 10, 8, 1.2, 1.1, 5, 0, 'left']], [6.9932, 71.0344, 5, -78.0277]]], [['quill fully extended', [[4, 3, 10, 8, 3, 4, 2, 0, 'right']], [90.0, -90.0, 8, 0.0]], ['negative yaw', [[4, 3, 10, 8, -4, -3, 4, -170, 'left']], [180.0, 90.0, 6, -80.0]], ['yaw 180 seam', [[4, 3, 10, 8, 0, 6, 7, 180, 'right']], [116.3843, -62.7204, 3, 126.3361]], ['reach between r and r2', [[1, 1, 10, 8, 1.2, 1.1, 5, 0, 'left']], [6.9932, 71.0344, 5, -78.0277]], ['back quadrant', [[5, 4, 10, 8, -6, -2, 3, 250, 'right']], [-122.3482, -91.4325, 7, 103.7807]], ['near base hole', [[4, 3, 10, 8, 0.5, 0.2, 5, 0, 'left']], 'unreachable'], ['yaw -540', [[4, 3, 10, 8, 2, -5, 9, -540, 'left']], [-101.5172, 80.4059, 1, -158.8887]]], [['left arm nominal', [[4, 3, 10, 8, 5, 2, 6, 30, 'left']], [-11.5172, 80.4059, 4, -38.8887]], ['right arm nominal', [[4, 3, 10, 8, 5, 2, 6, 30, 'right']], [55.12, -80.4059, 4, 55.2859]], ['quill fully retracted', [[4, 3, 10, 8, 3, 4, 10, 0, 'left']], [16.2602, 90.0, 0, -106.2602]], ['out of reach only', [[4, 3, 10, 8, 9, 0, 5, 0, 'left']], 'unreachable'], ['fully stretched', [[4, 3, 10, 8, 7, 0, 5, 45, 'left']], [0.0, 0.0, 5, 45.0]], ['near base hole', [[4, 3, 10, 8, 0.5, 0.2, 5, 0, 'left']], 'unreachable'], ['yaw -540', [[4, 3, 10, 8, 2, -5, 9, -540, 'left']], [-101.5172, 80.4059, 1, -158.8887]]]]\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":"4ad3598d698035e0aaa1d6bc5d74c658d03bd713c5ea9cccddfc3ba63f4aa76d","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(x):\n    l1,l2,d0,stroke,px,py,pz,yaw,arm=x\n    d3=d0-pz\n    if d3<0 or d3>stroke: return 'out-of-stroke'\n    r2=math.hypot(px,py)\n    c=(r2-l1*l1-l2*l2)/(2.0*l1*l2)\n    if c>1.0 or c<-1.0: return 'unreachable'\n    s=math.sqrt(1.0-c*c)\n    if arm=='right': s=-s\n    t2=math.atan2(s,c)\n    t1=math.atan2(py,px)-math.atan2(l2*s,l1+l2*c)\n    t4=math.radians(yaw)-t1-t2\n    res=[]\n    for t in (t1,t2,t4):\n        d=math.degrees(t)\n        while d>180.0: d-=360.0\n        while d<=-180.0: d+=360.0\n        res.append(round(d,4))\n    return [res[0],res[1],round(d3,4),res[2]]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['left arm nominal', [[4, 3, 10, 8, 5, 2, 6, 30, 'left']], [-11.5172, 80.4059, 4, -38.8887]], ['right arm nominal', [[4, 3, 10, 8, 5, 2, 6, 30, 'right']], [55.12, -80.4059, 4, 55.2859]], ['quill fully retracted', [[4, 3, 10, 8, 3, 4, 10, 0, 'left']], [16.2602, 90.0, 0, -106.2602]], ['quill fully extended', [[4, 3, 10, 8, 3, 4, 2, 0, 'right']], [90.0, -90.0, 8, 0.0]], ['target above quill home', [[4, 3, 10, 8, 3, 4, 12, 0, 'left']], 'out-of-stroke'], ['below stroke', [[4, 3, 10, 8, 3, 4, 1, 0, 'left']], 'out-of-stroke'], ['out of stroke and reach', [[4, 3, 10, 8, 9, 0, 12, 0, 'left']], 'out-of-stroke']], [['right arm nominal', [[4, 3, 10, 8, 5, 2, 6, 30, 'right']], [55.12, -80.4059, 4, 55.2859]], ['target above quill home', [[4, 3, 10, 8, 3, 4, 12, 0, 'left']], 'out-of-stroke'], ['below stroke', [[4, 3, 10, 8, 3, 4, 1, 0, 'left']], 'out-of-stroke'], ['out of stroke and reach', [[4, 3, 10, 8, 9, 0, 12, 0, 'left']], 'out-of-stroke'], ['out of reach only', [[4, 3, 10, 8, 9, 0, 5, 0, 'left']], 'unreachable'], ['fully stretched', [[4, 3, 10, 8, 7, 0, 5, 45, 'left']], [0.0, 0.0, 5, 45.0]], ['multi-turn yaw', [[4, 3, 10, 8, -2, 5, 4, 720, 'right']], [145.12, -80.4059, 6, -64.7141]]], [['quill fully retracted', [[4, 3, 10, 8, 3, 4, 10, 0, 'left']], [16.2602, 90.0, 0, -106.2602]], ['out of reach only', [[4, 3, 10, 8, 9, 0, 5, 0, 'left']], 'unreachable'], ['fully stretched', [[4, 3, 10, 8, 7, 0, 5, 45, 'left']], [0.0, 0.0, 5, 45.0]], ['multi-turn yaw', [[4, 3, 10, 8, -2, 5, 4, 720, 'right']], [145.12, -80.4059, 6, -64.7141]], ['negative yaw', [[4, 3, 10, 8, -4, -3, 4, -170, 'left']], [180.0, 90.0, 6, -80.0]], ['yaw 180 seam', [[4, 3, 10, 8, 0, 6, 7, 180, 'right']], [116.3843, -62.7204, 3, 126.3361]], ['reach between r and r2', [[1, 1, 10, 8, 1.2, 1.1, 5, 0, 'left']], [6.9932, 71.0344, 5, -78.0277]]], [['quill fully extended', [[4, 3, 10, 8, 3, 4, 2, 0, 'right']], [90.0, -90.0, 8, 0.0]], ['negative yaw', [[4, 3, 10, 8, -4, -3, 4, -170, 'left']], [180.0, 90.0, 6, -80.0]], ['yaw 180 seam', [[4, 3, 10, 8, 0, 6, 7, 180, 'right']], [116.3843, -62.7204, 3, 126.3361]], ['reach between r and r2', [[1, 1, 10, 8, 1.2, 1.1, 5, 0, 'left']], [6.9932, 71.0344, 5, -78.0277]], ['back quadrant', [[5, 4, 10, 8, -6, -2, 3, 250, 'right']], [-122.3482, -91.4325, 7, 103.7807]], ['near base hole', [[4, 3, 10, 8, 0.5, 0.2, 5, 0, 'left']], 'unreachable'], ['yaw -540', [[4, 3, 10, 8, 2, -5, 9, -540, 'left']], [-101.5172, 80.4059, 1, -158.8887]]], [['left arm nominal', [[4, 3, 10, 8, 5, 2, 6, 30, 'left']], [-11.5172, 80.4059, 4, -38.8887]], ['right arm nominal', [[4, 3, 10, 8, 5, 2, 6, 30, 'right']], [55.12, -80.4059, 4, 55.2859]], ['quill fully retracted', [[4, 3, 10, 8, 3, 4, 10, 0, 'left']], [16.2602, 90.0, 0, -106.2602]], ['out of reach only', [[4, 3, 10, 8, 9, 0, 5, 0, 'left']], 'unreachable'], ['fully stretched', [[4, 3, 10, 8, 7, 0, 5, 45, 'left']], [0.0, 0.0, 5, 45.0]], ['near base hole', [[4, 3, 10, 8, 0.5, 0.2, 5, 0, 'left']], 'unreachable'], ['yaw -540', [[4, 3, 10, 8, 2, -5, 9, -540, 'left']], [-101.5172, 80.4059, 1, -158.8887]]]]\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 planar or low-dimensional teaching model with a stipulated convention; not a general robotics library. 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-inverse_kinematics_solvers-scara-arm-planar-radius-squared","generated_at":"2026-09-29T14:51:04.520390+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Inverse kinematics code turns task-space goals into joint commands; a wrong branch, sign, limit or update order sends a real arm to the wrong pose.","root_cause":"r2 is computed with hypot, so the cosine formula mixes a length with squared lengths.","sha256":"ccbe774bf1cb9cf49a9fe228c86feac78cbf1ce2814f23c4e90147f1bb381dd1","title":"SCARA law of cosines receives the radius instead of its square · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verified":true,"visibility":"public","verification":{"attempt":{"elapsed_ms":39.02,"exit_code":1,"observations":[{"actual":"unreachable","check":"left arm nominal","expected":[-11.5172,80.4059,4,-38.8887],"passed":false},{"actual":"unreachable","check":"right arm nominal","expected":[55.12,-80.4059,4,55.2859],"passed":false},{"actual":"unreachable","check":"quill fully retracted","expected":[16.2602,90.0,0,-106.2602],"passed":false},{"actual":[86.4487,-80.4059,8,-6.0428],"check":"quill fully extended","expected":[90.0,-90.0,8,0.0],"passed":false},{"actual":"out-of-stroke","check":"target above quill home","expected":"out-of-stroke","passed":true},{"actual":"out-of-stroke","check":"below stroke","expected":"out-of-stroke","passed":true},{"actual":"out-of-stroke","check":"out of stroke and reach","expected":"out-of-stroke","passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"left arm nominal\", \"actual\": \"unreachable\", \"expected\": [-11.5172, 80.4059, 4, -38.8887], \"passed\": false}, {\"check\": \"right arm nominal\", \"actual\": \"unreachable\", \"expected\": [55.12, -80.4059, 4, 55.2859], \"passed\": false}, {\"check\": \"quill fully retracted\", \"actual\": \"unreachable\", \"expected\": [16.2602, 90.0, 0, -106.2602], \"passed\": false}, {\"check\": \"quill fully extended\", \"actual\": [86.4487, -80.4059, 8, -6.0428], \"expected\": [90.0, -90.0, 8, 0.0], \"passed\": false}, {\"check\": \"target above quill home\", \"actual\": \"out-of-stroke\", \"expected\": \"out-of-stroke\", \"passed\": true}, {\"check\": \"below stroke\", \"actual\": \"out-of-stroke\", \"expected\": \"out-of-stroke\", \"passed\": true}, {\"check\": \"out of stroke and reach\", \"actual\": \"out-of-stroke\", \"expected\": \"out-of-stroke\", \"passed\": true}], \"passed\": false}\n"},"broken":{"elapsed_ms":40.127,"exit_code":1,"observations":[{"actual":[-26.3524,144.8139,4,-88.4615],"check":"left arm nominal","expected":[-11.5172,80.4059,4,-38.8887],"passed":false},{"actual":[69.9553,-144.8139,4,104.8587],"check":"right arm nominal","expected":[55.12,-80.4059,4,55.2859],"passed":false},{"actual":[5.2605,146.4427,0,-151.7032],"check":"quill fully retracted","expected":[16.2602,90.0,0,-106.2602],"passed":false},{"actual":[100.9997,-146.4427,8,45.443],"check":"quill fully extended","expected":[90.0,-90.0,8,0.0],"passed":false},{"actual":"out-of-stroke","check":"target above quill home","expected":"out-of-stroke","passed":true},{"actual":"out-of-stroke","check":"below stroke","expected":"out-of-stroke","passed":true},{"actual":"out-of-stroke","check":"out of stroke and reach","expected":"out-of-stroke","passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"left arm nominal\", \"actual\": [-26.3524, 144.8139, 4, -88.4615], \"expected\": [-11.5172, 80.4059, 4, -38.8887], \"passed\": false}, {\"check\": \"right arm nominal\", \"actual\": [69.9553, -144.8139, 4, 104.8587], \"expected\": [55.12, -80.4059, 4, 55.2859], \"passed\": false}, {\"check\": \"quill fully retracted\", \"actual\": [5.2605, 146.4427, 0, -151.7032], \"expected\": [16.2602, 90.0, 0, -106.2602], \"passed\": false}, {\"check\": \"quill fully extended\", \"actual\": [100.9997, -146.4427, 8, 45.443], \"expected\": [90.0, -90.0, 8, 0.0], \"passed\": false}, {\"check\": \"target above quill home\", \"actual\": \"out-of-stroke\", \"expected\": \"out-of-stroke\", \"passed\": true}, {\"check\": \"below stroke\", \"actual\": \"out-of-stroke\", \"expected\": \"out-of-stroke\", \"passed\": true}, {\"check\": \"out of stroke and reach\", \"actual\": \"out-of-stroke\", \"expected\": \"out-of-stroke\", \"passed\": true}], \"passed\": false}\n"}},"member_only":{"stages":["fixed"],"fields":["implementations.fixed","verification.fixed","harness","repair"],"note":"The verified repair, its recorded checks, the repair description, and the scoring harness are available to members."}}