FA-69856 / Map projection transforms / Open access
Spherical web mercator forward projection: easting angular unit · case 01
Eastings are 57 times too large.
ROOT CAUSE
The easting multiplies the radius by longitude in degrees rather than radians.
VERIFIED REPAIR
At the easting angular unit step restore `px = R * math.radians(lon)`, leaving the rest of the model unchanged.
Unsuccessful approach: The conversion divides by 360 instead of 180, halving every easting.
Case contract
Input [lon, lat] in degrees. Longitude is first wrapped into the half-open range [-180, 180); latitude is clamped to +/-85.05112878. Return [x, y] metres on a sphere of radius 6378137 with y growing northward, each rounded to 3 decimals.
Why this case matters
Web map tiles, vector tile encoders and map viewers all start from this forward transform; small mistakes shift features by kilometres or mirror them across the equator.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
lon, lat = x
lon = ((lon + 180.0) % 360.0) - 180.0
lat = max(-85.05112878, min(85.05112878, lat))
R = 6378137.0
px = R * lon
py = R * math.log(math.tan(math.pi / 4 + math.radians(lat) / 2))
return [round(px, 3), round(py, 3)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression #0', [190.0, 10.0], [-18924313.435, 1118889.975]), ('regression #1', [-200.0, -20.0], [17811118.527, -2273030.927]), ('boundary #2', [180.0, 0.0], [-20037508.343, -0.0]), ('boundary #3', [-180.0, 45.0], [-20037508.343, 5621521.486]), ('regression #4', [545.0, 5.0], [-19480910.889, 557305.257]), ('boundary #5', [0.0, 89.0], [0.0, 20037508.343]), ('boundary #7', [0.0, 85.05112878], [0.0, 20037508.343]), ('control #8', [0.0, 0.0], [0.0, -0.0])], [('regression #1', [-200.0, -20.0], [17811118.527, -2273030.927]), ('boundary #2', [180.0, 0.0], [-20037508.343, -0.0]), ('boundary #5', [0.0, 89.0], [0.0, 20037508.343]), ('boundary #6', [10.0, -88.0], [1113194.908, -20037508.343]), ('boundary #7', [0.0, 85.05112878], [0.0, 20037508.343]), ('control #8', [0.0, 0.0], [0.0, -0.0]), ('regression #9', [-540.0, 30.0], [-20037508.343, 3503549.844]), ('regression #10', [-250.0, 12.5], [12245143.987, 1402665.19])], [('boundary #2', [180.0, 0.0], [-20037508.343, -0.0]), ('boundary #3', [-180.0, 45.0], [-20037508.343, 5621521.486]), ('boundary #5', [0.0, 89.0], [0.0, 20037508.343]), ('boundary #7', [0.0, 85.05112878], [0.0, 20037508.343]), ('control #8', [0.0, 0.0], [0.0, -0.0]), ('regression #9', [-540.0, 30.0], [-20037508.343, 3503549.844]), ('regression #10', [-250.0, 12.5], [12245143.987, 1402665.19]), ('regression #11', [-359.5, -40.0], [55659.745, -4865942.28])], [('boundary #3', [-180.0, 45.0], [-20037508.343, 5621521.486]), ('regression #4', [545.0, 5.0], [-19480910.889, 557305.257]), ('boundary #5', [0.0, 89.0], [0.0, 20037508.343]), ('boundary #7', [0.0, 85.05112878], [0.0, 20037508.343]), ('control #8', [0.0, 0.0], [0.0, -0.0]), ('regression #11', [-359.5, -40.0], [55659.745, -4865942.28]), ('boundary #12', [45.0, -86.5], [5009377.086, -20037508.343]), ('boundary #13', [-120.0, -87.25], [-13358338.895, -20037508.343])], [('regression #4', [545.0, 5.0], [-19480910.889, 557305.257]), ('boundary #5', [0.0, 89.0], [0.0, 20037508.343]), ('boundary #6', [10.0, -88.0], [1113194.908, -20037508.343]), ('boundary #7', [0.0, 85.05112878], [0.0, 20037508.343]), ('control #8', [0.0, 0.0], [0.0, -0.0]), ('regression #14', [-181.0, 0.5], [19926188.852, 55660.452]), ('control #15', [-17.048, 10.042], [-1897774.679, 1123637.827]), ('control #16', [151.867, -5.771], [16905757.108, -643513.79])]]
for label, args, expected in fixtures[N-1]:
check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression #0 | [-1084283290.0, 1118889.975] | [-18924313.435, 1118889.975] | Failed |
| regression #1 | [1020501920.0, -2273030.927] | [17811118.527, -2273030.927] | Failed |
| boundary #2 | [-1148064660.0, -0.0] | [-20037508.343, -0.0] | Failed |
| boundary #3 | [-1148064660.0, 5621521.486] | [-20037508.343, 5621521.486] | Failed |
| regression #4 | [-1116173975.0, 557305.257] | [-19480910.889, 557305.257] | Failed |
| boundary #5 | [0.0, 20037508.343] | [0.0, 20037508.343] | Passed |
| boundary #7 | [0.0, 20037508.343] | [0.0, 20037508.343] | Passed |
| control #8 | [0.0, -0.0] | [0.0, -0.0] | Passed |
SHA-256 / 7c60b4a3acb6ea77fba7e0d4a273bc383ff0fdf942bfe33d821099c0d7ce6128
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
lon, lat = x
lon = ((lon + 180.0) % 360.0) - 180.0
lat = max(-85.05112878, min(85.05112878, lat))
R = 6378137.0
px = R * lon * math.pi / 360.0
py = R * math.log(math.tan(math.pi / 4 + math.radians(lat) / 2))
return [round(px, 3), round(py, 3)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression #0', [190.0, 10.0], [-18924313.435, 1118889.975]), ('regression #1', [-200.0, -20.0], [17811118.527, -2273030.927]), ('boundary #2', [180.0, 0.0], [-20037508.343, -0.0]), ('boundary #3', [-180.0, 45.0], [-20037508.343, 5621521.486]), ('regression #4', [545.0, 5.0], [-19480910.889, 557305.257]), ('boundary #5', [0.0, 89.0], [0.0, 20037508.343]), ('boundary #7', [0.0, 85.05112878], [0.0, 20037508.343]), ('control #8', [0.0, 0.0], [0.0, -0.0])], [('regression #1', [-200.0, -20.0], [17811118.527, -2273030.927]), ('boundary #2', [180.0, 0.0], [-20037508.343, -0.0]), ('boundary #5', [0.0, 89.0], [0.0, 20037508.343]), ('boundary #6', [10.0, -88.0], [1113194.908, -20037508.343]), ('boundary #7', [0.0, 85.05112878], [0.0, 20037508.343]), ('control #8', [0.0, 0.0], [0.0, -0.0]), ('regression #9', [-540.0, 30.0], [-20037508.343, 3503549.844]), ('regression #10', [-250.0, 12.5], [12245143.987, 1402665.19])], [('boundary #2', [180.0, 0.0], [-20037508.343, -0.0]), ('boundary #3', [-180.0, 45.0], [-20037508.343, 5621521.486]), ('boundary #5', [0.0, 89.0], [0.0, 20037508.343]), ('boundary #7', [0.0, 85.05112878], [0.0, 20037508.343]), ('control #8', [0.0, 0.0], [0.0, -0.0]), ('regression #9', [-540.0, 30.0], [-20037508.343, 3503549.844]), ('regression #10', [-250.0, 12.5], [12245143.987, 1402665.19]), ('regression #11', [-359.5, -40.0], [55659.745, -4865942.28])], [('boundary #3', [-180.0, 45.0], [-20037508.343, 5621521.486]), ('regression #4', [545.0, 5.0], [-19480910.889, 557305.257]), ('boundary #5', [0.0, 89.0], [0.0, 20037508.343]), ('boundary #7', [0.0, 85.05112878], [0.0, 20037508.343]), ('control #8', [0.0, 0.0], [0.0, -0.0]), ('regression #11', [-359.5, -40.0], [55659.745, -4865942.28]), ('boundary #12', [45.0, -86.5], [5009377.086, -20037508.343]), ('boundary #13', [-120.0, -87.25], [-13358338.895, -20037508.343])], [('regression #4', [545.0, 5.0], [-19480910.889, 557305.257]), ('boundary #5', [0.0, 89.0], [0.0, 20037508.343]), ('boundary #6', [10.0, -88.0], [1113194.908, -20037508.343]), ('boundary #7', [0.0, 85.05112878], [0.0, 20037508.343]), ('control #8', [0.0, 0.0], [0.0, -0.0]), ('regression #14', [-181.0, 0.5], [19926188.852, 55660.452]), ('control #15', [-17.048, 10.042], [-1897774.679, 1123637.827]), ('control #16', [151.867, -5.771], [16905757.108, -643513.79])]]
for label, args, expected in fixtures[N-1]:
check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression #0 | [-9462156.717, 1118889.975] | [-18924313.435, 1118889.975] | Failed |
| regression #1 | [8905559.263, -2273030.927] | [17811118.527, -2273030.927] | Failed |
| boundary #2 | [-10018754.171, -0.0] | [-20037508.343, -0.0] | Failed |
| boundary #3 | [-10018754.171, 5621521.486] | [-20037508.343, 5621521.486] | Failed |
| regression #4 | [-9740455.444, 557305.257] | [-19480910.889, 557305.257] | Failed |
| boundary #5 | [0.0, 20037508.343] | [0.0, 20037508.343] | Passed |
| boundary #7 | [0.0, 20037508.343] | [0.0, 20037508.343] | Passed |
| control #8 | [0.0, -0.0] | [0.0, -0.0] | Passed |
SHA-256 / b05c06b89c883674e58d37363d7d503b760c5f5b6fb97d75785b59a06e03a5d3
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
lon, lat = x
lon = ((lon + 180.0) % 360.0) - 180.0
lat = max(-85.05112878, min(85.05112878, lat))
R = 6378137.0
px = R * math.radians(lon)
py = R * math.log(math.tan(math.pi / 4 + math.radians(lat) / 2))
return [round(px, 3), round(py, 3)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression #0', [190.0, 10.0], [-18924313.435, 1118889.975]), ('regression #1', [-200.0, -20.0], [17811118.527, -2273030.927]), ('boundary #2', [180.0, 0.0], [-20037508.343, -0.0]), ('boundary #3', [-180.0, 45.0], [-20037508.343, 5621521.486]), ('regression #4', [545.0, 5.0], [-19480910.889, 557305.257]), ('boundary #5', [0.0, 89.0], [0.0, 20037508.343]), ('boundary #7', [0.0, 85.05112878], [0.0, 20037508.343]), ('control #8', [0.0, 0.0], [0.0, -0.0])], [('regression #1', [-200.0, -20.0], [17811118.527, -2273030.927]), ('boundary #2', [180.0, 0.0], [-20037508.343, -0.0]), ('boundary #5', [0.0, 89.0], [0.0, 20037508.343]), ('boundary #6', [10.0, -88.0], [1113194.908, -20037508.343]), ('boundary #7', [0.0, 85.05112878], [0.0, 20037508.343]), ('control #8', [0.0, 0.0], [0.0, -0.0]), ('regression #9', [-540.0, 30.0], [-20037508.343, 3503549.844]), ('regression #10', [-250.0, 12.5], [12245143.987, 1402665.19])], [('boundary #2', [180.0, 0.0], [-20037508.343, -0.0]), ('boundary #3', [-180.0, 45.0], [-20037508.343, 5621521.486]), ('boundary #5', [0.0, 89.0], [0.0, 20037508.343]), ('boundary #7', [0.0, 85.05112878], [0.0, 20037508.343]), ('control #8', [0.0, 0.0], [0.0, -0.0]), ('regression #9', [-540.0, 30.0], [-20037508.343, 3503549.844]), ('regression #10', [-250.0, 12.5], [12245143.987, 1402665.19]), ('regression #11', [-359.5, -40.0], [55659.745, -4865942.28])], [('boundary #3', [-180.0, 45.0], [-20037508.343, 5621521.486]), ('regression #4', [545.0, 5.0], [-19480910.889, 557305.257]), ('boundary #5', [0.0, 89.0], [0.0, 20037508.343]), ('boundary #7', [0.0, 85.05112878], [0.0, 20037508.343]), ('control #8', [0.0, 0.0], [0.0, -0.0]), ('regression #11', [-359.5, -40.0], [55659.745, -4865942.28]), ('boundary #12', [45.0, -86.5], [5009377.086, -20037508.343]), ('boundary #13', [-120.0, -87.25], [-13358338.895, -20037508.343])], [('regression #4', [545.0, 5.0], [-19480910.889, 557305.257]), ('boundary #5', [0.0, 89.0], [0.0, 20037508.343]), ('boundary #6', [10.0, -88.0], [1113194.908, -20037508.343]), ('boundary #7', [0.0, 85.05112878], [0.0, 20037508.343]), ('control #8', [0.0, 0.0], [0.0, -0.0]), ('regression #14', [-181.0, 0.5], [19926188.852, 55660.452]), ('control #15', [-17.048, 10.042], [-1897774.679, 1123637.827]), ('control #16', [151.867, -5.771], [16905757.108, -643513.79])]]
for label, args, expected in fixtures[N-1]:
check(label, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression #0 | [-18924313.435, 1118889.975] | [-18924313.435, 1118889.975] | Passed |
| regression #1 | [17811118.527, -2273030.927] | [17811118.527, -2273030.927] | Passed |
| boundary #2 | [-20037508.343, -0.0] | [-20037508.343, -0.0] | Passed |
| boundary #3 | [-20037508.343, 5621521.486] | [-20037508.343, 5621521.486] | Passed |
| regression #4 | [-19480910.889, 557305.257] | [-19480910.889, 557305.257] | Passed |
| boundary #5 | [0.0, 20037508.343] | [0.0, 20037508.343] | Passed |
| boundary #7 | [0.0, 20037508.343] | [0.0, 20037508.343] | Passed |
| control #8 | [0.0, -0.0] | [0.0, -0.0] | Passed |
SHA-256 / c52abedf9ac99b6996a0a4fa2206035fbbaa33fca459726cc6cc8578e98f0421
Verification & scope
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.
Observations recorded using Python 3.12.14 at 2026-09-29T14:48:15.237472+00:00.
Case digest / e17ff2514caa140883c6c7367e842deebf9415e462a4760de868b53684e63ab3