{"abstract":"Reachable targets are stretched toward as unreachable, and far targets near the tip enter the iteration.","category":"Inverse kinematics solvers","checks":7,"contract":"Input [points, target, tol, iters]: planar joint positions from base to tip. Link lengths come from the initial points. If the base-to-target distance exceeds the total length, stretch every link toward the target and return [\"unreachable\", points]. Otherwise run FABRIK passes (tip to target and backward, base re-anchored, forward) while the tip is farther than tol and fewer than iters passes ran; return [status, passes, points] with status \"reached\" when the final tip error <= tol else \"max-iterations\"; coordinates rounded to 4 places.","evaluation_group":"w2-inverse_kinematics_solvers-fabrik-planar","failed_approach":"Comparing against the longest single link instead of the sum rejects many reachable targets.","family":"w2-inverse_kinematics_solvers-fabrik-planar-reachability-origin","id":"FA-87966","implementations":{"attempt":{"sha256":"dbc4be21112875ab272965b006553547bba01c5519e360cd3f3a7d6be66d56c8","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(x):\n    pts,t,tol,iters=x\n    p=[[float(v) for v in q] for q in pts]\n    d=[math.dist(p[i],p[i+1]) for i in range(len(p)-1)]\n    base=p[0][:]\n    if math.dist(base,t)>max(d):\n        for i in range(len(d)):\n            r=math.dist(p[i],t)\n            lam=d[i]/r\n            p[i+1]=[(1-lam)*p[i][0]+lam*t[0],(1-lam)*p[i][1]+lam*t[1]]\n        return ['unreachable',[[round(v,4) for v in q] for q in p]]\n    count=0\n    while math.dist(p[-1],t)>tol and count<iters:\n        count+=1\n        p[-1]=[float(t[0]),float(t[1])]\n        for i in range(len(p)-2,-1,-1):\n            r=math.dist(p[i+1],p[i])\n            lam=d[i]/r\n            p[i]=[(1-lam)*p[i+1][0]+lam*p[i][0],(1-lam)*p[i+1][1]+lam*p[i][1]]\n        p[0]=base[:]\n        for i in range(len(p)-1):\n            r=math.dist(p[i+1],p[i])\n            lam=d[i]/r\n            p[i+1]=[(1-lam)*p[i][0]+lam*p[i+1][0],(1-lam)*p[i][1]+lam*p[i+1][1]]\n    status='reached' if math.dist(p[-1],t)<=tol else 'max-iterations'\n    return [status,count,[[round(v,4) for v in q] for q in p]]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['two links bend up', [[[[0, 0], [1, 0], [2, 0]], [1, 1], 0.001, 10]], ['reached', 1, [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]]], ['unequal links', [[[[0, 0], [2, 0], [3, 0]], [1, 2], 0.001, 10]], ['reached', 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]]], ['three unequal links', [[[[0, 0], [2, 0], [2.5, 0], [4, 0]], [1, 2.5], 0.001, 20]], ['reached', 1, [[0.0, 0.0], [1.8649, 0.7227], [1.7717, 1.2139], [0.9999, 2.5001]]]], ['unreachable along x', [[[[0, 0], [1, 0], [2, 0]], [5, 0], 0.001, 10]], ['unreachable', [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]], ['unreachable diagonal unequal', [[[[0, 0], [2, 1], [3, 1]], [4, 4], 0.001, 10]], ['unreachable', [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]]], ['single link one pass', [[[[0, 0], [2, 0]], [0, 2], 1e-06, 1]], ['reached', 1, [[0.0, 0.0], [0.0, 2.0]]]], ['already on target zero tol', [[[[0, 0], [1, 0], [2, 0]], [2, 0], 0, 5]], ['reached', 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]]], [['unequal links', [[[[0, 0], [2, 0], [3, 0]], [1, 2], 0.001, 10]], ['reached', 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]]], ['unreachable diagonal unequal', [[[[0, 0], [2, 1], [3, 1]], [4, 4], 0.001, 10]], ['unreachable', [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]]], ['single link one pass', [[[[0, 0], [2, 0]], [0, 2], 1e-06, 1]], ['reached', 1, [[0.0, 0.0], [0.0, 2.0]]]], ['already on target zero tol', [[[[0, 0], [1, 0], [2, 0]], [2, 0], 0, 5]], ['reached', 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]], ['pass budget exhausted', [[[[0, 0], [1, 0], [1.5, 0], [3, 0]], [-1, 1.5], 1e-09, 2]], ['max-iterations', 2, [[0.0, 0.0], [0.809, 0.5878], [0.3308, 0.7337], [-0.9691, 1.4822]]]], ['offset base', [[[[1, 1], [2, 1], [3, 1]], [2, 2.5], 0.001, 10]], ['reached', 6, [[1.0, 1.0], [1.8605, 1.5094], [1.9999, 2.4996]]]], ['near full stretch reachable', [[[[0, 0], [0, 1], [0, 3]], [2.9, 0.2], 0.001, 15]], ['reached', 15, [[0.0, 0.0], [0.9105, 0.4134], [2.8991, 0.2001]]]]], [['three unequal links', [[[[0, 0], [2, 0], [2.5, 0], [4, 0]], [1, 2.5], 0.001, 20]], ['reached', 1, [[0.0, 0.0], [1.8649, 0.7227], [1.7717, 1.2139], [0.9999, 2.5001]]]], ['pass budget exhausted', [[[[0, 0], [1, 0], [1.5, 0], [3, 0]], [-1, 1.5], 1e-09, 2]], ['max-iterations', 2, [[0.0, 0.0], [0.809, 0.5878], [0.3308, 0.7337], [-0.9691, 1.4822]]]], ['offset base', [[[[1, 1], [2, 1], [3, 1]], [2, 2.5], 0.001, 10]], ['reached', 6, [[1.0, 1.0], [1.8605, 1.5094], [1.9999, 2.4996]]]], ['near full stretch reachable', [[[[0, 0], [0, 1], [0, 3]], [2.9, 0.2], 0.001, 15]], ['reached', 15, [[0.0, 0.0], [0.9105, 0.4134], [2.8991, 0.2001]]]], ['tip near base unequal', [[[[0, 0], [3, 0], [4, 0]], [2, 0.5], 0.001, 20]], ['max-iterations', 20, [[0.0, 0.0], [2.9861, 0.2886], [2.0083, 0.4982]]]], ['unreachable from offset base', [[[[2, 0], [2, 1], [2, 3]], [2, -4], 0.001, 10]], ['unreachable', [[2.0, 0.0], [2.0, -1.0], [2.0, -3.0]]]], ['start already inside tolerance', [[[[0, 0], [1, 1], [2, 1]], [2, 1.05], 0.1, 5]], ['reached', 0, [[0.0, 0.0], [1.0, 1.0], [2.0, 1.0]]]]], [['two links bend up', [[[[0, 0], [1, 0], [2, 0]], [1, 1], 0.001, 10]], ['reached', 1, [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]]], ['unequal links', [[[[0, 0], [2, 0], [3, 0]], [1, 2], 0.001, 10]], ['reached', 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]]], ['already on target zero tol', [[[[0, 0], [1, 0], [2, 0]], [2, 0], 0, 5]], ['reached', 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]], ['near full stretch reachable', [[[[0, 0], [0, 1], [0, 3]], [2.9, 0.2], 0.001, 15]], ['reached', 15, [[0.0, 0.0], [0.9105, 0.4134], [2.8991, 0.2001]]]], ['unreachable from offset base', [[[[2, 0], [2, 1], [2, 3]], [2, -4], 0.001, 10]], ['unreachable', [[2.0, 0.0], [2.0, -1.0], [2.0, -3.0]]]], ['start already inside tolerance', [[[[0, 0], [1, 1], [2, 1]], [2, 1.05], 0.1, 5]], ['reached', 0, [[0.0, 0.0], [1.0, 1.0], [2.0, 1.0]]]], ['zero passes allowed', [[[[0, 0], [1, 0], [2, 0]], [0, 2], 0.001, 0]], ['max-iterations', 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]]], [['two links bend up', [[[[0, 0], [1, 0], [2, 0]], [1, 1], 0.001, 10]], ['reached', 1, [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]]], ['unequal links', [[[[0, 0], [2, 0], [3, 0]], [1, 2], 0.001, 10]], ['reached', 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]]], ['three unequal links', [[[[0, 0], [2, 0], [2.5, 0], [4, 0]], [1, 2.5], 0.001, 20]], ['reached', 1, [[0.0, 0.0], [1.8649, 0.7227], [1.7717, 1.2139], [0.9999, 2.5001]]]], ['unreachable along x', [[[[0, 0], [1, 0], [2, 0]], [5, 0], 0.001, 10]], ['unreachable', [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]], ['unreachable diagonal unequal', [[[[0, 0], [2, 1], [3, 1]], [4, 4], 0.001, 10]], ['unreachable', [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]]], ['pass budget exhausted', [[[[0, 0], [1, 0], [1.5, 0], [3, 0]], [-1, 1.5], 1e-09, 2]], ['max-iterations', 2, [[0.0, 0.0], [0.809, 0.5878], [0.3308, 0.7337], [-0.9691, 1.4822]]]], ['zero passes allowed', [[[[0, 0], [1, 0], [2, 0]], [0, 2], 0.001, 0]], ['max-iterations', 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]]]]\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":"5bfea9858402cd908076948715b276bab54ce791dde2e3b2d725a79e96f0fbf0","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(x):\n    pts,t,tol,iters=x\n    p=[[float(v) for v in q] for q in pts]\n    d=[math.dist(p[i],p[i+1]) for i in range(len(p)-1)]\n    base=p[0][:]\n    if math.dist(p[-1],t)>sum(d):\n        for i in range(len(d)):\n            r=math.dist(p[i],t)\n            lam=d[i]/r\n            p[i+1]=[(1-lam)*p[i][0]+lam*t[0],(1-lam)*p[i][1]+lam*t[1]]\n        return ['unreachable',[[round(v,4) for v in q] for q in p]]\n    count=0\n    while math.dist(p[-1],t)>tol and count<iters:\n        count+=1\n        p[-1]=[float(t[0]),float(t[1])]\n        for i in range(len(p)-2,-1,-1):\n            r=math.dist(p[i+1],p[i])\n            lam=d[i]/r\n            p[i]=[(1-lam)*p[i+1][0]+lam*p[i][0],(1-lam)*p[i+1][1]+lam*p[i][1]]\n        p[0]=base[:]\n        for i in range(len(p)-1):\n            r=math.dist(p[i+1],p[i])\n            lam=d[i]/r\n            p[i+1]=[(1-lam)*p[i][0]+lam*p[i+1][0],(1-lam)*p[i][1]+lam*p[i+1][1]]\n    status='reached' if math.dist(p[-1],t)<=tol else 'max-iterations'\n    return [status,count,[[round(v,4) for v in q] for q in p]]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['two links bend up', [[[[0, 0], [1, 0], [2, 0]], [1, 1], 0.001, 10]], ['reached', 1, [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]]], ['unequal links', [[[[0, 0], [2, 0], [3, 0]], [1, 2], 0.001, 10]], ['reached', 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]]], ['three unequal links', [[[[0, 0], [2, 0], [2.5, 0], [4, 0]], [1, 2.5], 0.001, 20]], ['reached', 1, [[0.0, 0.0], [1.8649, 0.7227], [1.7717, 1.2139], [0.9999, 2.5001]]]], ['unreachable along x', [[[[0, 0], [1, 0], [2, 0]], [5, 0], 0.001, 10]], ['unreachable', [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]], ['unreachable diagonal unequal', [[[[0, 0], [2, 1], [3, 1]], [4, 4], 0.001, 10]], ['unreachable', [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]]], ['single link one pass', [[[[0, 0], [2, 0]], [0, 2], 1e-06, 1]], ['reached', 1, [[0.0, 0.0], [0.0, 2.0]]]], ['already on target zero tol', [[[[0, 0], [1, 0], [2, 0]], [2, 0], 0, 5]], ['reached', 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]]], [['unequal links', [[[[0, 0], [2, 0], [3, 0]], [1, 2], 0.001, 10]], ['reached', 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]]], ['unreachable diagonal unequal', [[[[0, 0], [2, 1], [3, 1]], [4, 4], 0.001, 10]], ['unreachable', [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]]], ['single link one pass', [[[[0, 0], [2, 0]], [0, 2], 1e-06, 1]], ['reached', 1, [[0.0, 0.0], [0.0, 2.0]]]], ['already on target zero tol', [[[[0, 0], [1, 0], [2, 0]], [2, 0], 0, 5]], ['reached', 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]], ['pass budget exhausted', [[[[0, 0], [1, 0], [1.5, 0], [3, 0]], [-1, 1.5], 1e-09, 2]], ['max-iterations', 2, [[0.0, 0.0], [0.809, 0.5878], [0.3308, 0.7337], [-0.9691, 1.4822]]]], ['offset base', [[[[1, 1], [2, 1], [3, 1]], [2, 2.5], 0.001, 10]], ['reached', 6, [[1.0, 1.0], [1.8605, 1.5094], [1.9999, 2.4996]]]], ['near full stretch reachable', [[[[0, 0], [0, 1], [0, 3]], [2.9, 0.2], 0.001, 15]], ['reached', 15, [[0.0, 0.0], [0.9105, 0.4134], [2.8991, 0.2001]]]]], [['three unequal links', [[[[0, 0], [2, 0], [2.5, 0], [4, 0]], [1, 2.5], 0.001, 20]], ['reached', 1, [[0.0, 0.0], [1.8649, 0.7227], [1.7717, 1.2139], [0.9999, 2.5001]]]], ['pass budget exhausted', [[[[0, 0], [1, 0], [1.5, 0], [3, 0]], [-1, 1.5], 1e-09, 2]], ['max-iterations', 2, [[0.0, 0.0], [0.809, 0.5878], [0.3308, 0.7337], [-0.9691, 1.4822]]]], ['offset base', [[[[1, 1], [2, 1], [3, 1]], [2, 2.5], 0.001, 10]], ['reached', 6, [[1.0, 1.0], [1.8605, 1.5094], [1.9999, 2.4996]]]], ['near full stretch reachable', [[[[0, 0], [0, 1], [0, 3]], [2.9, 0.2], 0.001, 15]], ['reached', 15, [[0.0, 0.0], [0.9105, 0.4134], [2.8991, 0.2001]]]], ['tip near base unequal', [[[[0, 0], [3, 0], [4, 0]], [2, 0.5], 0.001, 20]], ['max-iterations', 20, [[0.0, 0.0], [2.9861, 0.2886], [2.0083, 0.4982]]]], ['unreachable from offset base', [[[[2, 0], [2, 1], [2, 3]], [2, -4], 0.001, 10]], ['unreachable', [[2.0, 0.0], [2.0, -1.0], [2.0, -3.0]]]], ['start already inside tolerance', [[[[0, 0], [1, 1], [2, 1]], [2, 1.05], 0.1, 5]], ['reached', 0, [[0.0, 0.0], [1.0, 1.0], [2.0, 1.0]]]]], [['two links bend up', [[[[0, 0], [1, 0], [2, 0]], [1, 1], 0.001, 10]], ['reached', 1, [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]]], ['unequal links', [[[[0, 0], [2, 0], [3, 0]], [1, 2], 0.001, 10]], ['reached', 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]]], ['already on target zero tol', [[[[0, 0], [1, 0], [2, 0]], [2, 0], 0, 5]], ['reached', 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]], ['near full stretch reachable', [[[[0, 0], [0, 1], [0, 3]], [2.9, 0.2], 0.001, 15]], ['reached', 15, [[0.0, 0.0], [0.9105, 0.4134], [2.8991, 0.2001]]]], ['unreachable from offset base', [[[[2, 0], [2, 1], [2, 3]], [2, -4], 0.001, 10]], ['unreachable', [[2.0, 0.0], [2.0, -1.0], [2.0, -3.0]]]], ['start already inside tolerance', [[[[0, 0], [1, 1], [2, 1]], [2, 1.05], 0.1, 5]], ['reached', 0, [[0.0, 0.0], [1.0, 1.0], [2.0, 1.0]]]], ['zero passes allowed', [[[[0, 0], [1, 0], [2, 0]], [0, 2], 0.001, 0]], ['max-iterations', 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]]], [['two links bend up', [[[[0, 0], [1, 0], [2, 0]], [1, 1], 0.001, 10]], ['reached', 1, [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]]], ['unequal links', [[[[0, 0], [2, 0], [3, 0]], [1, 2], 0.001, 10]], ['reached', 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]]], ['three unequal links', [[[[0, 0], [2, 0], [2.5, 0], [4, 0]], [1, 2.5], 0.001, 20]], ['reached', 1, [[0.0, 0.0], [1.8649, 0.7227], [1.7717, 1.2139], [0.9999, 2.5001]]]], ['unreachable along x', [[[[0, 0], [1, 0], [2, 0]], [5, 0], 0.001, 10]], ['unreachable', [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]], ['unreachable diagonal unequal', [[[[0, 0], [2, 1], [3, 1]], [4, 4], 0.001, 10]], ['unreachable', [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]]], ['pass budget exhausted', [[[[0, 0], [1, 0], [1.5, 0], [3, 0]], [-1, 1.5], 1e-09, 2]], ['max-iterations', 2, [[0.0, 0.0], [0.809, 0.5878], [0.3308, 0.7337], [-0.9691, 1.4822]]]], ['zero passes allowed', [[[[0, 0], [1, 0], [2, 0]], [0, 2], 0.001, 0]], ['max-iterations', 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]]]]\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":"9bac0f1278e77d16481f0ff1bcf9a3caa6be88bf41177f4297553218602d6a93","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(x):\n    pts,t,tol,iters=x\n    p=[[float(v) for v in q] for q in pts]\n    d=[math.dist(p[i],p[i+1]) for i in range(len(p)-1)]\n    base=p[0][:]\n    if math.dist(base,t)>sum(d):\n        for i in range(len(d)):\n            r=math.dist(p[i],t)\n            lam=d[i]/r\n            p[i+1]=[(1-lam)*p[i][0]+lam*t[0],(1-lam)*p[i][1]+lam*t[1]]\n        return ['unreachable',[[round(v,4) for v in q] for q in p]]\n    count=0\n    while math.dist(p[-1],t)>tol and count<iters:\n        count+=1\n        p[-1]=[float(t[0]),float(t[1])]\n        for i in range(len(p)-2,-1,-1):\n            r=math.dist(p[i+1],p[i])\n            lam=d[i]/r\n            p[i]=[(1-lam)*p[i+1][0]+lam*p[i][0],(1-lam)*p[i+1][1]+lam*p[i][1]]\n        p[0]=base[:]\n        for i in range(len(p)-1):\n            r=math.dist(p[i+1],p[i])\n            lam=d[i]/r\n            p[i+1]=[(1-lam)*p[i][0]+lam*p[i+1][0],(1-lam)*p[i][1]+lam*p[i+1][1]]\n    status='reached' if math.dist(p[-1],t)<=tol else 'max-iterations'\n    return [status,count,[[round(v,4) for v in q] for q in p]]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[['two links bend up', [[[[0, 0], [1, 0], [2, 0]], [1, 1], 0.001, 10]], ['reached', 1, [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]]], ['unequal links', [[[[0, 0], [2, 0], [3, 0]], [1, 2], 0.001, 10]], ['reached', 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]]], ['three unequal links', [[[[0, 0], [2, 0], [2.5, 0], [4, 0]], [1, 2.5], 0.001, 20]], ['reached', 1, [[0.0, 0.0], [1.8649, 0.7227], [1.7717, 1.2139], [0.9999, 2.5001]]]], ['unreachable along x', [[[[0, 0], [1, 0], [2, 0]], [5, 0], 0.001, 10]], ['unreachable', [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]], ['unreachable diagonal unequal', [[[[0, 0], [2, 1], [3, 1]], [4, 4], 0.001, 10]], ['unreachable', [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]]], ['single link one pass', [[[[0, 0], [2, 0]], [0, 2], 1e-06, 1]], ['reached', 1, [[0.0, 0.0], [0.0, 2.0]]]], ['already on target zero tol', [[[[0, 0], [1, 0], [2, 0]], [2, 0], 0, 5]], ['reached', 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]]], [['unequal links', [[[[0, 0], [2, 0], [3, 0]], [1, 2], 0.001, 10]], ['reached', 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]]], ['unreachable diagonal unequal', [[[[0, 0], [2, 1], [3, 1]], [4, 4], 0.001, 10]], ['unreachable', [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]]], ['single link one pass', [[[[0, 0], [2, 0]], [0, 2], 1e-06, 1]], ['reached', 1, [[0.0, 0.0], [0.0, 2.0]]]], ['already on target zero tol', [[[[0, 0], [1, 0], [2, 0]], [2, 0], 0, 5]], ['reached', 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]], ['pass budget exhausted', [[[[0, 0], [1, 0], [1.5, 0], [3, 0]], [-1, 1.5], 1e-09, 2]], ['max-iterations', 2, [[0.0, 0.0], [0.809, 0.5878], [0.3308, 0.7337], [-0.9691, 1.4822]]]], ['offset base', [[[[1, 1], [2, 1], [3, 1]], [2, 2.5], 0.001, 10]], ['reached', 6, [[1.0, 1.0], [1.8605, 1.5094], [1.9999, 2.4996]]]], ['near full stretch reachable', [[[[0, 0], [0, 1], [0, 3]], [2.9, 0.2], 0.001, 15]], ['reached', 15, [[0.0, 0.0], [0.9105, 0.4134], [2.8991, 0.2001]]]]], [['three unequal links', [[[[0, 0], [2, 0], [2.5, 0], [4, 0]], [1, 2.5], 0.001, 20]], ['reached', 1, [[0.0, 0.0], [1.8649, 0.7227], [1.7717, 1.2139], [0.9999, 2.5001]]]], ['pass budget exhausted', [[[[0, 0], [1, 0], [1.5, 0], [3, 0]], [-1, 1.5], 1e-09, 2]], ['max-iterations', 2, [[0.0, 0.0], [0.809, 0.5878], [0.3308, 0.7337], [-0.9691, 1.4822]]]], ['offset base', [[[[1, 1], [2, 1], [3, 1]], [2, 2.5], 0.001, 10]], ['reached', 6, [[1.0, 1.0], [1.8605, 1.5094], [1.9999, 2.4996]]]], ['near full stretch reachable', [[[[0, 0], [0, 1], [0, 3]], [2.9, 0.2], 0.001, 15]], ['reached', 15, [[0.0, 0.0], [0.9105, 0.4134], [2.8991, 0.2001]]]], ['tip near base unequal', [[[[0, 0], [3, 0], [4, 0]], [2, 0.5], 0.001, 20]], ['max-iterations', 20, [[0.0, 0.0], [2.9861, 0.2886], [2.0083, 0.4982]]]], ['unreachable from offset base', [[[[2, 0], [2, 1], [2, 3]], [2, -4], 0.001, 10]], ['unreachable', [[2.0, 0.0], [2.0, -1.0], [2.0, -3.0]]]], ['start already inside tolerance', [[[[0, 0], [1, 1], [2, 1]], [2, 1.05], 0.1, 5]], ['reached', 0, [[0.0, 0.0], [1.0, 1.0], [2.0, 1.0]]]]], [['two links bend up', [[[[0, 0], [1, 0], [2, 0]], [1, 1], 0.001, 10]], ['reached', 1, [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]]], ['unequal links', [[[[0, 0], [2, 0], [3, 0]], [1, 2], 0.001, 10]], ['reached', 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]]], ['already on target zero tol', [[[[0, 0], [1, 0], [2, 0]], [2, 0], 0, 5]], ['reached', 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]], ['near full stretch reachable', [[[[0, 0], [0, 1], [0, 3]], [2.9, 0.2], 0.001, 15]], ['reached', 15, [[0.0, 0.0], [0.9105, 0.4134], [2.8991, 0.2001]]]], ['unreachable from offset base', [[[[2, 0], [2, 1], [2, 3]], [2, -4], 0.001, 10]], ['unreachable', [[2.0, 0.0], [2.0, -1.0], [2.0, -3.0]]]], ['start already inside tolerance', [[[[0, 0], [1, 1], [2, 1]], [2, 1.05], 0.1, 5]], ['reached', 0, [[0.0, 0.0], [1.0, 1.0], [2.0, 1.0]]]], ['zero passes allowed', [[[[0, 0], [1, 0], [2, 0]], [0, 2], 0.001, 0]], ['max-iterations', 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]]], [['two links bend up', [[[[0, 0], [1, 0], [2, 0]], [1, 1], 0.001, 10]], ['reached', 1, [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]]], ['unequal links', [[[[0, 0], [2, 0], [3, 0]], [1, 2], 0.001, 10]], ['reached', 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]]], ['three unequal links', [[[[0, 0], [2, 0], [2.5, 0], [4, 0]], [1, 2.5], 0.001, 20]], ['reached', 1, [[0.0, 0.0], [1.8649, 0.7227], [1.7717, 1.2139], [0.9999, 2.5001]]]], ['unreachable along x', [[[[0, 0], [1, 0], [2, 0]], [5, 0], 0.001, 10]], ['unreachable', [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]], ['unreachable diagonal unequal', [[[[0, 0], [2, 1], [3, 1]], [4, 4], 0.001, 10]], ['unreachable', [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]]], ['pass budget exhausted', [[[[0, 0], [1, 0], [1.5, 0], [3, 0]], [-1, 1.5], 1e-09, 2]], ['max-iterations', 2, [[0.0, 0.0], [0.809, 0.5878], [0.3308, 0.7337], [-0.9691, 1.4822]]]], ['zero passes allowed', [[[[0, 0], [1, 0], [2, 0]], [0, 2], 0.001, 0]], ['max-iterations', 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]]]]]\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-fabrik-planar-reachability-origin","generated_at":"2026-09-29T14:51:03.795350+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":"Compare the base-to-target distance with the total chain length.","root_cause":"The reach test uses the distance from the end effector to the target instead of from the fixed base.","sha256":"b3f09f23dc1eb39a4c48be576557b304fe3a663d2daeb16aa87e2f29e58f2324","title":"FABRIK reachability is measured from the current tip · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":42.029,"exit_code":1,"observations":[{"actual":["unreachable",[[0.0,0.0],[0.7071,0.7071],[1.4142,1.4142]]],"check":"two links bend up","expected":["reached",1,[[0.0,0.0],[1.0,0.0],[1.0,1.0]]],"passed":false},{"actual":["unreachable",[[0.0,0.0],[0.8944,1.7889],[1.3416,2.6833]]],"check":"unequal links","expected":["reached",2,[[0.0,0.0],[1.6,1.2],[1.0,2.0]]],"passed":false},{"actual":["unreachable",[[0.0,0.0],[0.7428,1.857],[0.9285,2.3212],[1.4856,3.7139]]],"check":"three unequal links","expected":["reached",1,[[0.0,0.0],[1.8649,0.7227],[1.7717,1.2139],[0.9999,2.5001]]],"passed":false},{"actual":["unreachable",[[0.0,0.0],[1.0,0.0],[2.0,0.0]]],"check":"unreachable along x","expected":["unreachable",[[0.0,0.0],[1.0,0.0],[2.0,0.0]]],"passed":true},{"actual":["unreachable",[[0.0,0.0],[1.5811,1.5811],[2.2882,2.2882]]],"check":"unreachable diagonal unequal","expected":["unreachable",[[0.0,0.0],[1.5811,1.5811],[2.2882,2.2882]]],"passed":true},{"actual":["reached",1,[[0.0,0.0],[0.0,2.0]]],"check":"single link one pass","expected":["reached",1,[[0.0,0.0],[0.0,2.0]]],"passed":true},{"actual":["unreachable",[[0.0,0.0],[1.0,0.0],[2.0,0.0]]],"check":"already on target zero tol","expected":["reached",0,[[0.0,0.0],[1.0,0.0],[2.0,0.0]]],"passed":false}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"two links bend up\", \"actual\": [\"unreachable\", [[0.0, 0.0], [0.7071, 0.7071], [1.4142, 1.4142]]], \"expected\": [\"reached\", 1, [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]], \"passed\": false}, {\"check\": \"unequal links\", \"actual\": [\"unreachable\", [[0.0, 0.0], [0.8944, 1.7889], [1.3416, 2.6833]]], \"expected\": [\"reached\", 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]], \"passed\": false}, {\"check\": \"three unequal links\", \"actual\": [\"unreachable\", [[0.0, 0.0], [0.7428, 1.857], [0.9285, 2.3212], [1.4856, 3.7139]]], \"expected\": [\"reached\", 1, [[0.0, 0.0], [1.8649, 0.7227], [1.7717, 1.2139], [0.9999, 2.5001]]], \"passed\": false}, {\"check\": \"unreachable along x\", \"actual\": [\"unreachable\", [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]], \"expected\": [\"unreachable\", [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]], \"passed\": true}, {\"check\": \"unreachable diagonal unequal\", \"actual\": [\"unreachable\", [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]], \"expected\": [\"unreachable\", [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]], \"passed\": true}, {\"check\": \"single link one pass\", \"actual\": [\"reached\", 1, [[0.0, 0.0], [0.0, 2.0]]], \"expected\": [\"reached\", 1, [[0.0, 0.0], [0.0, 2.0]]], \"passed\": true}, {\"check\": \"already on target zero tol\", \"actual\": [\"unreachable\", [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]], \"expected\": [\"reached\", 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]], \"passed\": false}], \"passed\": false}\n"},"broken":{"elapsed_ms":39.245,"exit_code":1,"observations":[{"actual":["reached",1,[[0.0,0.0],[1.0,0.0],[1.0,1.0]]],"check":"two links bend up","expected":["reached",1,[[0.0,0.0],[1.0,0.0],[1.0,1.0]]],"passed":true},{"actual":["reached",2,[[0.0,0.0],[1.6,1.2],[1.0,2.0]]],"check":"unequal links","expected":["reached",2,[[0.0,0.0],[1.6,1.2],[1.0,2.0]]],"passed":true},{"actual":["reached",1,[[0.0,0.0],[1.8649,0.7227],[1.7717,1.2139],[0.9999,2.5001]]],"check":"three unequal links","expected":["reached",1,[[0.0,0.0],[1.8649,0.7227],[1.7717,1.2139],[0.9999,2.5001]]],"passed":true},{"actual":["unreachable",[[0.0,0.0],[1.0,0.0],[2.0,0.0]]],"check":"unreachable along x","expected":["unreachable",[[0.0,0.0],[1.0,0.0],[2.0,0.0]]],"passed":true},{"actual":["max-iterations",10,[[0.0,0.0],[1.5811,1.5811],[2.2882,2.2882]]],"check":"unreachable diagonal unequal","expected":["unreachable",[[0.0,0.0],[1.5811,1.5811],[2.2882,2.2882]]],"passed":false},{"actual":["unreachable",[[0.0,0.0],[0.0,2.0]]],"check":"single link one pass","expected":["reached",1,[[0.0,0.0],[0.0,2.0]]],"passed":false},{"actual":["reached",0,[[0.0,0.0],[1.0,0.0],[2.0,0.0]]],"check":"already on target zero tol","expected":["reached",0,[[0.0,0.0],[1.0,0.0],[2.0,0.0]]],"passed":true}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"two links bend up\", \"actual\": [\"reached\", 1, [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]], \"expected\": [\"reached\", 1, [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]], \"passed\": true}, {\"check\": \"unequal links\", \"actual\": [\"reached\", 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]], \"expected\": [\"reached\", 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]], \"passed\": true}, {\"check\": \"three unequal links\", \"actual\": [\"reached\", 1, [[0.0, 0.0], [1.8649, 0.7227], [1.7717, 1.2139], [0.9999, 2.5001]]], \"expected\": [\"reached\", 1, [[0.0, 0.0], [1.8649, 0.7227], [1.7717, 1.2139], [0.9999, 2.5001]]], \"passed\": true}, {\"check\": \"unreachable along x\", \"actual\": [\"unreachable\", [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]], \"expected\": [\"unreachable\", [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]], \"passed\": true}, {\"check\": \"unreachable diagonal unequal\", \"actual\": [\"max-iterations\", 10, [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]], \"expected\": [\"unreachable\", [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]], \"passed\": false}, {\"check\": \"single link one pass\", \"actual\": [\"unreachable\", [[0.0, 0.0], [0.0, 2.0]]], \"expected\": [\"reached\", 1, [[0.0, 0.0], [0.0, 2.0]]], \"passed\": false}, {\"check\": \"already on target zero tol\", \"actual\": [\"reached\", 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]], \"expected\": [\"reached\", 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]], \"passed\": true}], \"passed\": false}\n"},"fixed":{"elapsed_ms":44.143,"exit_code":0,"observations":[{"actual":["reached",1,[[0.0,0.0],[1.0,0.0],[1.0,1.0]]],"check":"two links bend up","expected":["reached",1,[[0.0,0.0],[1.0,0.0],[1.0,1.0]]],"passed":true},{"actual":["reached",2,[[0.0,0.0],[1.6,1.2],[1.0,2.0]]],"check":"unequal links","expected":["reached",2,[[0.0,0.0],[1.6,1.2],[1.0,2.0]]],"passed":true},{"actual":["reached",1,[[0.0,0.0],[1.8649,0.7227],[1.7717,1.2139],[0.9999,2.5001]]],"check":"three unequal links","expected":["reached",1,[[0.0,0.0],[1.8649,0.7227],[1.7717,1.2139],[0.9999,2.5001]]],"passed":true},{"actual":["unreachable",[[0.0,0.0],[1.0,0.0],[2.0,0.0]]],"check":"unreachable along x","expected":["unreachable",[[0.0,0.0],[1.0,0.0],[2.0,0.0]]],"passed":true},{"actual":["unreachable",[[0.0,0.0],[1.5811,1.5811],[2.2882,2.2882]]],"check":"unreachable diagonal unequal","expected":["unreachable",[[0.0,0.0],[1.5811,1.5811],[2.2882,2.2882]]],"passed":true},{"actual":["reached",1,[[0.0,0.0],[0.0,2.0]]],"check":"single link one pass","expected":["reached",1,[[0.0,0.0],[0.0,2.0]]],"passed":true},{"actual":["reached",0,[[0.0,0.0],[1.0,0.0],[2.0,0.0]]],"check":"already on target zero tol","expected":["reached",0,[[0.0,0.0],[1.0,0.0],[2.0,0.0]]],"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"two links bend up\", \"actual\": [\"reached\", 1, [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]], \"expected\": [\"reached\", 1, [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]], \"passed\": true}, {\"check\": \"unequal links\", \"actual\": [\"reached\", 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]], \"expected\": [\"reached\", 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]], \"passed\": true}, {\"check\": \"three unequal links\", \"actual\": [\"reached\", 1, [[0.0, 0.0], [1.8649, 0.7227], [1.7717, 1.2139], [0.9999, 2.5001]]], \"expected\": [\"reached\", 1, [[0.0, 0.0], [1.8649, 0.7227], [1.7717, 1.2139], [0.9999, 2.5001]]], \"passed\": true}, {\"check\": \"unreachable along x\", \"actual\": [\"unreachable\", [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]], \"expected\": [\"unreachable\", [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]], \"passed\": true}, {\"check\": \"unreachable diagonal unequal\", \"actual\": [\"unreachable\", [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]], \"expected\": [\"unreachable\", [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]], \"passed\": true}, {\"check\": \"single link one pass\", \"actual\": [\"reached\", 1, [[0.0, 0.0], [0.0, 2.0]]], \"expected\": [\"reached\", 1, [[0.0, 0.0], [0.0, 2.0]]], \"passed\": true}, {\"check\": \"already on target zero tol\", \"actual\": [\"reached\", 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]], \"expected\": [\"reached\", 0, [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]], \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}