{"abstract":"Stretched chains for unreachable targets have compressed outer links.","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":"Measuring from the not-yet-updated child joint uses a stale position.","family":"w2-inverse_kinematics_solvers-fabrik-planar-unreachable-stretch-distance","id":"FA-87986","implementations":{"attempt":{"sha256":"7a15ee4deab11ec9fc365e82ab7444709a3b78c39d3f0b3b81c0145d4e5f4005","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+1],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]]]]], [['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]]]], ['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]]]]], [['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]]]], ['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]]]], ['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]]]], ['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]]]], ['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]]]], ['single link one pass', [[[[0, 0], [2, 0]], [0, 2], 1e-06, 1]], ['reached', 1, [[0.0, 0.0], [0.0, 2.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]]]]]]\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":"49449c6f25d2b143c51bb9560b1a0a281e3f141f874e15a348184b381a4894d0","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(base,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]]]]], [['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]]]], ['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]]]]], [['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]]]], ['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]]]], ['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]]]], ['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]]]], ['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]]]], ['single link one pass', [[[[0, 0], [2, 0]], [0, 2], 1e-06, 1]], ['reached', 1, [[0.0, 0.0], [0.0, 2.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]]]]]]\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":"7be06a4ee2398adde467d64e8bac20fa482e41228d1dbfbd198125e2db7c41bb","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]]]]], [['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]]]], ['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]]]]], [['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]]]], ['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]]]], ['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]]]], ['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]]]], ['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]]]], ['single link one pass', [[[[0, 0], [2, 0]], [0, 2], 1e-06, 1]], ['reached', 1, [[0.0, 0.0], [0.0, 2.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]]]]]]\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-unreachable-stretch-distance","generated_at":"2026-09-29T14:51:03.922536+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":"Recompute r as the distance from the current joint p[i] to the target.","root_cause":"Each joint is interpolated with the fixed base-to-target distance instead of its own distance to the target.","sha256":"71e06583f0503ef854ddaeb46396a6cedbcdce24b271b40a57598b5853d63b20","title":"Unreachable FABRIK stretch uses the base distance for every joint · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":39.544,"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.25,0.0],[2.5,0.0]]],"check":"unreachable along x","expected":["unreachable",[[0.0,0.0],[1.0,0.0],[2.0,0.0]]],"passed":false},{"actual":["unreachable",[[0.0,0.0],[2.4807,2.4807],[2.9611,2.9611]]],"check":"unreachable diagonal unequal","expected":["unreachable",[[0.0,0.0],[1.5811,1.5811],[2.2882,2.2882]]],"passed":false},{"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":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.25, 0.0], [2.5, 0.0]]], \"expected\": [\"unreachable\", [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]], \"passed\": false}, {\"check\": \"unreachable diagonal unequal\", \"actual\": [\"unreachable\", [[0.0, 0.0], [2.4807, 2.4807], [2.9611, 2.9611]]], \"expected\": [\"unreachable\", [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]], \"passed\": false}, {\"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\": false}\n"},"broken":{"elapsed_ms":40.543,"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],[1.8,0.0]]],"check":"unreachable along x","expected":["unreachable",[[0.0,0.0],[1.0,0.0],[2.0,0.0]]],"passed":false},{"actual":["unreachable",[[0.0,0.0],[1.5811,1.5811],[2.0087,2.0087]]],"check":"unreachable diagonal unequal","expected":["unreachable",[[0.0,0.0],[1.5811,1.5811],[2.2882,2.2882]]],"passed":false},{"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":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], [1.8, 0.0]]], \"expected\": [\"unreachable\", [[0.0, 0.0], [1.0, 0.0], [2.0, 0.0]]], \"passed\": false}, {\"check\": \"unreachable diagonal unequal\", \"actual\": [\"unreachable\", [[0.0, 0.0], [1.5811, 1.5811], [2.0087, 2.0087]]], \"expected\": [\"unreachable\", [[0.0, 0.0], [1.5811, 1.5811], [2.2882, 2.2882]]], \"passed\": false}, {\"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\": false}\n"},"fixed":{"elapsed_ms":40.228,"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"}