FA-96366 / Phone number formatting / Open access
E.164 parser with trunk prefixes: the first matching country code wins · case 01
"+83..." is parsed as country 8 with a national number starting with 3.
ROOT CAUSE
The first table entry whose code prefixes the digits is kept, and the one-digit code is listed first.
VERIFIED REPAIR
Keep the matching country with the longest code.
Unsuccessful approach: Reversing the comparison keeps the shortest code, which misparses three-digit codes too.
Case contract
Input [number, default region]. Toy table (cc, trunk, national lengths): DD 8/-/9, AA 42/0/9, BB 83/8/10, CC 891/-/7-8. Remove "(0)" and keep digits. A leading "+" or "00" means international: drop "00", pick the country with the longest matching code. Otherwise the region is used and a national number of a trunk country must start with its trunk, which is removed once. The national part must have an allowed length. Return "+" cc national or None.
Why this case matters
Canonical E.164 storage is the join key for calls, messaging and deduplication; one wrong prefix rule routes numbers to another country.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
num, region = x
TABLE = {'DD': ('8', '', (9,)), 'AA': ('42', '0', (9,)), 'BB': ('83', '8', (10,)), 'CC': ('891', '', (7, 8))}
s = num.strip().replace('(0)', '')
raw = ''.join(c for c in s if c.isdigit())
if s.startswith('+') or raw.startswith('00'):
if not s.startswith('+'):
raw = raw[2:]
best = None
for code, (cc, trunk, lens) in TABLE.items():
if raw.startswith(cc) and best is None:
best = code
if best is None:
return None
cc, trunk, lens = TABLE[best]
nat = raw[len(cc):]
else:
if region not in TABLE:
return None
cc, trunk, lens = TABLE[region]
if trunk:
if not raw.startswith(trunk):
return None
raw = raw[len(trunk):]
nat = raw
if len(nat) not in lens:
return None
return '+' + cc + nat
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['national with trunk zero', ['0555011234', 'AA'], '+42555011234'], ['national missing its trunk', ['555011234', 'AA'], None], ['ten digits without trunk', ['5555011234', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550111', 'BB'], '+838125550111'], ['international two-digit code', ['+83 8125550111', 'AA'], '+838125550111'], ['double-zero international prefix', ['0083 8125550111', 'CC'], '+838125550111'], ['parenthesized trunk in international form', ['+42 (0)555011234', 'BB'], '+42555011234'], ['one-digit country code', ['+8 555011223', 'AA'], '+8555011223'], ['three-digit country code', ['+891 5550113', 'BB'], '+8915550113'], ['international with wrong length', ['+83 555011234', 'AA'], None], ['national without trunk country', ['5550113', 'CC'], '+8915550113']], [['national with trunk zero', ['0555012345', 'AA'], '+42555012345'], ['national missing its trunk', ['555012345', 'AA'], None], ['ten digits without trunk', ['5555012345', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550122', 'BB'], '+838125550122'], ['international two-digit code', ['+83 8125550122', 'AA'], '+838125550122'], ['double-zero international prefix', ['0083 8125550122', 'CC'], '+838125550122'], ['parenthesized trunk in international form', ['+42 (0)555012345', 'BB'], '+42555012345'], ['one-digit country code', ['+8 555022334', 'AA'], '+8555022334'], ['three-digit country code', ['+891 5550124', 'BB'], '+8915550124'], ['international with wrong length', ['+83 555012345', 'AA'], None], ['national without trunk country', ['5550124', 'CC'], '+8915550124']], [['national with trunk zero', ['0555013456', 'AA'], '+42555013456'], ['national missing its trunk', ['555013456', 'AA'], None], ['ten digits without trunk', ['5555013456', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550133', 'BB'], '+838125550133'], ['international two-digit code', ['+83 8125550133', 'AA'], '+838125550133'], ['double-zero international prefix', ['0083 8125550133', 'CC'], '+838125550133'], ['parenthesized trunk in international form', ['+42 (0)555013456', 'BB'], '+42555013456'], ['one-digit country code', ['+8 555033445', 'AA'], '+8555033445'], ['three-digit country code', ['+891 5550135', 'BB'], '+8915550135'], ['international with wrong length', ['+83 555013456', 'AA'], None], ['national without trunk country', ['5550135', 'CC'], '+8915550135']], [['national with trunk zero', ['0555014567', 'AA'], '+42555014567'], ['national missing its trunk', ['555014567', 'AA'], None], ['ten digits without trunk', ['5555014567', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550144', 'BB'], '+838125550144'], ['international two-digit code', ['+83 8125550144', 'AA'], '+838125550144'], ['double-zero international prefix', ['0083 8125550144', 'CC'], '+838125550144'], ['parenthesized trunk in international form', ['+42 (0)555014567', 'BB'], '+42555014567'], ['one-digit country code', ['+8 555044556', 'AA'], '+8555044556'], ['three-digit country code', ['+891 5550146', 'BB'], '+8915550146'], ['international with wrong length', ['+83 555014567', 'AA'], None], ['national without trunk country', ['5550146', 'CC'], '+8915550146']], [['national with trunk zero', ['0555015678', 'AA'], '+42555015678'], ['national missing its trunk', ['555015678', 'AA'], None], ['ten digits without trunk', ['5555015678', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550155', 'BB'], '+838125550155'], ['international two-digit code', ['+83 8125550155', 'AA'], '+838125550155'], ['double-zero international prefix', ['0083 8125550155', 'CC'], '+838125550155'], ['parenthesized trunk in international form', ['+42 (0)555015678', 'BB'], '+42555015678'], ['one-digit country code', ['+8 555055667', 'AA'], '+8555055667'], ['three-digit country code', ['+891 5550157', 'BB'], '+8915550157'], ['international with wrong length', ['+83 555015678', 'AA'], None], ['national without trunk country', ['5550157', 'CC'], '+8915550157']]]
for label, arg, expected in fixtures[N - 1]:
check(label, solve(arg), 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 |
|---|---|---|---|
| national with trunk zero | +42555011234 | +42555011234 | Passed |
| national missing its trunk | None | None | Passed |
| ten digits without trunk | None | None | Passed |
| national whose number repeats the trunk digit | +838125550111 | +838125550111 | Passed |
| international two-digit code | None | +838125550111 | Failed |
| double-zero international prefix | None | +838125550111 | Failed |
| parenthesized trunk in international form | +42555011234 | +42555011234 | Passed |
| one-digit country code | +8555011223 | +8555011223 | Passed |
| three-digit country code | +8915550113 | +8915550113 | Passed |
| international with wrong length | None | None | Passed |
| national without trunk country | +8915550113 | +8915550113 | Passed |
SHA-256 / 3cb459aff8311e5d515e4a01d4aea11643f1c5b4fa023769c44791a3cd354ea4
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
num, region = x
TABLE = {'DD': ('8', '', (9,)), 'AA': ('42', '0', (9,)), 'BB': ('83', '8', (10,)), 'CC': ('891', '', (7, 8))}
s = num.strip().replace('(0)', '')
raw = ''.join(c for c in s if c.isdigit())
if s.startswith('+') or raw.startswith('00'):
if not s.startswith('+'):
raw = raw[2:]
best = None
for code, (cc, trunk, lens) in TABLE.items():
if raw.startswith(cc) and (best is None or len(cc) < len(TABLE[best][0])):
best = code
if best is None:
return None
cc, trunk, lens = TABLE[best]
nat = raw[len(cc):]
else:
if region not in TABLE:
return None
cc, trunk, lens = TABLE[region]
if trunk:
if not raw.startswith(trunk):
return None
raw = raw[len(trunk):]
nat = raw
if len(nat) not in lens:
return None
return '+' + cc + nat
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['national with trunk zero', ['0555011234', 'AA'], '+42555011234'], ['national missing its trunk', ['555011234', 'AA'], None], ['ten digits without trunk', ['5555011234', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550111', 'BB'], '+838125550111'], ['international two-digit code', ['+83 8125550111', 'AA'], '+838125550111'], ['double-zero international prefix', ['0083 8125550111', 'CC'], '+838125550111'], ['parenthesized trunk in international form', ['+42 (0)555011234', 'BB'], '+42555011234'], ['one-digit country code', ['+8 555011223', 'AA'], '+8555011223'], ['three-digit country code', ['+891 5550113', 'BB'], '+8915550113'], ['international with wrong length', ['+83 555011234', 'AA'], None], ['national without trunk country', ['5550113', 'CC'], '+8915550113']], [['national with trunk zero', ['0555012345', 'AA'], '+42555012345'], ['national missing its trunk', ['555012345', 'AA'], None], ['ten digits without trunk', ['5555012345', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550122', 'BB'], '+838125550122'], ['international two-digit code', ['+83 8125550122', 'AA'], '+838125550122'], ['double-zero international prefix', ['0083 8125550122', 'CC'], '+838125550122'], ['parenthesized trunk in international form', ['+42 (0)555012345', 'BB'], '+42555012345'], ['one-digit country code', ['+8 555022334', 'AA'], '+8555022334'], ['three-digit country code', ['+891 5550124', 'BB'], '+8915550124'], ['international with wrong length', ['+83 555012345', 'AA'], None], ['national without trunk country', ['5550124', 'CC'], '+8915550124']], [['national with trunk zero', ['0555013456', 'AA'], '+42555013456'], ['national missing its trunk', ['555013456', 'AA'], None], ['ten digits without trunk', ['5555013456', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550133', 'BB'], '+838125550133'], ['international two-digit code', ['+83 8125550133', 'AA'], '+838125550133'], ['double-zero international prefix', ['0083 8125550133', 'CC'], '+838125550133'], ['parenthesized trunk in international form', ['+42 (0)555013456', 'BB'], '+42555013456'], ['one-digit country code', ['+8 555033445', 'AA'], '+8555033445'], ['three-digit country code', ['+891 5550135', 'BB'], '+8915550135'], ['international with wrong length', ['+83 555013456', 'AA'], None], ['national without trunk country', ['5550135', 'CC'], '+8915550135']], [['national with trunk zero', ['0555014567', 'AA'], '+42555014567'], ['national missing its trunk', ['555014567', 'AA'], None], ['ten digits without trunk', ['5555014567', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550144', 'BB'], '+838125550144'], ['international two-digit code', ['+83 8125550144', 'AA'], '+838125550144'], ['double-zero international prefix', ['0083 8125550144', 'CC'], '+838125550144'], ['parenthesized trunk in international form', ['+42 (0)555014567', 'BB'], '+42555014567'], ['one-digit country code', ['+8 555044556', 'AA'], '+8555044556'], ['three-digit country code', ['+891 5550146', 'BB'], '+8915550146'], ['international with wrong length', ['+83 555014567', 'AA'], None], ['national without trunk country', ['5550146', 'CC'], '+8915550146']], [['national with trunk zero', ['0555015678', 'AA'], '+42555015678'], ['national missing its trunk', ['555015678', 'AA'], None], ['ten digits without trunk', ['5555015678', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550155', 'BB'], '+838125550155'], ['international two-digit code', ['+83 8125550155', 'AA'], '+838125550155'], ['double-zero international prefix', ['0083 8125550155', 'CC'], '+838125550155'], ['parenthesized trunk in international form', ['+42 (0)555015678', 'BB'], '+42555015678'], ['one-digit country code', ['+8 555055667', 'AA'], '+8555055667'], ['three-digit country code', ['+891 5550157', 'BB'], '+8915550157'], ['international with wrong length', ['+83 555015678', 'AA'], None], ['national without trunk country', ['5550157', 'CC'], '+8915550157']]]
for label, arg, expected in fixtures[N - 1]:
check(label, solve(arg), 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 |
|---|---|---|---|
| national with trunk zero | +42555011234 | +42555011234 | Passed |
| national missing its trunk | None | None | Passed |
| ten digits without trunk | None | None | Passed |
| national whose number repeats the trunk digit | +838125550111 | +838125550111 | Passed |
| international two-digit code | None | +838125550111 | Failed |
| double-zero international prefix | None | +838125550111 | Failed |
| parenthesized trunk in international form | +42555011234 | +42555011234 | Passed |
| one-digit country code | +8555011223 | +8555011223 | Passed |
| three-digit country code | +8915550113 | +8915550113 | Passed |
| international with wrong length | None | None | Passed |
| national without trunk country | +8915550113 | +8915550113 | Passed |
SHA-256 / 552baa7dd10a8af8f0cb7f06412123ffd9c9710e56123a8fdac7a6ffea7491a0
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
num, region = x
TABLE = {'DD': ('8', '', (9,)), 'AA': ('42', '0', (9,)), 'BB': ('83', '8', (10,)), 'CC': ('891', '', (7, 8))}
s = num.strip().replace('(0)', '')
raw = ''.join(c for c in s if c.isdigit())
if s.startswith('+') or raw.startswith('00'):
if not s.startswith('+'):
raw = raw[2:]
best = None
for code, (cc, trunk, lens) in TABLE.items():
if raw.startswith(cc) and (best is None or len(cc) > len(TABLE[best][0])):
best = code
if best is None:
return None
cc, trunk, lens = TABLE[best]
nat = raw[len(cc):]
else:
if region not in TABLE:
return None
cc, trunk, lens = TABLE[region]
if trunk:
if not raw.startswith(trunk):
return None
raw = raw[len(trunk):]
nat = raw
if len(nat) not in lens:
return None
return '+' + cc + nat
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['national with trunk zero', ['0555011234', 'AA'], '+42555011234'], ['national missing its trunk', ['555011234', 'AA'], None], ['ten digits without trunk', ['5555011234', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550111', 'BB'], '+838125550111'], ['international two-digit code', ['+83 8125550111', 'AA'], '+838125550111'], ['double-zero international prefix', ['0083 8125550111', 'CC'], '+838125550111'], ['parenthesized trunk in international form', ['+42 (0)555011234', 'BB'], '+42555011234'], ['one-digit country code', ['+8 555011223', 'AA'], '+8555011223'], ['three-digit country code', ['+891 5550113', 'BB'], '+8915550113'], ['international with wrong length', ['+83 555011234', 'AA'], None], ['national without trunk country', ['5550113', 'CC'], '+8915550113']], [['national with trunk zero', ['0555012345', 'AA'], '+42555012345'], ['national missing its trunk', ['555012345', 'AA'], None], ['ten digits without trunk', ['5555012345', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550122', 'BB'], '+838125550122'], ['international two-digit code', ['+83 8125550122', 'AA'], '+838125550122'], ['double-zero international prefix', ['0083 8125550122', 'CC'], '+838125550122'], ['parenthesized trunk in international form', ['+42 (0)555012345', 'BB'], '+42555012345'], ['one-digit country code', ['+8 555022334', 'AA'], '+8555022334'], ['three-digit country code', ['+891 5550124', 'BB'], '+8915550124'], ['international with wrong length', ['+83 555012345', 'AA'], None], ['national without trunk country', ['5550124', 'CC'], '+8915550124']], [['national with trunk zero', ['0555013456', 'AA'], '+42555013456'], ['national missing its trunk', ['555013456', 'AA'], None], ['ten digits without trunk', ['5555013456', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550133', 'BB'], '+838125550133'], ['international two-digit code', ['+83 8125550133', 'AA'], '+838125550133'], ['double-zero international prefix', ['0083 8125550133', 'CC'], '+838125550133'], ['parenthesized trunk in international form', ['+42 (0)555013456', 'BB'], '+42555013456'], ['one-digit country code', ['+8 555033445', 'AA'], '+8555033445'], ['three-digit country code', ['+891 5550135', 'BB'], '+8915550135'], ['international with wrong length', ['+83 555013456', 'AA'], None], ['national without trunk country', ['5550135', 'CC'], '+8915550135']], [['national with trunk zero', ['0555014567', 'AA'], '+42555014567'], ['national missing its trunk', ['555014567', 'AA'], None], ['ten digits without trunk', ['5555014567', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550144', 'BB'], '+838125550144'], ['international two-digit code', ['+83 8125550144', 'AA'], '+838125550144'], ['double-zero international prefix', ['0083 8125550144', 'CC'], '+838125550144'], ['parenthesized trunk in international form', ['+42 (0)555014567', 'BB'], '+42555014567'], ['one-digit country code', ['+8 555044556', 'AA'], '+8555044556'], ['three-digit country code', ['+891 5550146', 'BB'], '+8915550146'], ['international with wrong length', ['+83 555014567', 'AA'], None], ['national without trunk country', ['5550146', 'CC'], '+8915550146']], [['national with trunk zero', ['0555015678', 'AA'], '+42555015678'], ['national missing its trunk', ['555015678', 'AA'], None], ['ten digits without trunk', ['5555015678', 'AA'], None], ['national whose number repeats the trunk digit', ['8 8125550155', 'BB'], '+838125550155'], ['international two-digit code', ['+83 8125550155', 'AA'], '+838125550155'], ['double-zero international prefix', ['0083 8125550155', 'CC'], '+838125550155'], ['parenthesized trunk in international form', ['+42 (0)555015678', 'BB'], '+42555015678'], ['one-digit country code', ['+8 555055667', 'AA'], '+8555055667'], ['three-digit country code', ['+891 5550157', 'BB'], '+8915550157'], ['international with wrong length', ['+83 555015678', 'AA'], None], ['national without trunk country', ['5550157', 'CC'], '+8915550157']]]
for label, arg, expected in fixtures[N - 1]:
check(label, solve(arg), 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 |
|---|---|---|---|
| national with trunk zero | +42555011234 | +42555011234 | Passed |
| national missing its trunk | None | None | Passed |
| ten digits without trunk | None | None | Passed |
| national whose number repeats the trunk digit | +838125550111 | +838125550111 | Passed |
| international two-digit code | +838125550111 | +838125550111 | Passed |
| double-zero international prefix | +838125550111 | +838125550111 | Passed |
| parenthesized trunk in international form | +42555011234 | +42555011234 | Passed |
| one-digit country code | +8555011223 | +8555011223 | Passed |
| three-digit country code | +8915550113 | +8915550113 | Passed |
| international with wrong length | None | None | Passed |
| national without trunk country | +8915550113 | +8915550113 | Passed |
SHA-256 / a5fcde9868b1dc678208edee6e790bb754bafaf6cf02a25f9b0a8efb584d2a82
Verification & scope
A deterministic toy contract over synthetic, obviously fictitious telephone numbers and toy country tables. The rules are stipulated for this model only and make no claim of conformance with any numbering plan or telecommunications standard. 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:52:22.061369+00:00.
Case digest / 2b1b8d731abc0db64161c87144d27146ef204f6f075c968708d585f1898a0cf5