{"abstract":"Joints are placed at the complementary fraction of the segment and link lengths are not preserved.","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":"Inverting lambda to r/d_i keeps the anchor but scales the segment by the reciprocal.","family":"w2-inverse_kinematics_solvers-fabrik-planar-backward-interpolation-anchor","id":"FA-87976","implementations":{"attempt":{"sha256":"2b2c41ad31e148df6ce21e706795eb77ac8f1f53414af080dc4c270e2e554c91","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=r/d[i]\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]]]], ['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]]]], ['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]]]], ['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]]]], ['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]]]], ['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]]]]]]\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":"04c6ea508b3993282079fd820bc8e1ba1efe23ba43398a6807147e5e1d0e09e6","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][0]+lam*p[i+1][0],(1-lam)*p[i][1]+lam*p[i+1][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]]]], ['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]]]], ['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]]]], ['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]]]], ['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]]]], ['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]]]]]]\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":"c62419076f6f6d847eef62c2b780ad442e76fb0e58a182e786c56a84d0ae946e","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]]]], ['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]]]], ['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]]]], ['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]]]], ['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]]]], ['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]]]]]]\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-backward-interpolation-anchor","generated_at":"2026-09-29T14:51:03.881443+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":"Place p[i] at (1-lambda) p[i+1] + lambda p[i] with lambda = d_i / r.","root_cause":"The backward update weights the old joint by (1-lambda) instead of the freshly placed child joint.","sha256":"be7489d3f91cc9be0cc27c3e99489d82d2248496c224d8905e58954a322cdacc","title":"FABRIK backward pass interpolates from the wrong joint · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":39.928,"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":["max-iterations",10,[[0.0,0.0],[-0.884,-1.794],[-0.4392,-0.8984]]],"check":"unequal links","expected":["reached",2,[[0.0,0.0],[1.6,1.2],[1.0,2.0]]],"passed":false},{"actual":["reached",10,[[0.0,0.0],[1.8733,0.7005],[1.6518,1.1487],[1.0001,2.4998]]],"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":["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\": [\"max-iterations\", 10, [[0.0, 0.0], [-0.884, -1.794], [-0.4392, -0.8984]]], \"expected\": [\"reached\", 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]], \"passed\": false}, {\"check\": \"three unequal links\", \"actual\": [\"reached\", 10, [[0.0, 0.0], [1.8733, 0.7005], [1.6518, 1.1487], [1.0001, 2.4998]]], \"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\": [\"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":44.748,"exit_code":1,"observations":[{"actual":["max-iterations",10,[[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":["max-iterations",10,[[0.0,0.0],[1.1868,1.6098],[0.755,2.5117]]],"check":"unequal links","expected":["reached",2,[[0.0,0.0],[1.6,1.2],[1.0,2.0]]],"passed":false},{"actual":["max-iterations",20,[[0.0,0.0],[0.8707,1.8005],[1.2595,2.1149],[0.4213,3.3588]]],"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":["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\": [\"max-iterations\", 10, [[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\": [\"max-iterations\", 10, [[0.0, 0.0], [1.1868, 1.6098], [0.755, 2.5117]]], \"expected\": [\"reached\", 2, [[0.0, 0.0], [1.6, 1.2], [1.0, 2.0]]], \"passed\": false}, {\"check\": \"three unequal links\", \"actual\": [\"max-iterations\", 20, [[0.0, 0.0], [0.8707, 1.8005], [1.2595, 2.1149], [0.4213, 3.3588]]], \"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\": [\"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.77,"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"}