{"abstract":"Points just north of the equator in a southern grid jump by ten thousand kilometres.","category":"Map projection transforms","checks":8,"contract":"Input [lon, lat, zone, hemisphere] with |lat| <= 80 and lon within 4 degrees of the zone central meridian 6*zone-183. On a sphere R = 6371000 with k0 = 0.9996: B = cos(phi)*sin(dl); x = 0.5*k0*R*ln((1+B)/(1-B)); y = k0*R*atan2(tan(phi), cos(dl)). Easting = 500000 + x. Northing = y plus 10000000 when the requested grid hemisphere is \"S\" (the caller may deliberately project points just north of the equator in a southern grid). Return [easting, northing] rounded to 2 decimals.","evaluation_group":"w2-map-projection-transforms-spherical-utm-forward","failed_approach":"Requiring both the S flag and a negative latitude still drops the false northing for northern points in a southern grid.","family":"w2-map-projection-transforms-spherical-utm-forward-grid-hemisphere-flag","id":"FA-70021","implementations":{"attempt":{"sha256":"d3dbb5c90f7aad33a52c117fad93300bdc70cc7159c6f9231056808acf870351","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(x):\n    lon, lat, zone, hemi = x\n    R = 6371000.0\n    k0 = 0.9996\n    lon0 = zone * 6 - 183\n    dl = math.radians(lon - lon0)\n    phi = math.radians(lat)\n    B = math.cos(phi) * math.sin(dl)\n    xm = 0.5 * k0 * R * math.log((1 + B) / (1 - B))\n    ym = k0 * R * math.atan2(math.tan(phi), math.cos(dl))\n    easting = 500000.0 + xm\n    northing = ym + (10000000.0 if hemi == 'S' and lat < 0 else 0.0)\n    return [round(easting, 2), round(northing, 2)]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[('control #0', [-146.456, 65.451, 6, 'S'], [525121.58, 17275016.5]), ('control #1', [-24.305, 48.206, 26, 'S'], [699628.48, 15361620.03]), ('control #2', [-3.252, -34.222, 30, 'N'], [476839.56, -3803819.3]), ('control #3', [140.223, -1.339, 54, 'S'], [413657.04, 9851155.87]), ('control #4', [-99.681, -57.299, 14, 'S'], [459106.63, 3630985.93]), ('control #5', [131.956, -7.201, 52, 'S'], [826109.36, 9198550.44]), ('control #6', [-63.683, 39.81, 20, 'S'], [441683.41, 14425121.91]), ('control #7', [-31.602, 39.795, 25, 'S'], [619393.11, 14424164.48])], [('control #1', [-24.305, 48.206, 26, 'S'], [699628.48, 15361620.03]), ('control #4', [-99.681, -57.299, 14, 'S'], [459106.63, 3630985.93]), ('control #5', [131.956, -7.201, 52, 'S'], [826109.36, 9198550.44]), ('control #6', [-63.683, 39.81, 20, 'S'], [441683.41, 14425121.91]), ('control #7', [-31.602, 39.795, 25, 'S'], [619393.11, 14424164.48]), ('control #8', [87.283, -45.722, 45, 'N'], [521960.41, -5082059.64]), ('control #9', [74.243, 54.044, 43, 'S'], [450595.96, 16007279.04]), ('control #12', [-107.58, 5.652, 13, 'N'], [214531.37, 628855.65])], [('control #2', [-3.252, -34.222, 30, 'N'], [476839.56, -3803819.3]), ('control #6', [-63.683, 39.81, 20, 'S'], [441683.41, 14425121.91]), ('control #8', [87.283, -45.722, 45, 'N'], [521960.41, -5082059.64]), ('control #9', [74.243, 54.044, 43, 'S'], [450595.96, 16007279.04]), ('control #10', [-96.557, 39.544, 14, 'S'], [709406.66, 14398176.63]), ('control #12', [-107.58, 5.652, 13, 'N'], [214531.37, 628855.65]), ('boundary #16', [15.0, 0.0, 33, 'N'], [500000.0, 0.0]), ('boundary #18', [3.0, 45.0, 31, 'N'], [500000.0, 5001770.19])], [('control #6', [-63.683, 39.81, 20, 'S'], [441683.41, 14425121.91]), ('control #9', [74.243, 54.044, 43, 'S'], [450595.96, 16007279.04]), ('control #11', [162.356, -15.269, 58, 'N'], [216405.53, -1698880.3]), ('control #12', [-107.58, 5.652, 13, 'N'], [214531.37, 628855.65]), ('control #13', [100.982, 3.293, 47, 'S'], [719980.03, 10366237.05]), ('regression #14', [9.0, 0.5, 32, 'S'], [500000.0, 10055575.22]), ('boundary #16', [15.0, 0.0, 33, 'N'], [500000.0, 0.0]), ('boundary #18', [3.0, 45.0, 31, 'N'], [500000.0, 5001770.19])], [('control #7', [-31.602, 39.795, 25, 'S'], [619393.11, 14424164.48]), ('control #10', [-96.557, 39.544, 14, 'S'], [709406.66, 14398176.63]), ('regression #14', [9.0, 0.5, 32, 'S'], [500000.0, 10055575.22]), ('regression #15', [-75.5, 0.2, 18, 'S'], [444424.41, 10022230.94]), ('boundary #16', [15.0, 0.0, 33, 'N'], [500000.0, 0.0]), ('regression #17', [30.0, -0.3, 36, 'N'], [166400.77, -33390.89]), ('boundary #18', [3.0, 45.0, 31, 'N'], [500000.0, 5001770.19]), ('control #19', [12.3, -35.0, 33, 'S'], [254136.28, 6106410.11])]]\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":"85dd9867c9da49290ebc5a97b2c53f36226bbdd105c91eec09c3413f61550675","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(x):\n    lon, lat, zone, hemi = x\n    R = 6371000.0\n    k0 = 0.9996\n    lon0 = zone * 6 - 183\n    dl = math.radians(lon - lon0)\n    phi = math.radians(lat)\n    B = math.cos(phi) * math.sin(dl)\n    xm = 0.5 * k0 * R * math.log((1 + B) / (1 - B))\n    ym = k0 * R * math.atan2(math.tan(phi), math.cos(dl))\n    easting = 500000.0 + xm\n    northing = ym + (10000000.0 if lat < 0 else 0.0)\n    return [round(easting, 2), round(northing, 2)]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[('control #0', [-146.456, 65.451, 6, 'S'], [525121.58, 17275016.5]), ('control #1', [-24.305, 48.206, 26, 'S'], [699628.48, 15361620.03]), ('control #2', [-3.252, -34.222, 30, 'N'], [476839.56, -3803819.3]), ('control #3', [140.223, -1.339, 54, 'S'], [413657.04, 9851155.87]), ('control #4', [-99.681, -57.299, 14, 'S'], [459106.63, 3630985.93]), ('control #5', [131.956, -7.201, 52, 'S'], [826109.36, 9198550.44]), ('control #6', [-63.683, 39.81, 20, 'S'], [441683.41, 14425121.91]), ('control #7', [-31.602, 39.795, 25, 'S'], [619393.11, 14424164.48])], [('control #1', [-24.305, 48.206, 26, 'S'], [699628.48, 15361620.03]), ('control #4', [-99.681, -57.299, 14, 'S'], [459106.63, 3630985.93]), ('control #5', [131.956, -7.201, 52, 'S'], [826109.36, 9198550.44]), ('control #6', [-63.683, 39.81, 20, 'S'], [441683.41, 14425121.91]), ('control #7', [-31.602, 39.795, 25, 'S'], [619393.11, 14424164.48]), ('control #8', [87.283, -45.722, 45, 'N'], [521960.41, -5082059.64]), ('control #9', [74.243, 54.044, 43, 'S'], [450595.96, 16007279.04]), ('control #12', [-107.58, 5.652, 13, 'N'], [214531.37, 628855.65])], [('control #2', [-3.252, -34.222, 30, 'N'], [476839.56, -3803819.3]), ('control #6', [-63.683, 39.81, 20, 'S'], [441683.41, 14425121.91]), ('control #8', [87.283, -45.722, 45, 'N'], [521960.41, -5082059.64]), ('control #9', [74.243, 54.044, 43, 'S'], [450595.96, 16007279.04]), ('control #10', [-96.557, 39.544, 14, 'S'], [709406.66, 14398176.63]), ('control #12', [-107.58, 5.652, 13, 'N'], [214531.37, 628855.65]), ('boundary #16', [15.0, 0.0, 33, 'N'], [500000.0, 0.0]), ('boundary #18', [3.0, 45.0, 31, 'N'], [500000.0, 5001770.19])], [('control #6', [-63.683, 39.81, 20, 'S'], [441683.41, 14425121.91]), ('control #9', [74.243, 54.044, 43, 'S'], [450595.96, 16007279.04]), ('control #11', [162.356, -15.269, 58, 'N'], [216405.53, -1698880.3]), ('control #12', [-107.58, 5.652, 13, 'N'], [214531.37, 628855.65]), ('control #13', [100.982, 3.293, 47, 'S'], [719980.03, 10366237.05]), ('regression #14', [9.0, 0.5, 32, 'S'], [500000.0, 10055575.22]), ('boundary #16', [15.0, 0.0, 33, 'N'], [500000.0, 0.0]), ('boundary #18', [3.0, 45.0, 31, 'N'], [500000.0, 5001770.19])], [('control #7', [-31.602, 39.795, 25, 'S'], [619393.11, 14424164.48]), ('control #10', [-96.557, 39.544, 14, 'S'], [709406.66, 14398176.63]), ('regression #14', [9.0, 0.5, 32, 'S'], [500000.0, 10055575.22]), ('regression #15', [-75.5, 0.2, 18, 'S'], [444424.41, 10022230.94]), ('boundary #16', [15.0, 0.0, 33, 'N'], [500000.0, 0.0]), ('regression #17', [30.0, -0.3, 36, 'N'], [166400.77, -33390.89]), ('boundary #18', [3.0, 45.0, 31, 'N'], [500000.0, 5001770.19]), ('control #19', [12.3, -35.0, 33, 'S'], [254136.28, 6106410.11])]]\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":"20beae4d0c9b3ef4c1d95554606546155931632289ec474266f27a39689a7b53","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\nimport math\nN = 1\nobservations = []\ndef solve(x):\n    lon, lat, zone, hemi = x\n    R = 6371000.0\n    k0 = 0.9996\n    lon0 = zone * 6 - 183\n    dl = math.radians(lon - lon0)\n    phi = math.radians(lat)\n    B = math.cos(phi) * math.sin(dl)\n    xm = 0.5 * k0 * R * math.log((1 + B) / (1 - B))\n    ym = k0 * R * math.atan2(math.tan(phi), math.cos(dl))\n    easting = 500000.0 + xm\n    northing = ym + (10000000.0 if hemi == 'S' else 0.0)\n    return [round(easting, 2), round(northing, 2)]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nfixtures = [[('control #0', [-146.456, 65.451, 6, 'S'], [525121.58, 17275016.5]), ('control #1', [-24.305, 48.206, 26, 'S'], [699628.48, 15361620.03]), ('control #2', [-3.252, -34.222, 30, 'N'], [476839.56, -3803819.3]), ('control #3', [140.223, -1.339, 54, 'S'], [413657.04, 9851155.87]), ('control #4', [-99.681, -57.299, 14, 'S'], [459106.63, 3630985.93]), ('control #5', [131.956, -7.201, 52, 'S'], [826109.36, 9198550.44]), ('control #6', [-63.683, 39.81, 20, 'S'], [441683.41, 14425121.91]), ('control #7', [-31.602, 39.795, 25, 'S'], [619393.11, 14424164.48])], [('control #1', [-24.305, 48.206, 26, 'S'], [699628.48, 15361620.03]), ('control #4', [-99.681, -57.299, 14, 'S'], [459106.63, 3630985.93]), ('control #5', [131.956, -7.201, 52, 'S'], [826109.36, 9198550.44]), ('control #6', [-63.683, 39.81, 20, 'S'], [441683.41, 14425121.91]), ('control #7', [-31.602, 39.795, 25, 'S'], [619393.11, 14424164.48]), ('control #8', [87.283, -45.722, 45, 'N'], [521960.41, -5082059.64]), ('control #9', [74.243, 54.044, 43, 'S'], [450595.96, 16007279.04]), ('control #12', [-107.58, 5.652, 13, 'N'], [214531.37, 628855.65])], [('control #2', [-3.252, -34.222, 30, 'N'], [476839.56, -3803819.3]), ('control #6', [-63.683, 39.81, 20, 'S'], [441683.41, 14425121.91]), ('control #8', [87.283, -45.722, 45, 'N'], [521960.41, -5082059.64]), ('control #9', [74.243, 54.044, 43, 'S'], [450595.96, 16007279.04]), ('control #10', [-96.557, 39.544, 14, 'S'], [709406.66, 14398176.63]), ('control #12', [-107.58, 5.652, 13, 'N'], [214531.37, 628855.65]), ('boundary #16', [15.0, 0.0, 33, 'N'], [500000.0, 0.0]), ('boundary #18', [3.0, 45.0, 31, 'N'], [500000.0, 5001770.19])], [('control #6', [-63.683, 39.81, 20, 'S'], [441683.41, 14425121.91]), ('control #9', [74.243, 54.044, 43, 'S'], [450595.96, 16007279.04]), ('control #11', [162.356, -15.269, 58, 'N'], [216405.53, -1698880.3]), ('control #12', [-107.58, 5.652, 13, 'N'], [214531.37, 628855.65]), ('control #13', [100.982, 3.293, 47, 'S'], [719980.03, 10366237.05]), ('regression #14', [9.0, 0.5, 32, 'S'], [500000.0, 10055575.22]), ('boundary #16', [15.0, 0.0, 33, 'N'], [500000.0, 0.0]), ('boundary #18', [3.0, 45.0, 31, 'N'], [500000.0, 5001770.19])], [('control #7', [-31.602, 39.795, 25, 'S'], [619393.11, 14424164.48]), ('control #10', [-96.557, 39.544, 14, 'S'], [709406.66, 14398176.63]), ('regression #14', [9.0, 0.5, 32, 'S'], [500000.0, 10055575.22]), ('regression #15', [-75.5, 0.2, 18, 'S'], [444424.41, 10022230.94]), ('boundary #16', [15.0, 0.0, 33, 'N'], [500000.0, 0.0]), ('regression #17', [30.0, -0.3, 36, 'N'], [166400.77, -33390.89]), ('boundary #18', [3.0, 45.0, 31, 'N'], [500000.0, 5001770.19]), ('control #19', [12.3, -35.0, 33, 'S'], [254136.28, 6106410.11])]]\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":"Stipulated deterministic toy contract on a bounded input domain; results are rounded as stated and no conformance with any published standard or library is claimed. 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-map-projection-transforms-spherical-utm-forward-grid-hemisphere-flag","generated_at":"2026-09-29T14:48:16.703025+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Survey exports and GPS receivers express positions as UTM eastings and northings; a wrong false origin or meridian moves points by hundreds of kilometres.","repair":"At the grid hemisphere flag step restore `(10000000.0 if hemi == 'S' else 0.0)`, leaving the rest of the model unchanged.","root_cause":"The false northing is chosen from the sign of the point latitude instead of the requested grid hemisphere.","sha256":"4a545ff61aba3d968740002aac3329c8933104493c36ba89b4149319daad9096","title":"Spherical transverse mercator in a UTM grid: grid hemisphere flag · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":41.171,"exit_code":1,"observations":[{"actual":[525121.58,7275016.5],"check":"control #0","expected":[525121.58,17275016.5],"passed":false},{"actual":[699628.48,5361620.03],"check":"control #1","expected":[699628.48,15361620.03],"passed":false},{"actual":[476839.56,-3803819.3],"check":"control #2","expected":[476839.56,-3803819.3],"passed":true},{"actual":[413657.04,9851155.87],"check":"control #3","expected":[413657.04,9851155.87],"passed":true},{"actual":[459106.63,3630985.93],"check":"control #4","expected":[459106.63,3630985.93],"passed":true},{"actual":[826109.36,9198550.44],"check":"control #5","expected":[826109.36,9198550.44],"passed":true},{"actual":[441683.41,4425121.91],"check":"control #6","expected":[441683.41,14425121.91],"passed":false},{"actual":[619393.11,4424164.48],"check":"control #7","expected":[619393.11,14424164.48],"passed":false}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"control #0\", \"actual\": [525121.58, 7275016.5], \"expected\": [525121.58, 17275016.5], \"passed\": false}, {\"check\": \"control #1\", \"actual\": [699628.48, 5361620.03], \"expected\": [699628.48, 15361620.03], \"passed\": false}, {\"check\": \"control #2\", \"actual\": [476839.56, -3803819.3], \"expected\": [476839.56, -3803819.3], \"passed\": true}, {\"check\": \"control #3\", \"actual\": [413657.04, 9851155.87], \"expected\": [413657.04, 9851155.87], \"passed\": true}, {\"check\": \"control #4\", \"actual\": [459106.63, 3630985.93], \"expected\": [459106.63, 3630985.93], \"passed\": true}, {\"check\": \"control #5\", \"actual\": [826109.36, 9198550.44], \"expected\": [826109.36, 9198550.44], \"passed\": true}, {\"check\": \"control #6\", \"actual\": [441683.41, 4425121.91], \"expected\": [441683.41, 14425121.91], \"passed\": false}, {\"check\": \"control #7\", \"actual\": [619393.11, 4424164.48], \"expected\": [619393.11, 14424164.48], \"passed\": false}], \"passed\": false}\n"},"broken":{"elapsed_ms":41.4,"exit_code":1,"observations":[{"actual":[525121.58,7275016.5],"check":"control #0","expected":[525121.58,17275016.5],"passed":false},{"actual":[699628.48,5361620.03],"check":"control #1","expected":[699628.48,15361620.03],"passed":false},{"actual":[476839.56,6196180.7],"check":"control #2","expected":[476839.56,-3803819.3],"passed":false},{"actual":[413657.04,9851155.87],"check":"control #3","expected":[413657.04,9851155.87],"passed":true},{"actual":[459106.63,3630985.93],"check":"control #4","expected":[459106.63,3630985.93],"passed":true},{"actual":[826109.36,9198550.44],"check":"control #5","expected":[826109.36,9198550.44],"passed":true},{"actual":[441683.41,4425121.91],"check":"control #6","expected":[441683.41,14425121.91],"passed":false},{"actual":[619393.11,4424164.48],"check":"control #7","expected":[619393.11,14424164.48],"passed":false}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"control #0\", \"actual\": [525121.58, 7275016.5], \"expected\": [525121.58, 17275016.5], \"passed\": false}, {\"check\": \"control #1\", \"actual\": [699628.48, 5361620.03], \"expected\": [699628.48, 15361620.03], \"passed\": false}, {\"check\": \"control #2\", \"actual\": [476839.56, 6196180.7], \"expected\": [476839.56, -3803819.3], \"passed\": false}, {\"check\": \"control #3\", \"actual\": [413657.04, 9851155.87], \"expected\": [413657.04, 9851155.87], \"passed\": true}, {\"check\": \"control #4\", \"actual\": [459106.63, 3630985.93], \"expected\": [459106.63, 3630985.93], \"passed\": true}, {\"check\": \"control #5\", \"actual\": [826109.36, 9198550.44], \"expected\": [826109.36, 9198550.44], \"passed\": true}, {\"check\": \"control #6\", \"actual\": [441683.41, 4425121.91], \"expected\": [441683.41, 14425121.91], \"passed\": false}, {\"check\": \"control #7\", \"actual\": [619393.11, 4424164.48], \"expected\": [619393.11, 14424164.48], \"passed\": false}], \"passed\": false}\n"},"fixed":{"elapsed_ms":42.686,"exit_code":0,"observations":[{"actual":[525121.58,17275016.5],"check":"control #0","expected":[525121.58,17275016.5],"passed":true},{"actual":[699628.48,15361620.03],"check":"control #1","expected":[699628.48,15361620.03],"passed":true},{"actual":[476839.56,-3803819.3],"check":"control #2","expected":[476839.56,-3803819.3],"passed":true},{"actual":[413657.04,9851155.87],"check":"control #3","expected":[413657.04,9851155.87],"passed":true},{"actual":[459106.63,3630985.93],"check":"control #4","expected":[459106.63,3630985.93],"passed":true},{"actual":[826109.36,9198550.44],"check":"control #5","expected":[826109.36,9198550.44],"passed":true},{"actual":[441683.41,14425121.91],"check":"control #6","expected":[441683.41,14425121.91],"passed":true},{"actual":[619393.11,14424164.48],"check":"control #7","expected":[619393.11,14424164.48],"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"control #0\", \"actual\": [525121.58, 17275016.5], \"expected\": [525121.58, 17275016.5], \"passed\": true}, {\"check\": \"control #1\", \"actual\": [699628.48, 15361620.03], \"expected\": [699628.48, 15361620.03], \"passed\": true}, {\"check\": \"control #2\", \"actual\": [476839.56, -3803819.3], \"expected\": [476839.56, -3803819.3], \"passed\": true}, {\"check\": \"control #3\", \"actual\": [413657.04, 9851155.87], \"expected\": [413657.04, 9851155.87], \"passed\": true}, {\"check\": \"control #4\", \"actual\": [459106.63, 3630985.93], \"expected\": [459106.63, 3630985.93], \"passed\": true}, {\"check\": \"control #5\", \"actual\": [826109.36, 9198550.44], \"expected\": [826109.36, 9198550.44], \"passed\": true}, {\"check\": \"control #6\", \"actual\": [441683.41, 14425121.91], \"expected\": [441683.41, 14425121.91], \"passed\": true}, {\"check\": \"control #7\", \"actual\": [619393.11, 14424164.48], \"expected\": [619393.11, 14424164.48], \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}