{"abstract":"The shoulder points past the target by twice the forearm offset angle.","category":"Inverse kinematics solvers","checks":7,"contract":"Input [l1,l2,px,py,elbow] with positive link lengths. Return [q1,q2] in degrees (4 decimals) for a planar two-link arm whose end effector reaches (px,py); elbow \"up\" gives q2>=0, \"down\" gives q2<=0; q1 is wrapped to [-180,180). Points outside the annulus |l1-l2|<=r<=l1+l2 (1e-9 slack on r squared) return \"unreachable\".","evaluation_group":"w2-inverse_kinematics_solvers-two-link-analytic","failed_approach":"Swapping sine and cosine inside the offset atan2 measures the offset from the wrong axis.","family":"w2-inverse_kinematics_solvers-two-link-analytic-shoulder-offset-angle","id":"FA-87861","implementations":{"attempt":{"sha256":"b86c7dc970b2113318dbc3278901b9ef38f6ad8047f26e542d7427f0e5ec26ae","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(x):\n    l1,l2,px,py,elbow=x\n    r2=px*px+py*py\n    reach=l1+l2\n    if r2>reach*reach+1e-9: return 'unreachable'\n    if r2<(l1-l2)**2-1e-9: return 'unreachable'\n    c=(r2-l1*l1-l2*l2)/(2*l1*l2)\n    c=max(-1.0,min(1.0,c))\n    s=math.sqrt(1-c*c)\n    if elbow=='down': s=-s\n    q2=math.atan2(s,c)\n    q1=math.atan2(py,px)-math.atan2(l2*c,l1+l2*s)\n    d1=math.degrees(q1)\n    d1=(d1+180.0)%360.0-180.0\n    return [round(d1,4),round(math.degrees(q2),4)]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['general elbow up', [[2, 1, 2, 1, 'up']], [0.0, 90.0]], ['general elbow down', [[2, 1, 2, 1, 'down']], [53.1301, -90.0]], ['fully extended on x axis', [[2, 1, 3, 0, 'up']], [0.0, 0.0]], ['fully extended diagonal', [[3, 4, 4.2, 5.6, 'up']], [53.1301, 0.0]], ['outside workspace', [[2, 1, 3, 1, 'up']], 'unreachable'], ['between reach and reach squared', [[1, 1, 1.9, 1.2, 'up']], 'unreachable'], ['inside inner hole', [[3, 1, 1, 0, 'up']], 'unreachable']], [['general elbow down', [[2, 1, 2, 1, 'down']], [53.1301, -90.0]], ['outside workspace', [[2, 1, 3, 1, 'up']], 'unreachable'], ['between reach and reach squared', [[1, 1, 1.9, 1.2, 'up']], 'unreachable'], ['inside inner hole', [[3, 1, 1, 0, 'up']], 'unreachable'], ['inner boundary folded', [[3, 1, 2, 0, 'down']], [0.0, -180.0]], ['third quadrant target', [[2, 2, -2, -1, 'up']], [150.5529, 112.0243]], ['second quadrant target', [[2, 1.5, -2, 1, 'down']], [-165.5619, -102.0247]]], [['fully extended on x axis', [[2, 1, 3, 0, 'up']], [0.0, 0.0]], ['inner boundary folded', [[3, 1, 2, 0, 'down']], [0.0, -180.0]], ['third quadrant target', [[2, 2, -2, -1, 'up']], [150.5529, 112.0243]], ['second quadrant target', [[2, 1.5, -2, 1, 'down']], [-165.5619, -102.0247]], ['negative y axis', [[1.5, 1, 0, -2, 'up']], [-118.955, 75.5225]], ['behind base elbow down', [[2, 1, -2.5, -0.5, 'down']], [-147.3681, -67.9757]], ['equal links near base', [[1, 1, 0.5, 0.2, 'up']], [-52.5785, 148.7597]]], [['fully extended diagonal', [[3, 4, 4.2, 5.6, 'up']], [53.1301, 0.0]], ['second quadrant target', [[2, 1.5, -2, 1, 'down']], [-165.5619, -102.0247]], ['behind base elbow down', [[2, 1, -2.5, -0.5, 'down']], [-147.3681, -67.9757]], ['equal links near base', [[1, 1, 0.5, 0.2, 'up']], [-52.5785, 148.7597]], ['long forearm hole', [[1, 3, 0.5, 1, 'down']], 'unreachable'], ['long forearm reachable', [[1, 3, 2.5, 0.5, 'up']], [-95.7981, 125.6853]], ['positive y axis', [[2, 2, 0, 3, 'down']], [131.4096, -82.8192]]], [['inner boundary folded', [[3, 1, 2, 0, 'down']], [0.0, -180.0]], ['negative y axis', [[1.5, 1, 0, -2, 'up']], [-118.955, 75.5225]], ['long forearm reachable', [[1, 3, 2.5, 0.5, 'up']], [-95.7981, 125.6853]], ['positive y axis', [[2, 2, 0, 3, 'down']], [131.4096, -82.8192]], ['wrap past minus 180', [[1, 2, -2.2, -0.3, 'up']], [123.5259, 91.0027]], ['upper left down', [[3, 2, -1, 4, 'down']], [131.2512, -70.5288]], ['near full reach', [[5, 3, 7.9, 0.5, 'down']], [10.0523, -17.1893]]]]\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":"0b657171c43cf1231506a2bca2027af9bd7a8e10891b4b78e8f99b4e4a786cc5","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(x):\n    l1,l2,px,py,elbow=x\n    r2=px*px+py*py\n    reach=l1+l2\n    if r2>reach*reach+1e-9: return 'unreachable'\n    if r2<(l1-l2)**2-1e-9: return 'unreachable'\n    c=(r2-l1*l1-l2*l2)/(2*l1*l2)\n    c=max(-1.0,min(1.0,c))\n    s=math.sqrt(1-c*c)\n    if elbow=='down': s=-s\n    q2=math.atan2(s,c)\n    q1=math.atan2(py,px)+math.atan2(l2*s,l1+l2*c)\n    d1=math.degrees(q1)\n    d1=(d1+180.0)%360.0-180.0\n    return [round(d1,4),round(math.degrees(q2),4)]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['general elbow up', [[2, 1, 2, 1, 'up']], [0.0, 90.0]], ['general elbow down', [[2, 1, 2, 1, 'down']], [53.1301, -90.0]], ['fully extended on x axis', [[2, 1, 3, 0, 'up']], [0.0, 0.0]], ['fully extended diagonal', [[3, 4, 4.2, 5.6, 'up']], [53.1301, 0.0]], ['outside workspace', [[2, 1, 3, 1, 'up']], 'unreachable'], ['between reach and reach squared', [[1, 1, 1.9, 1.2, 'up']], 'unreachable'], ['inside inner hole', [[3, 1, 1, 0, 'up']], 'unreachable']], [['general elbow down', [[2, 1, 2, 1, 'down']], [53.1301, -90.0]], ['outside workspace', [[2, 1, 3, 1, 'up']], 'unreachable'], ['between reach and reach squared', [[1, 1, 1.9, 1.2, 'up']], 'unreachable'], ['inside inner hole', [[3, 1, 1, 0, 'up']], 'unreachable'], ['inner boundary folded', [[3, 1, 2, 0, 'down']], [0.0, -180.0]], ['third quadrant target', [[2, 2, -2, -1, 'up']], [150.5529, 112.0243]], ['second quadrant target', [[2, 1.5, -2, 1, 'down']], [-165.5619, -102.0247]]], [['fully extended on x axis', [[2, 1, 3, 0, 'up']], [0.0, 0.0]], ['inner boundary folded', [[3, 1, 2, 0, 'down']], [0.0, -180.0]], ['third quadrant target', [[2, 2, -2, -1, 'up']], [150.5529, 112.0243]], ['second quadrant target', [[2, 1.5, -2, 1, 'down']], [-165.5619, -102.0247]], ['negative y axis', [[1.5, 1, 0, -2, 'up']], [-118.955, 75.5225]], ['behind base elbow down', [[2, 1, -2.5, -0.5, 'down']], [-147.3681, -67.9757]], ['equal links near base', [[1, 1, 0.5, 0.2, 'up']], [-52.5785, 148.7597]]], [['fully extended diagonal', [[3, 4, 4.2, 5.6, 'up']], [53.1301, 0.0]], ['second quadrant target', [[2, 1.5, -2, 1, 'down']], [-165.5619, -102.0247]], ['behind base elbow down', [[2, 1, -2.5, -0.5, 'down']], [-147.3681, -67.9757]], ['equal links near base', [[1, 1, 0.5, 0.2, 'up']], [-52.5785, 148.7597]], ['long forearm hole', [[1, 3, 0.5, 1, 'down']], 'unreachable'], ['long forearm reachable', [[1, 3, 2.5, 0.5, 'up']], [-95.7981, 125.6853]], ['positive y axis', [[2, 2, 0, 3, 'down']], [131.4096, -82.8192]]], [['inner boundary folded', [[3, 1, 2, 0, 'down']], [0.0, -180.0]], ['negative y axis', [[1.5, 1, 0, -2, 'up']], [-118.955, 75.5225]], ['long forearm reachable', [[1, 3, 2.5, 0.5, 'up']], [-95.7981, 125.6853]], ['positive y axis', [[2, 2, 0, 3, 'down']], [131.4096, -82.8192]], ['wrap past minus 180', [[1, 2, -2.2, -0.3, 'up']], [123.5259, 91.0027]], ['upper left down', [[3, 2, -1, 4, 'down']], [131.2512, -70.5288]], ['near full reach', [[5, 3, 7.9, 0.5, 'down']], [10.0523, -17.1893]]]]\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":"a6c248822f8f3d89fa456d043f7e4b21b0215f39dee065750858981efd903b8b","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(x):\n    l1,l2,px,py,elbow=x\n    r2=px*px+py*py\n    reach=l1+l2\n    if r2>reach*reach+1e-9: return 'unreachable'\n    if r2<(l1-l2)**2-1e-9: return 'unreachable'\n    c=(r2-l1*l1-l2*l2)/(2*l1*l2)\n    c=max(-1.0,min(1.0,c))\n    s=math.sqrt(1-c*c)\n    if elbow=='down': s=-s\n    q2=math.atan2(s,c)\n    q1=math.atan2(py,px)-math.atan2(l2*s,l1+l2*c)\n    d1=math.degrees(q1)\n    d1=(d1+180.0)%360.0-180.0\n    return [round(d1,4),round(math.degrees(q2),4)]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['general elbow up', [[2, 1, 2, 1, 'up']], [0.0, 90.0]], ['general elbow down', [[2, 1, 2, 1, 'down']], [53.1301, -90.0]], ['fully extended on x axis', [[2, 1, 3, 0, 'up']], [0.0, 0.0]], ['fully extended diagonal', [[3, 4, 4.2, 5.6, 'up']], [53.1301, 0.0]], ['outside workspace', [[2, 1, 3, 1, 'up']], 'unreachable'], ['between reach and reach squared', [[1, 1, 1.9, 1.2, 'up']], 'unreachable'], ['inside inner hole', [[3, 1, 1, 0, 'up']], 'unreachable']], [['general elbow down', [[2, 1, 2, 1, 'down']], [53.1301, -90.0]], ['outside workspace', [[2, 1, 3, 1, 'up']], 'unreachable'], ['between reach and reach squared', [[1, 1, 1.9, 1.2, 'up']], 'unreachable'], ['inside inner hole', [[3, 1, 1, 0, 'up']], 'unreachable'], ['inner boundary folded', [[3, 1, 2, 0, 'down']], [0.0, -180.0]], ['third quadrant target', [[2, 2, -2, -1, 'up']], [150.5529, 112.0243]], ['second quadrant target', [[2, 1.5, -2, 1, 'down']], [-165.5619, -102.0247]]], [['fully extended on x axis', [[2, 1, 3, 0, 'up']], [0.0, 0.0]], ['inner boundary folded', [[3, 1, 2, 0, 'down']], [0.0, -180.0]], ['third quadrant target', [[2, 2, -2, -1, 'up']], [150.5529, 112.0243]], ['second quadrant target', [[2, 1.5, -2, 1, 'down']], [-165.5619, -102.0247]], ['negative y axis', [[1.5, 1, 0, -2, 'up']], [-118.955, 75.5225]], ['behind base elbow down', [[2, 1, -2.5, -0.5, 'down']], [-147.3681, -67.9757]], ['equal links near base', [[1, 1, 0.5, 0.2, 'up']], [-52.5785, 148.7597]]], [['fully extended diagonal', [[3, 4, 4.2, 5.6, 'up']], [53.1301, 0.0]], ['second quadrant target', [[2, 1.5, -2, 1, 'down']], [-165.5619, -102.0247]], ['behind base elbow down', [[2, 1, -2.5, -0.5, 'down']], [-147.3681, -67.9757]], ['equal links near base', [[1, 1, 0.5, 0.2, 'up']], [-52.5785, 148.7597]], ['long forearm hole', [[1, 3, 0.5, 1, 'down']], 'unreachable'], ['long forearm reachable', [[1, 3, 2.5, 0.5, 'up']], [-95.7981, 125.6853]], ['positive y axis', [[2, 2, 0, 3, 'down']], [131.4096, -82.8192]]], [['inner boundary folded', [[3, 1, 2, 0, 'down']], [0.0, -180.0]], ['negative y axis', [[1.5, 1, 0, -2, 'up']], [-118.955, 75.5225]], ['long forearm reachable', [[1, 3, 2.5, 0.5, 'up']], [-95.7981, 125.6853]], ['positive y axis', [[2, 2, 0, 3, 'down']], [131.4096, -82.8192]], ['wrap past minus 180', [[1, 2, -2.2, -0.3, 'up']], [123.5259, 91.0027]], ['upper left down', [[3, 2, -1, 4, 'down']], [131.2512, -70.5288]], ['near full reach', [[5, 3, 7.9, 0.5, 'down']], [10.0523, -17.1893]]]]\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-two-link-analytic-shoulder-offset-angle","generated_at":"2026-09-29T14:51:02.844649+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.","repair":"Subtract the offset angle atan2(l2 sin q2, l1+l2 cos q2) from the target bearing.","root_cause":"q1 is computed as atan2(py,px)+atan2(l2 s,l1+l2 c).","sha256":"c41e25dd7a866187f4c535f0b4d774755de0e2d7c2b527820faaecdf2d9ef748","title":"Shoulder angle adds the forearm offset instead of subtracting it · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":40.231,"exit_code":1,"observations":[{"actual":[26.5651,90.0],"check":"general elbow up","expected":[0.0,90.0],"passed":false},{"actual":[26.5651,-90.0],"check":"general elbow down","expected":[53.1301,-90.0],"passed":false},{"actual":[-26.5651,0.0],"check":"fully extended on x axis","expected":[0.0,0.0],"passed":false},{"actual":[0.0,0.0],"check":"fully extended diagonal","expected":[53.1301,0.0],"passed":false},{"actual":"unreachable","check":"outside workspace","expected":"unreachable","passed":true},{"actual":"unreachable","check":"between reach and reach squared","expected":"unreachable","passed":true},{"actual":"unreachable","check":"inside inner hole","expected":"unreachable","passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"general elbow up\", \"actual\": [26.5651, 90.0], \"expected\": [0.0, 90.0], \"passed\": false}, {\"check\": \"general elbow down\", \"actual\": [26.5651, -90.0], \"expected\": [53.1301, -90.0], \"passed\": false}, {\"check\": \"fully extended on x axis\", \"actual\": [-26.5651, 0.0], \"expected\": [0.0, 0.0], \"passed\": false}, {\"check\": \"fully extended diagonal\", \"actual\": [0.0, 0.0], \"expected\": [53.1301, 0.0], \"passed\": false}, {\"check\": \"outside workspace\", \"actual\": \"unreachable\", \"expected\": \"unreachable\", \"passed\": true}, {\"check\": \"between reach and reach squared\", \"actual\": \"unreachable\", \"expected\": \"unreachable\", \"passed\": true}, {\"check\": \"inside inner hole\", \"actual\": \"unreachable\", \"expected\": \"unreachable\", \"passed\": true}], \"passed\": false}\n"},"broken":{"elapsed_ms":40.402,"exit_code":1,"observations":[{"actual":[53.1301,90.0],"check":"general elbow up","expected":[0.0,90.0],"passed":false},{"actual":[0.0,-90.0],"check":"general elbow down","expected":[53.1301,-90.0],"passed":false},{"actual":[0.0,0.0],"check":"fully extended on x axis","expected":[0.0,0.0],"passed":true},{"actual":[53.1301,0.0],"check":"fully extended diagonal","expected":[53.1301,0.0],"passed":true},{"actual":"unreachable","check":"outside workspace","expected":"unreachable","passed":true},{"actual":"unreachable","check":"between reach and reach squared","expected":"unreachable","passed":true},{"actual":"unreachable","check":"inside inner hole","expected":"unreachable","passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"general elbow up\", \"actual\": [53.1301, 90.0], \"expected\": [0.0, 90.0], \"passed\": false}, {\"check\": \"general elbow down\", \"actual\": [0.0, -90.0], \"expected\": [53.1301, -90.0], \"passed\": false}, {\"check\": \"fully extended on x axis\", \"actual\": [0.0, 0.0], \"expected\": [0.0, 0.0], \"passed\": true}, {\"check\": \"fully extended diagonal\", \"actual\": [53.1301, 0.0], \"expected\": [53.1301, 0.0], \"passed\": true}, {\"check\": \"outside workspace\", \"actual\": \"unreachable\", \"expected\": \"unreachable\", \"passed\": true}, {\"check\": \"between reach and reach squared\", \"actual\": \"unreachable\", \"expected\": \"unreachable\", \"passed\": true}, {\"check\": \"inside inner hole\", \"actual\": \"unreachable\", \"expected\": \"unreachable\", \"passed\": true}], \"passed\": false}\n"},"fixed":{"elapsed_ms":37.242,"exit_code":0,"observations":[{"actual":[0.0,90.0],"check":"general elbow up","expected":[0.0,90.0],"passed":true},{"actual":[53.1301,-90.0],"check":"general elbow down","expected":[53.1301,-90.0],"passed":true},{"actual":[0.0,0.0],"check":"fully extended on x axis","expected":[0.0,0.0],"passed":true},{"actual":[53.1301,0.0],"check":"fully extended diagonal","expected":[53.1301,0.0],"passed":true},{"actual":"unreachable","check":"outside workspace","expected":"unreachable","passed":true},{"actual":"unreachable","check":"between reach and reach squared","expected":"unreachable","passed":true},{"actual":"unreachable","check":"inside inner hole","expected":"unreachable","passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"general elbow up\", \"actual\": [0.0, 90.0], \"expected\": [0.0, 90.0], \"passed\": true}, {\"check\": \"general elbow down\", \"actual\": [53.1301, -90.0], \"expected\": [53.1301, -90.0], \"passed\": true}, {\"check\": \"fully extended on x axis\", \"actual\": [0.0, 0.0], \"expected\": [0.0, 0.0], \"passed\": true}, {\"check\": \"fully extended diagonal\", \"actual\": [53.1301, 0.0], \"expected\": [53.1301, 0.0], \"passed\": true}, {\"check\": \"outside workspace\", \"actual\": \"unreachable\", \"expected\": \"unreachable\", \"passed\": true}, {\"check\": \"between reach and reach squared\", \"actual\": \"unreachable\", \"expected\": \"unreachable\", \"passed\": true}, {\"check\": \"inside inner hole\", \"actual\": \"unreachable\", \"expected\": \"unreachable\", \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}