FA-72691 / Check-digit algorithms / Open access
UK VAT weights start at seven · case 01
Valid VAT numbers are reported invalid.
ROOT CAUSE
The weights come from range(7, 0, -1) instead of 8 down to 2.
VERIFIED REPAIR
Weight the seven leading digits 8, 7, 6, 5, 4, 3, 2.
Unsuccessful approach: Ascending weights 2..8 apply the right values to the wrong positions.
Case contract
UK VAT registration number check. Spaces are removed, the text is upper-cased and an optional GB prefix removed; the rest must be 9 ASCII digits (else "malformed"). Weights 8..2 apply to the first seven digits; the last two digits form a number c. Return "mod97" if (sum + c) is divisible by 97, "mod9755" if (sum + c + 55) is, else "invalid".
Why this case matters
Invoice processing screens supplier VAT numbers before reclaiming input tax.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(s):
t = s.replace(' ', '').upper()
if t.startswith('GB'):
t = t[2:]
if len(t) != 9 or not t.isascii() or not t.isdigit():
return 'malformed'
total = sum(int(ch) * w for ch, w in zip(t[:7], range(7, 0, -1)))
c = int(t[7:])
if (total + c) % 97 == 0:
return 'mod97'
if (total + c + 55) % 97 == 0:
return 'mod9755'
return 'invalid'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression ["GB041839277"]', ['GB041839277'], 'mod97'], ['regression ["GB 261 7623 04"]', ['GB 261 7623 04'], 'mod9755'], ['partial-repair ["729236520"]', ['729236520'], 'mod97'], ['control ["041839278"]', ['041839278'], 'invalid'], ['control ["261762305"]', ['261762305'], 'invalid'], ['control ["729236521"]', ['729236521'], 'invalid'], ['control ["260407727"]', ['260407727'], 'invalid'], ['control ["029331391"]', ['029331391'], 'invalid']], [['regression ["GB260407726"]', ['GB260407726'], 'mod9755'], ['regression ["GB 029 3313 90"]', ['GB 029 3313 90'], 'mod97'], ['partial-repair ["581077575"]', ['581077575'], 'mod9755'], ['control ["581077576"]', ['581077576'], 'invalid'], ['control ["GB98078068"]', ['GB98078068'], 'malformed'], ['control ["GB98078068X"]', ['GB98078068X'], 'malformed'], ['control ["123456789"]', ['123456789'], 'invalid'], ['control ["041839278"]', ['041839278'], 'invalid']], [['regression ["GB658372602"]', ['GB658372602'], 'mod97'], ['regression ["GB 225 8573 89"]', ['GB 225 8573 89'], 'mod9755'], ['partial-repair ["331553089"]', ['331553089'], 'mod97'], ['control ["261762305"]', ['261762305'], 'invalid'], ['control ["729236521"]', ['729236521'], 'invalid'], ['control ["260407727"]', ['260407727'], 'invalid'], ['control ["029331391"]', ['029331391'], 'invalid'], ['control ["581077576"]', ['581077576'], 'invalid']], [['regression ["GB784073455"]', ['GB784073455'], 'mod9755'], ['regression ["GB 397 1093 27"]', ['GB 397 1093 27'], 'mod97'], ['partial-repair ["155142529"]', ['155142529'], 'mod9755'], ['control ["GB98078068"]', ['GB98078068'], 'malformed'], ['control ["GB98078068X"]', ['GB98078068X'], 'malformed'], ['control ["123456789"]', ['123456789'], 'invalid'], ['control ["041839278"]', ['041839278'], 'invalid'], ['control ["261762305"]', ['261762305'], 'invalid']], [['regression ["GB801525174"]', ['GB801525174'], 'mod97'], ['regression ["GB 307 8958 63"]', ['GB 307 8958 63'], 'mod9755'], ['partial-repair ["GB980780684"]', ['GB980780684'], 'mod97'], ['control ["729236521"]', ['729236521'], 'invalid'], ['control ["260407727"]', ['260407727'], 'invalid'], ['control ["029331391"]', ['029331391'], 'invalid'], ['control ["581077576"]', ['581077576'], 'invalid'], ['control ["GB98078068"]', ['GB98078068'], 'malformed']]]
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 ["GB041839277"] | invalid | mod97 | Failed |
| regression ["GB 261 7623 04"] | invalid | mod9755 | Failed |
| partial-repair ["729236520"] | invalid | mod97 | Failed |
| control ["041839278"] | invalid | invalid | Passed |
| control ["261762305"] | invalid | invalid | Passed |
| control ["729236521"] | invalid | invalid | Passed |
| control ["260407727"] | invalid | invalid | Passed |
| control ["029331391"] | invalid | invalid | Passed |
SHA-256 / 44afd3875f747078e31bc30288922759f6cd7204cc4f67843bc9b193f12f3478
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(s):
t = s.replace(' ', '').upper()
if t.startswith('GB'):
t = t[2:]
if len(t) != 9 or not t.isascii() or not t.isdigit():
return 'malformed'
total = sum(int(ch) * w for ch, w in zip(t[:7], range(2, 9)))
c = int(t[7:])
if (total + c) % 97 == 0:
return 'mod97'
if (total + c + 55) % 97 == 0:
return 'mod9755'
return 'invalid'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression ["GB041839277"]', ['GB041839277'], 'mod97'], ['regression ["GB 261 7623 04"]', ['GB 261 7623 04'], 'mod9755'], ['partial-repair ["729236520"]', ['729236520'], 'mod97'], ['control ["041839278"]', ['041839278'], 'invalid'], ['control ["261762305"]', ['261762305'], 'invalid'], ['control ["729236521"]', ['729236521'], 'invalid'], ['control ["260407727"]', ['260407727'], 'invalid'], ['control ["029331391"]', ['029331391'], 'invalid']], [['regression ["GB260407726"]', ['GB260407726'], 'mod9755'], ['regression ["GB 029 3313 90"]', ['GB 029 3313 90'], 'mod97'], ['partial-repair ["581077575"]', ['581077575'], 'mod9755'], ['control ["581077576"]', ['581077576'], 'invalid'], ['control ["GB98078068"]', ['GB98078068'], 'malformed'], ['control ["GB98078068X"]', ['GB98078068X'], 'malformed'], ['control ["123456789"]', ['123456789'], 'invalid'], ['control ["041839278"]', ['041839278'], 'invalid']], [['regression ["GB658372602"]', ['GB658372602'], 'mod97'], ['regression ["GB 225 8573 89"]', ['GB 225 8573 89'], 'mod9755'], ['partial-repair ["331553089"]', ['331553089'], 'mod97'], ['control ["261762305"]', ['261762305'], 'invalid'], ['control ["729236521"]', ['729236521'], 'invalid'], ['control ["260407727"]', ['260407727'], 'invalid'], ['control ["029331391"]', ['029331391'], 'invalid'], ['control ["581077576"]', ['581077576'], 'invalid']], [['regression ["GB784073455"]', ['GB784073455'], 'mod9755'], ['regression ["GB 397 1093 27"]', ['GB 397 1093 27'], 'mod97'], ['partial-repair ["155142529"]', ['155142529'], 'mod9755'], ['control ["GB98078068"]', ['GB98078068'], 'malformed'], ['control ["GB98078068X"]', ['GB98078068X'], 'malformed'], ['control ["123456789"]', ['123456789'], 'invalid'], ['control ["041839278"]', ['041839278'], 'invalid'], ['control ["261762305"]', ['261762305'], 'invalid']], [['regression ["GB801525174"]', ['GB801525174'], 'mod97'], ['regression ["GB 307 8958 63"]', ['GB 307 8958 63'], 'mod9755'], ['partial-repair ["GB980780684"]', ['GB980780684'], 'mod97'], ['control ["729236521"]', ['729236521'], 'invalid'], ['control ["260407727"]', ['260407727'], 'invalid'], ['control ["029331391"]', ['029331391'], 'invalid'], ['control ["581077576"]', ['581077576'], 'invalid'], ['control ["GB98078068"]', ['GB98078068'], 'malformed']]]
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 ["GB041839277"] | invalid | mod97 | Failed |
| regression ["GB 261 7623 04"] | mod9755 | mod9755 | Passed |
| partial-repair ["729236520"] | invalid | mod97 | Failed |
| control ["041839278"] | invalid | invalid | Passed |
| control ["261762305"] | invalid | invalid | Passed |
| control ["729236521"] | invalid | invalid | Passed |
| control ["260407727"] | invalid | invalid | Passed |
| control ["029331391"] | invalid | invalid | Passed |
SHA-256 / e1112f8861a42e8a2f5cf2b400c7b224a5f2fdf150f09935ef5e401cc5c63d67
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(s):
t = s.replace(' ', '').upper()
if t.startswith('GB'):
t = t[2:]
if len(t) != 9 or not t.isascii() or not t.isdigit():
return 'malformed'
total = sum(int(ch) * w for ch, w in zip(t[:7], range(8, 1, -1)))
c = int(t[7:])
if (total + c) % 97 == 0:
return 'mod97'
if (total + c + 55) % 97 == 0:
return 'mod9755'
return 'invalid'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression ["GB041839277"]', ['GB041839277'], 'mod97'], ['regression ["GB 261 7623 04"]', ['GB 261 7623 04'], 'mod9755'], ['partial-repair ["729236520"]', ['729236520'], 'mod97'], ['control ["041839278"]', ['041839278'], 'invalid'], ['control ["261762305"]', ['261762305'], 'invalid'], ['control ["729236521"]', ['729236521'], 'invalid'], ['control ["260407727"]', ['260407727'], 'invalid'], ['control ["029331391"]', ['029331391'], 'invalid']], [['regression ["GB260407726"]', ['GB260407726'], 'mod9755'], ['regression ["GB 029 3313 90"]', ['GB 029 3313 90'], 'mod97'], ['partial-repair ["581077575"]', ['581077575'], 'mod9755'], ['control ["581077576"]', ['581077576'], 'invalid'], ['control ["GB98078068"]', ['GB98078068'], 'malformed'], ['control ["GB98078068X"]', ['GB98078068X'], 'malformed'], ['control ["123456789"]', ['123456789'], 'invalid'], ['control ["041839278"]', ['041839278'], 'invalid']], [['regression ["GB658372602"]', ['GB658372602'], 'mod97'], ['regression ["GB 225 8573 89"]', ['GB 225 8573 89'], 'mod9755'], ['partial-repair ["331553089"]', ['331553089'], 'mod97'], ['control ["261762305"]', ['261762305'], 'invalid'], ['control ["729236521"]', ['729236521'], 'invalid'], ['control ["260407727"]', ['260407727'], 'invalid'], ['control ["029331391"]', ['029331391'], 'invalid'], ['control ["581077576"]', ['581077576'], 'invalid']], [['regression ["GB784073455"]', ['GB784073455'], 'mod9755'], ['regression ["GB 397 1093 27"]', ['GB 397 1093 27'], 'mod97'], ['partial-repair ["155142529"]', ['155142529'], 'mod9755'], ['control ["GB98078068"]', ['GB98078068'], 'malformed'], ['control ["GB98078068X"]', ['GB98078068X'], 'malformed'], ['control ["123456789"]', ['123456789'], 'invalid'], ['control ["041839278"]', ['041839278'], 'invalid'], ['control ["261762305"]', ['261762305'], 'invalid']], [['regression ["GB801525174"]', ['GB801525174'], 'mod97'], ['regression ["GB 307 8958 63"]', ['GB 307 8958 63'], 'mod9755'], ['partial-repair ["GB980780684"]', ['GB980780684'], 'mod97'], ['control ["729236521"]', ['729236521'], 'invalid'], ['control ["260407727"]', ['260407727'], 'invalid'], ['control ["029331391"]', ['029331391'], 'invalid'], ['control ["581077576"]', ['581077576'], 'invalid'], ['control ["GB98078068"]', ['GB98078068'], 'malformed']]]
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 ["GB041839277"] | mod97 | mod97 | Passed |
| regression ["GB 261 7623 04"] | mod9755 | mod9755 | Passed |
| partial-repair ["729236520"] | mod97 | mod97 | Passed |
| control ["041839278"] | invalid | invalid | Passed |
| control ["261762305"] | invalid | invalid | Passed |
| control ["729236521"] | invalid | invalid | Passed |
| control ["260407727"] | invalid | invalid | Passed |
| control ["029331391"] | invalid | invalid | Passed |
SHA-256 / a40501fb7419ea2a41995bf1b7d524120aa04a87897f22f482032d5cd24d29d7
Verification & scope
A deterministic, bounded teaching model of the named scheme under the stated contract; not a certified validator. 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:40.816765+00:00.
Case digest / 16c28058d8469ae57ce077b04271d6d984c3c58cbaecf60a629d0d714e36a4ff