FA-96396 / Phone number formatting / Open access
Variable-length area code grouping: the shortest matching area code is used · case 01
"04012 ..." is grouped as area 040.
ROOT CAUSE
The shortest matching area code is selected.
VERIFIED REPAIR
Choose the longest matching area code.
Unsuccessful approach: Taking the first match in table order still picks 40 before 4012.
Case contract
Keep digits and drop one leading trunk 0; nine national digits must remain. Numbers starting 7 are mobile with a four-digit block code; otherwise the area code is the longest match from 2, 30, 31, 40, 4012 (no match -> None). The subscriber part is one group if at most 5 digits, two equal halves if even, else 3 then the rest. Return "0" + area + " " + groups joined by spaces.
Why this case matters
Area codes of different lengths share leading digits; choosing the wrong one regroups every digit and prints a number users cannot dial.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
AREAS = ['2', '30', '31', '40', '4012']
d = ''.join(c for c in x if c.isdigit())
if d.startswith('0'):
d = d[1:]
if len(d) != 9:
return None
if d[0] == '7':
area = d[:4]
else:
area = min((a for a in AREAS if d.startswith(a)), key=len, default=None)
if area is None:
return None
sub = d[len(area):]
if len(sub) <= 5:
groups = [sub]
elif len(sub) % 2 == 0:
h = len(sub) // 2
groups = [sub[:h], sub[h:]]
else:
groups = [sub[:3], sub[3:]]
return '0' + area + ' ' + ' '.join(groups)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['one-digit area', '02 55501234', '02 5550 1234'], ['two-digit area', '030 5501234', '030 550 1234'], ['long area code wins over its prefix', '04012 01234', '04012 01234'], ['short area code', '040-3501234', '040 350 1234'], ['mobile block', '07111 01234', '07111 01234'], ['ten digits without trunk', '1255501234', None], ['unknown area prefix', '0955501234', None], ['national number typed without trunk', '255501234', '02 5550 1234']], [['one-digit area', '02 55502345', '02 5550 2345'], ['two-digit area', '030 5502345', '030 550 2345'], ['long area code wins over its prefix', '04012 02345', '04012 02345'], ['short area code', '040-3502345', '040 350 2345'], ['mobile block', '07222 02345', '07222 02345'], ['ten digits without trunk', '1255502345', None], ['unknown area prefix', '0955502345', None], ['national number typed without trunk', '255502345', '02 5550 2345']], [['one-digit area', '02 55503456', '02 5550 3456'], ['two-digit area', '030 5503456', '030 550 3456'], ['long area code wins over its prefix', '04012 03456', '04012 03456'], ['short area code', '040-3503456', '040 350 3456'], ['mobile block', '07333 03456', '07333 03456'], ['ten digits without trunk', '1255503456', None], ['unknown area prefix', '0955503456', None], ['national number typed without trunk', '255503456', '02 5550 3456']], [['one-digit area', '02 55504567', '02 5550 4567'], ['two-digit area', '030 5504567', '030 550 4567'], ['long area code wins over its prefix', '04012 04567', '04012 04567'], ['short area code', '040-3504567', '040 350 4567'], ['mobile block', '07444 04567', '07444 04567'], ['ten digits without trunk', '1255504567', None], ['unknown area prefix', '0955504567', None], ['national number typed without trunk', '255504567', '02 5550 4567']], [['one-digit area', '02 55505678', '02 5550 5678'], ['two-digit area', '030 5505678', '030 550 5678'], ['long area code wins over its prefix', '04012 05678', '04012 05678'], ['short area code', '040-3505678', '040 350 5678'], ['mobile block', '07555 05678', '07555 05678'], ['ten digits without trunk', '1255505678', None], ['unknown area prefix', '0955505678', None], ['national number typed without trunk', '255505678', '02 5550 5678']]]
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 |
|---|---|---|---|
| one-digit area | 02 5550 1234 | 02 5550 1234 | Passed |
| two-digit area | 030 550 1234 | 030 550 1234 | Passed |
| long area code wins over its prefix | 040 120 1234 | 04012 01234 | Failed |
| short area code | 040 350 1234 | 040 350 1234 | Passed |
| mobile block | 07111 01234 | 07111 01234 | Passed |
| ten digits without trunk | None | None | Passed |
| unknown area prefix | None | None | Passed |
| national number typed without trunk | 02 5550 1234 | 02 5550 1234 | Passed |
SHA-256 / a51f23973a48bc49efef4798d45c1c4d592d5d439c1a796c58c17059675aa0a8
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
AREAS = ['2', '30', '31', '40', '4012']
d = ''.join(c for c in x if c.isdigit())
if d.startswith('0'):
d = d[1:]
if len(d) != 9:
return None
if d[0] == '7':
area = d[:4]
else:
area = next((a for a in AREAS if d.startswith(a)), None)
if area is None:
return None
sub = d[len(area):]
if len(sub) <= 5:
groups = [sub]
elif len(sub) % 2 == 0:
h = len(sub) // 2
groups = [sub[:h], sub[h:]]
else:
groups = [sub[:3], sub[3:]]
return '0' + area + ' ' + ' '.join(groups)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['one-digit area', '02 55501234', '02 5550 1234'], ['two-digit area', '030 5501234', '030 550 1234'], ['long area code wins over its prefix', '04012 01234', '04012 01234'], ['short area code', '040-3501234', '040 350 1234'], ['mobile block', '07111 01234', '07111 01234'], ['ten digits without trunk', '1255501234', None], ['unknown area prefix', '0955501234', None], ['national number typed without trunk', '255501234', '02 5550 1234']], [['one-digit area', '02 55502345', '02 5550 2345'], ['two-digit area', '030 5502345', '030 550 2345'], ['long area code wins over its prefix', '04012 02345', '04012 02345'], ['short area code', '040-3502345', '040 350 2345'], ['mobile block', '07222 02345', '07222 02345'], ['ten digits without trunk', '1255502345', None], ['unknown area prefix', '0955502345', None], ['national number typed without trunk', '255502345', '02 5550 2345']], [['one-digit area', '02 55503456', '02 5550 3456'], ['two-digit area', '030 5503456', '030 550 3456'], ['long area code wins over its prefix', '04012 03456', '04012 03456'], ['short area code', '040-3503456', '040 350 3456'], ['mobile block', '07333 03456', '07333 03456'], ['ten digits without trunk', '1255503456', None], ['unknown area prefix', '0955503456', None], ['national number typed without trunk', '255503456', '02 5550 3456']], [['one-digit area', '02 55504567', '02 5550 4567'], ['two-digit area', '030 5504567', '030 550 4567'], ['long area code wins over its prefix', '04012 04567', '04012 04567'], ['short area code', '040-3504567', '040 350 4567'], ['mobile block', '07444 04567', '07444 04567'], ['ten digits without trunk', '1255504567', None], ['unknown area prefix', '0955504567', None], ['national number typed without trunk', '255504567', '02 5550 4567']], [['one-digit area', '02 55505678', '02 5550 5678'], ['two-digit area', '030 5505678', '030 550 5678'], ['long area code wins over its prefix', '04012 05678', '04012 05678'], ['short area code', '040-3505678', '040 350 5678'], ['mobile block', '07555 05678', '07555 05678'], ['ten digits without trunk', '1255505678', None], ['unknown area prefix', '0955505678', None], ['national number typed without trunk', '255505678', '02 5550 5678']]]
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 |
|---|---|---|---|
| one-digit area | 02 5550 1234 | 02 5550 1234 | Passed |
| two-digit area | 030 550 1234 | 030 550 1234 | Passed |
| long area code wins over its prefix | 040 120 1234 | 04012 01234 | Failed |
| short area code | 040 350 1234 | 040 350 1234 | Passed |
| mobile block | 07111 01234 | 07111 01234 | Passed |
| ten digits without trunk | None | None | Passed |
| unknown area prefix | None | None | Passed |
| national number typed without trunk | 02 5550 1234 | 02 5550 1234 | Passed |
SHA-256 / 8ebcb9704a2e14d4dc8689137c6a65b5b4785df2dd86af1bbee5086ad131655f
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
AREAS = ['2', '30', '31', '40', '4012']
d = ''.join(c for c in x if c.isdigit())
if d.startswith('0'):
d = d[1:]
if len(d) != 9:
return None
if d[0] == '7':
area = d[:4]
else:
area = max((a for a in AREAS if d.startswith(a)), key=len, default=None)
if area is None:
return None
sub = d[len(area):]
if len(sub) <= 5:
groups = [sub]
elif len(sub) % 2 == 0:
h = len(sub) // 2
groups = [sub[:h], sub[h:]]
else:
groups = [sub[:3], sub[3:]]
return '0' + area + ' ' + ' '.join(groups)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['one-digit area', '02 55501234', '02 5550 1234'], ['two-digit area', '030 5501234', '030 550 1234'], ['long area code wins over its prefix', '04012 01234', '04012 01234'], ['short area code', '040-3501234', '040 350 1234'], ['mobile block', '07111 01234', '07111 01234'], ['ten digits without trunk', '1255501234', None], ['unknown area prefix', '0955501234', None], ['national number typed without trunk', '255501234', '02 5550 1234']], [['one-digit area', '02 55502345', '02 5550 2345'], ['two-digit area', '030 5502345', '030 550 2345'], ['long area code wins over its prefix', '04012 02345', '04012 02345'], ['short area code', '040-3502345', '040 350 2345'], ['mobile block', '07222 02345', '07222 02345'], ['ten digits without trunk', '1255502345', None], ['unknown area prefix', '0955502345', None], ['national number typed without trunk', '255502345', '02 5550 2345']], [['one-digit area', '02 55503456', '02 5550 3456'], ['two-digit area', '030 5503456', '030 550 3456'], ['long area code wins over its prefix', '04012 03456', '04012 03456'], ['short area code', '040-3503456', '040 350 3456'], ['mobile block', '07333 03456', '07333 03456'], ['ten digits without trunk', '1255503456', None], ['unknown area prefix', '0955503456', None], ['national number typed without trunk', '255503456', '02 5550 3456']], [['one-digit area', '02 55504567', '02 5550 4567'], ['two-digit area', '030 5504567', '030 550 4567'], ['long area code wins over its prefix', '04012 04567', '04012 04567'], ['short area code', '040-3504567', '040 350 4567'], ['mobile block', '07444 04567', '07444 04567'], ['ten digits without trunk', '1255504567', None], ['unknown area prefix', '0955504567', None], ['national number typed without trunk', '255504567', '02 5550 4567']], [['one-digit area', '02 55505678', '02 5550 5678'], ['two-digit area', '030 5505678', '030 550 5678'], ['long area code wins over its prefix', '04012 05678', '04012 05678'], ['short area code', '040-3505678', '040 350 5678'], ['mobile block', '07555 05678', '07555 05678'], ['ten digits without trunk', '1255505678', None], ['unknown area prefix', '0955505678', None], ['national number typed without trunk', '255505678', '02 5550 5678']]]
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 |
|---|---|---|---|
| one-digit area | 02 5550 1234 | 02 5550 1234 | Passed |
| two-digit area | 030 550 1234 | 030 550 1234 | Passed |
| long area code wins over its prefix | 04012 01234 | 04012 01234 | Passed |
| short area code | 040 350 1234 | 040 350 1234 | Passed |
| mobile block | 07111 01234 | 07111 01234 | Passed |
| ten digits without trunk | None | None | Passed |
| unknown area prefix | None | None | Passed |
| national number typed without trunk | 02 5550 1234 | 02 5550 1234 | Passed |
SHA-256 / 830693da487542d60a53ef955bc8d823ef571b2d54e416f514f1b9bbbd5d5009
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.414319+00:00.
Case digest / 21e84043e72819b0336e4784a7a2d17150717a6c440373915a126a743759871f