FA-96391 / Phone number formatting / Open access
E.164 parser with trunk prefixes: international numbers are measured with the caller region lengths · case 01
"+83" plus ten digits is rejected when the default region is AA.
ROOT CAUSE
The length set of the default region is used instead of the matched country.
VERIFIED REPAIR
Use the matched country entry for code, trunk and lengths.
Unsuccessful approach: Accepting any length from 7 to 10 lets a nine-digit BB number through.
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 or len(cc) > len(TABLE[best][0])):
best = code
if best is None:
return None
cc, trunk, lens = TABLE[best][0], '', TABLE.get(region, TABLE[best])[2]
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 | None | +42555011234 | Failed |
| one-digit country code | +8555011223 | +8555011223 | Passed |
| three-digit country code | None | +8915550113 | Failed |
| international with wrong length | +83555011234 | None | Failed |
| national without trunk country | +8915550113 | +8915550113 | Passed |
SHA-256 / cb694f5930e227487ab86d5d8d0f29ec16662c823ae411687378a91f2ebf7b1d
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][0], '', (7, 8, 9, 10)
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 | +83555011234 | None | Failed |
| national without trunk country | +8915550113 | +8915550113 | Passed |
SHA-256 / 3c339bb5f38b7c7a2b94a76818c19b6fe6062e316a929090e834d00170a2ac8b
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.406985+00:00.
Case digest / 5ef792df5928e33fd113b73f32170557899b8051cfaaf24b2012b37af5c1e50d