FAILURE MAP
← Case archive

FA-69271 / Tide and marine navigation tables / Open access

Compass variation and deviation: Westerly corrections are treated as easterly · case 01

Conversions in westerly variation go the wrong way.

Verified by executionVariant 1 · 7 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The sign helper makes W positive.

VERIFIED REPAIR

East is positive, west negative.

Unsuccessful approach: Taking the sign from a leading minus sign ignores the E/W suffix.

Case contract

Input [value, frm, to, var, dev] with frm/to in C (compass), M (magnetic), T (true); var and dev like "3.5W"/"2E" (east positive). M=C+dev, T=M+var; converting downward subtracts. Return [value mod 360 rounded 1, total compass error dev+var as "x.xE"/"x.xW" or "0"].

Why this case matters

Tide tables and passage plans turn published predictions into go/no-go decisions about depth, clearance and timing.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
    val,frm,to,var,dev=x
    def sg(s):
        v=float(s[:-1])
        return v if s[-1]=='W' else -v
    lvl={'C':0,'M':1,'T':2}
    corr=[sg(dev),sg(var)]
    a,b=lvl[frm],lvl[to]
    if b>a: val+=sum(corr[a:b])
    else: val-=sum(corr[b:a])
    e=sum(corr)
    err='0' if e==0 else '%.1f%s'%(abs(e),'E' if e>0 else 'W')
    return [round(val%360,1),err]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('compass variation and deviation [100, "C", "T", "4W", "2E"]', [100, 'C', 'T', '4W', '2E'], [98.0, '2.0W']), ('compass variation and deviation [100, "T", "C", "4W", "2E"]', [100, 'T', 'C', '4W', '2E'], [102.0, '2.0W']), ('compass variation and deviation [355, "C", "M", "3W", "6E"]', [355, 'C', 'M', '3W', '6E'], [1.0, '3.0E']), ('compass variation and deviation [5, "T", "M", "7W", "1W"]', [5, 'T', 'M', '7W', '1W'], [12.0, '8.0W']), ('compass variation and deviation [5, "M", "T", "7W", "1W"]', [5, 'M', 'T', '7W', '1W'], [358.0, '8.0W']), ('compass variation and deviation [200, "M", "C", "0.5E", "1.5W"]', [200, 'M', 'C', '0.5E', '1.5W'], [201.5, '1.0W']), ('compass variation and deviation [200, "C", "M", "0.5E", "1.5W"]', [200, 'C', 'M', '0.5E', '1.5W'], [198.5, '1.0W'])], [('compass variation and deviation [100, "T", "C", "4W", "2E"]', [100, 'T', 'C', '4W', '2E'], [102.0, '2.0W']), ('compass variation and deviation [5, "T", "M", "7W", "1W"]', [5, 'T', 'M', '7W', '1W'], [12.0, '8.0W']), ('compass variation and deviation [5, "M", "T", "7W", "1W"]', [5, 'M', 'T', '7W', '1W'], [358.0, '8.0W']), ('compass variation and deviation [200, "M", "C", "0.5E", "1.5W"]', [200, 'M', 'C', '0.5E', '1.5W'], [201.5, '1.0W']), ('compass variation and deviation [200, "C", "M", "0.5E", "1.5W"]', [200, 'C', 'M', '0.5E', '1.5W'], [198.5, '1.0W']), ('compass variation and deviation [90, "T", "T", "3E", "3W"]', [90, 'T', 'T', '3E', '3W'], [90, '0']), ('compass variation and deviation [270.5, "C", "T", "12.5E", "3.5E"]', [270.5, 'C', 'T', '12.5E', '3.5E'], [286.5, '16.0E'])], [('compass variation and deviation [355, "C", "M", "3W", "6E"]', [355, 'C', 'M', '3W', '6E'], [1.0, '3.0E']), ('compass variation and deviation [200, "C", "M", "0.5E", "1.5W"]', [200, 'C', 'M', '0.5E', '1.5W'], [198.5, '1.0W']), ('compass variation and deviation [90, "T", "T", "3E", "3W"]', [90, 'T', 'T', '3E', '3W'], [90, '0']), ('compass variation and deviation [270.5, "C", "T", "12.5E", "3.5E"]', [270.5, 'C', 'T', '12.5E', '3.5E'], [286.5, '16.0E']), ('compass variation and deviation [1, "T", "C", "2E", "3E"]', [1, 'T', 'C', '2E', '3E'], [356.0, '5.0E']), ('compass variation and deviation [45, "C", "T", "3E", "3W"]', [45, 'C', 'T', '3E', '3W'], [45.0, '0']), ('compass variation and deviation [180, "M", "T", "0E", "2W"]', [180, 'M', 'T', '0E', '2W'], [180.0, '2.0W'])], [('compass variation and deviation [5, "T", "M", "7W", "1W"]', [5, 'T', 'M', '7W', '1W'], [12.0, '8.0W']), ('compass variation and deviation [1, "T", "C", "2E", "3E"]', [1, 'T', 'C', '2E', '3E'], [356.0, '5.0E']), ('compass variation and deviation [45, "C", "T", "3E", "3W"]', [45, 'C', 'T', '3E', '3W'], [45.0, '0']), ('compass variation and deviation [180, "M", "T", "0E", "2W"]', [180, 'M', 'T', '0E', '2W'], [180.0, '2.0W']), ('compass variation and deviation [100, "C", "T", "4W", "2E"]', [100, 'C', 'T', '4W', '2E'], [98.0, '2.0W']), ('compass variation and deviation [100, "T", "C", "4W", "2E"]', [100, 'T', 'C', '4W', '2E'], [102.0, '2.0W']), ('compass variation and deviation [355, "C", "M", "3W", "6E"]', [355, 'C', 'M', '3W', '6E'], [1.0, '3.0E'])], [('compass variation and deviation [5, "M", "T", "7W", "1W"]', [5, 'M', 'T', '7W', '1W'], [358.0, '8.0W']), ('compass variation and deviation [100, "C", "T", "4W", "2E"]', [100, 'C', 'T', '4W', '2E'], [98.0, '2.0W']), ('compass variation and deviation [100, "T", "C", "4W", "2E"]', [100, 'T', 'C', '4W', '2E'], [102.0, '2.0W']), ('compass variation and deviation [355, "C", "M", "3W", "6E"]', [355, 'C', 'M', '3W', '6E'], [1.0, '3.0E']), ('compass variation and deviation [5, "T", "M", "7W", "1W"]', [5, 'T', 'M', '7W', '1W'], [12.0, '8.0W']), ('compass variation and deviation [200, "M", "C", "0.5E", "1.5W"]', [200, 'M', 'C', '0.5E', '1.5W'], [201.5, '1.0W']), ('compass variation and deviation [200, "C", "M", "0.5E", "1.5W"]', [200, 'C', 'M', '0.5E', '1.5W'], [198.5, '1.0W'])]]
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 fixtureActualExpectedOutcome
compass variation and deviation [100, "C", "T", "4W", "2E"][102.0, '2.0E'][98.0, '2.0W']Failed
compass variation and deviation [100, "T", "C", "4W", "2E"][98.0, '2.0E'][102.0, '2.0W']Failed
compass variation and deviation [355, "C", "M", "3W", "6E"][349.0, '3.0W'][1.0, '3.0E']Failed
compass variation and deviation [5, "T", "M", "7W", "1W"][358.0, '8.0E'][12.0, '8.0W']Failed
compass variation and deviation [5, "M", "T", "7W", "1W"][12.0, '8.0E'][358.0, '8.0W']Failed
compass variation and deviation [200, "M", "C", "0.5E", "1.5W"][198.5, '1.0E'][201.5, '1.0W']Failed
compass variation and deviation [200, "C", "M", "0.5E", "1.5W"][201.5, '1.0E'][198.5, '1.0W']Failed

SHA-256 / b68e866fba7980dd79ff30aaf0582427ae9125c318466892d5d9ee9cc4a3c990

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
    val,frm,to,var,dev=x
    def sg(s):
        v=float(s[:-1])
        return v if s[0]!='-' else -v
    lvl={'C':0,'M':1,'T':2}
    corr=[sg(dev),sg(var)]
    a,b=lvl[frm],lvl[to]
    if b>a: val+=sum(corr[a:b])
    else: val-=sum(corr[b:a])
    e=sum(corr)
    err='0' if e==0 else '%.1f%s'%(abs(e),'E' if e>0 else 'W')
    return [round(val%360,1),err]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('compass variation and deviation [100, "C", "T", "4W", "2E"]', [100, 'C', 'T', '4W', '2E'], [98.0, '2.0W']), ('compass variation and deviation [100, "T", "C", "4W", "2E"]', [100, 'T', 'C', '4W', '2E'], [102.0, '2.0W']), ('compass variation and deviation [355, "C", "M", "3W", "6E"]', [355, 'C', 'M', '3W', '6E'], [1.0, '3.0E']), ('compass variation and deviation [5, "T", "M", "7W", "1W"]', [5, 'T', 'M', '7W', '1W'], [12.0, '8.0W']), ('compass variation and deviation [5, "M", "T", "7W", "1W"]', [5, 'M', 'T', '7W', '1W'], [358.0, '8.0W']), ('compass variation and deviation [200, "M", "C", "0.5E", "1.5W"]', [200, 'M', 'C', '0.5E', '1.5W'], [201.5, '1.0W']), ('compass variation and deviation [200, "C", "M", "0.5E", "1.5W"]', [200, 'C', 'M', '0.5E', '1.5W'], [198.5, '1.0W'])], [('compass variation and deviation [100, "T", "C", "4W", "2E"]', [100, 'T', 'C', '4W', '2E'], [102.0, '2.0W']), ('compass variation and deviation [5, "T", "M", "7W", "1W"]', [5, 'T', 'M', '7W', '1W'], [12.0, '8.0W']), ('compass variation and deviation [5, "M", "T", "7W", "1W"]', [5, 'M', 'T', '7W', '1W'], [358.0, '8.0W']), ('compass variation and deviation [200, "M", "C", "0.5E", "1.5W"]', [200, 'M', 'C', '0.5E', '1.5W'], [201.5, '1.0W']), ('compass variation and deviation [200, "C", "M", "0.5E", "1.5W"]', [200, 'C', 'M', '0.5E', '1.5W'], [198.5, '1.0W']), ('compass variation and deviation [90, "T", "T", "3E", "3W"]', [90, 'T', 'T', '3E', '3W'], [90, '0']), ('compass variation and deviation [270.5, "C", "T", "12.5E", "3.5E"]', [270.5, 'C', 'T', '12.5E', '3.5E'], [286.5, '16.0E'])], [('compass variation and deviation [355, "C", "M", "3W", "6E"]', [355, 'C', 'M', '3W', '6E'], [1.0, '3.0E']), ('compass variation and deviation [200, "C", "M", "0.5E", "1.5W"]', [200, 'C', 'M', '0.5E', '1.5W'], [198.5, '1.0W']), ('compass variation and deviation [90, "T", "T", "3E", "3W"]', [90, 'T', 'T', '3E', '3W'], [90, '0']), ('compass variation and deviation [270.5, "C", "T", "12.5E", "3.5E"]', [270.5, 'C', 'T', '12.5E', '3.5E'], [286.5, '16.0E']), ('compass variation and deviation [1, "T", "C", "2E", "3E"]', [1, 'T', 'C', '2E', '3E'], [356.0, '5.0E']), ('compass variation and deviation [45, "C", "T", "3E", "3W"]', [45, 'C', 'T', '3E', '3W'], [45.0, '0']), ('compass variation and deviation [180, "M", "T", "0E", "2W"]', [180, 'M', 'T', '0E', '2W'], [180.0, '2.0W'])], [('compass variation and deviation [5, "T", "M", "7W", "1W"]', [5, 'T', 'M', '7W', '1W'], [12.0, '8.0W']), ('compass variation and deviation [1, "T", "C", "2E", "3E"]', [1, 'T', 'C', '2E', '3E'], [356.0, '5.0E']), ('compass variation and deviation [45, "C", "T", "3E", "3W"]', [45, 'C', 'T', '3E', '3W'], [45.0, '0']), ('compass variation and deviation [180, "M", "T", "0E", "2W"]', [180, 'M', 'T', '0E', '2W'], [180.0, '2.0W']), ('compass variation and deviation [100, "C", "T", "4W", "2E"]', [100, 'C', 'T', '4W', '2E'], [98.0, '2.0W']), ('compass variation and deviation [100, "T", "C", "4W", "2E"]', [100, 'T', 'C', '4W', '2E'], [102.0, '2.0W']), ('compass variation and deviation [355, "C", "M", "3W", "6E"]', [355, 'C', 'M', '3W', '6E'], [1.0, '3.0E'])], [('compass variation and deviation [5, "M", "T", "7W", "1W"]', [5, 'M', 'T', '7W', '1W'], [358.0, '8.0W']), ('compass variation and deviation [100, "C", "T", "4W", "2E"]', [100, 'C', 'T', '4W', '2E'], [98.0, '2.0W']), ('compass variation and deviation [100, "T", "C", "4W", "2E"]', [100, 'T', 'C', '4W', '2E'], [102.0, '2.0W']), ('compass variation and deviation [355, "C", "M", "3W", "6E"]', [355, 'C', 'M', '3W', '6E'], [1.0, '3.0E']), ('compass variation and deviation [5, "T", "M", "7W", "1W"]', [5, 'T', 'M', '7W', '1W'], [12.0, '8.0W']), ('compass variation and deviation [200, "M", "C", "0.5E", "1.5W"]', [200, 'M', 'C', '0.5E', '1.5W'], [201.5, '1.0W']), ('compass variation and deviation [200, "C", "M", "0.5E", "1.5W"]', [200, 'C', 'M', '0.5E', '1.5W'], [198.5, '1.0W'])]]
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 fixtureActualExpectedOutcome
compass variation and deviation [100, "C", "T", "4W", "2E"][106.0, '6.0E'][98.0, '2.0W']Failed
compass variation and deviation [100, "T", "C", "4W", "2E"][94.0, '6.0E'][102.0, '2.0W']Failed
compass variation and deviation [355, "C", "M", "3W", "6E"][1.0, '9.0E'][1.0, '3.0E']Failed
compass variation and deviation [5, "T", "M", "7W", "1W"][358.0, '8.0E'][12.0, '8.0W']Failed
compass variation and deviation [5, "M", "T", "7W", "1W"][12.0, '8.0E'][358.0, '8.0W']Failed
compass variation and deviation [200, "M", "C", "0.5E", "1.5W"][198.5, '2.0E'][201.5, '1.0W']Failed
compass variation and deviation [200, "C", "M", "0.5E", "1.5W"][201.5, '2.0E'][198.5, '1.0W']Failed

SHA-256 / 316dedb62c33aa0f58dc36b1d6423602b28a4686ae07496f347c9c97547eb2dc

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(x):
    val,frm,to,var,dev=x
    def sg(s):
        v=float(s[:-1])
        return v if s[-1]=='E' else -v
    lvl={'C':0,'M':1,'T':2}
    corr=[sg(dev),sg(var)]
    a,b=lvl[frm],lvl[to]
    if b>a: val+=sum(corr[a:b])
    else: val-=sum(corr[b:a])
    e=sum(corr)
    err='0' if e==0 else '%.1f%s'%(abs(e),'E' if e>0 else 'W')
    return [round(val%360,1),err]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('compass variation and deviation [100, "C", "T", "4W", "2E"]', [100, 'C', 'T', '4W', '2E'], [98.0, '2.0W']), ('compass variation and deviation [100, "T", "C", "4W", "2E"]', [100, 'T', 'C', '4W', '2E'], [102.0, '2.0W']), ('compass variation and deviation [355, "C", "M", "3W", "6E"]', [355, 'C', 'M', '3W', '6E'], [1.0, '3.0E']), ('compass variation and deviation [5, "T", "M", "7W", "1W"]', [5, 'T', 'M', '7W', '1W'], [12.0, '8.0W']), ('compass variation and deviation [5, "M", "T", "7W", "1W"]', [5, 'M', 'T', '7W', '1W'], [358.0, '8.0W']), ('compass variation and deviation [200, "M", "C", "0.5E", "1.5W"]', [200, 'M', 'C', '0.5E', '1.5W'], [201.5, '1.0W']), ('compass variation and deviation [200, "C", "M", "0.5E", "1.5W"]', [200, 'C', 'M', '0.5E', '1.5W'], [198.5, '1.0W'])], [('compass variation and deviation [100, "T", "C", "4W", "2E"]', [100, 'T', 'C', '4W', '2E'], [102.0, '2.0W']), ('compass variation and deviation [5, "T", "M", "7W", "1W"]', [5, 'T', 'M', '7W', '1W'], [12.0, '8.0W']), ('compass variation and deviation [5, "M", "T", "7W", "1W"]', [5, 'M', 'T', '7W', '1W'], [358.0, '8.0W']), ('compass variation and deviation [200, "M", "C", "0.5E", "1.5W"]', [200, 'M', 'C', '0.5E', '1.5W'], [201.5, '1.0W']), ('compass variation and deviation [200, "C", "M", "0.5E", "1.5W"]', [200, 'C', 'M', '0.5E', '1.5W'], [198.5, '1.0W']), ('compass variation and deviation [90, "T", "T", "3E", "3W"]', [90, 'T', 'T', '3E', '3W'], [90, '0']), ('compass variation and deviation [270.5, "C", "T", "12.5E", "3.5E"]', [270.5, 'C', 'T', '12.5E', '3.5E'], [286.5, '16.0E'])], [('compass variation and deviation [355, "C", "M", "3W", "6E"]', [355, 'C', 'M', '3W', '6E'], [1.0, '3.0E']), ('compass variation and deviation [200, "C", "M", "0.5E", "1.5W"]', [200, 'C', 'M', '0.5E', '1.5W'], [198.5, '1.0W']), ('compass variation and deviation [90, "T", "T", "3E", "3W"]', [90, 'T', 'T', '3E', '3W'], [90, '0']), ('compass variation and deviation [270.5, "C", "T", "12.5E", "3.5E"]', [270.5, 'C', 'T', '12.5E', '3.5E'], [286.5, '16.0E']), ('compass variation and deviation [1, "T", "C", "2E", "3E"]', [1, 'T', 'C', '2E', '3E'], [356.0, '5.0E']), ('compass variation and deviation [45, "C", "T", "3E", "3W"]', [45, 'C', 'T', '3E', '3W'], [45.0, '0']), ('compass variation and deviation [180, "M", "T", "0E", "2W"]', [180, 'M', 'T', '0E', '2W'], [180.0, '2.0W'])], [('compass variation and deviation [5, "T", "M", "7W", "1W"]', [5, 'T', 'M', '7W', '1W'], [12.0, '8.0W']), ('compass variation and deviation [1, "T", "C", "2E", "3E"]', [1, 'T', 'C', '2E', '3E'], [356.0, '5.0E']), ('compass variation and deviation [45, "C", "T", "3E", "3W"]', [45, 'C', 'T', '3E', '3W'], [45.0, '0']), ('compass variation and deviation [180, "M", "T", "0E", "2W"]', [180, 'M', 'T', '0E', '2W'], [180.0, '2.0W']), ('compass variation and deviation [100, "C", "T", "4W", "2E"]', [100, 'C', 'T', '4W', '2E'], [98.0, '2.0W']), ('compass variation and deviation [100, "T", "C", "4W", "2E"]', [100, 'T', 'C', '4W', '2E'], [102.0, '2.0W']), ('compass variation and deviation [355, "C", "M", "3W", "6E"]', [355, 'C', 'M', '3W', '6E'], [1.0, '3.0E'])], [('compass variation and deviation [5, "M", "T", "7W", "1W"]', [5, 'M', 'T', '7W', '1W'], [358.0, '8.0W']), ('compass variation and deviation [100, "C", "T", "4W", "2E"]', [100, 'C', 'T', '4W', '2E'], [98.0, '2.0W']), ('compass variation and deviation [100, "T", "C", "4W", "2E"]', [100, 'T', 'C', '4W', '2E'], [102.0, '2.0W']), ('compass variation and deviation [355, "C", "M", "3W", "6E"]', [355, 'C', 'M', '3W', '6E'], [1.0, '3.0E']), ('compass variation and deviation [5, "T", "M", "7W", "1W"]', [5, 'T', 'M', '7W', '1W'], [12.0, '8.0W']), ('compass variation and deviation [200, "M", "C", "0.5E", "1.5W"]', [200, 'M', 'C', '0.5E', '1.5W'], [201.5, '1.0W']), ('compass variation and deviation [200, "C", "M", "0.5E", "1.5W"]', [200, 'C', 'M', '0.5E', '1.5W'], [198.5, '1.0W'])]]
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 fixtureActualExpectedOutcome
compass variation and deviation [100, "C", "T", "4W", "2E"][98.0, '2.0W'][98.0, '2.0W']Passed
compass variation and deviation [100, "T", "C", "4W", "2E"][102.0, '2.0W'][102.0, '2.0W']Passed
compass variation and deviation [355, "C", "M", "3W", "6E"][1.0, '3.0E'][1.0, '3.0E']Passed
compass variation and deviation [5, "T", "M", "7W", "1W"][12.0, '8.0W'][12.0, '8.0W']Passed
compass variation and deviation [5, "M", "T", "7W", "1W"][358.0, '8.0W'][358.0, '8.0W']Passed
compass variation and deviation [200, "M", "C", "0.5E", "1.5W"][201.5, '1.0W'][201.5, '1.0W']Passed
compass variation and deviation [200, "C", "M", "0.5E", "1.5W"][198.5, '1.0W'][198.5, '1.0W']Passed

SHA-256 / dbdbf0456ca6697447279b0ae283ced1a6bce543b3fd01e1d71c28ae9d0b5d7e

Verification & scope

A deterministic toy model with stipulated rules and constants; not certified hydrographic software or a substitute for official tide tables. 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:09.958114+00:00.

Case digest / 40e5e3bfa27da390e7f9d09d8541a61adf9c6f56684a16bf86ce0f315c870d4e