FAILURE MAP
← Case archive

FA-96761 / Phone number formatting / Open access

Pattern-driven phone input mask: digits beyond the pattern are dropped silently · case 01

An eleven-digit input renders as a valid ten-digit number.

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

ROOT CAUSE

Unconsumed digits are not checked after the pattern ends.

VERIFIED REPAIR

Return None if any digit was not consumed.

Unsuccessful approach: Allowing one leftover digit still drops it silently.

Case contract

Input [digits, pattern]. Each X consumes the next digit; "\" makes the next pattern character a literal; other characters are literals. Literals are buffered and written only in front of the next digit, so a partial input never ends in a literal; when the whole pattern was consumed the trailing literals are written too. More digits than X slots returns None.

Why this case matters

Input masks drive what users see while typing; stray punctuation, lost literals or silently dropped digits produce numbers that differ from what was typed.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    digits, pattern = x
    out, i, k, pend = [], 0, 0, ''
    while k < len(pattern):
        ch = pattern[k]
        if ch == '\\' and k + 1 < len(pattern):
            pend += pattern[k + 1]
            k += 2
            continue
        if ch == 'X':
            if i >= len(digits):
                break
            out.append(pend + digits[i])
            pend = ''
            i += 1
        else:
            pend += ch
        k += 1
    if k >= len(pattern):
        out.append(pend)
    return ''.join(out)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['complete ten digits', ['5550113456', '(XXX) XXX-XXXX'], '(555) 011-3456'], ['three digits keep the bracket pending', ['555', '(XXX) XXX-XXXX'], '(555'], ['six digits', ['555011', '(XXX) XXX-XXXX'], '(555) 011'], ['nothing typed', ['', '(XXX) XXX-XXXX'], ''], ['pattern ending in a literal', ['555', '(XXX)'], '(555)'], ['escaped letter X', ['5550', 'E\\XT XXXX'], 'EXT 5550'], ['one digit too many', ['55501134561', '(XXX) XXX-XXXX'], None], ['pairs pattern complete', ['5550113456', 'XX XX XX XX XX'], '55 50 11 34 56'], ['pairs pattern partial', ['5550', 'XX XX XX XX XX'], '55 50']], [['complete ten digits', ['6550123456', '(XXX) XXX-XXXX'], '(655) 012-3456'], ['three digits keep the bracket pending', ['655', '(XXX) XXX-XXXX'], '(655'], ['six digits', ['655012', '(XXX) XXX-XXXX'], '(655) 012'], ['nothing typed', ['', '(XXX) XXX-XXXX'], ''], ['pattern ending in a literal', ['655', '(XXX)'], '(655)'], ['escaped letter X', ['6550', 'E\\XT XXXX'], 'EXT 6550'], ['one digit too many', ['65501234562', '(XXX) XXX-XXXX'], None], ['pairs pattern complete', ['6550123456', 'XX XX XX XX XX'], '65 50 12 34 56'], ['pairs pattern partial', ['6550', 'XX XX XX XX XX'], '65 50']], [['complete ten digits', ['7550133456', '(XXX) XXX-XXXX'], '(755) 013-3456'], ['three digits keep the bracket pending', ['755', '(XXX) XXX-XXXX'], '(755'], ['six digits', ['755013', '(XXX) XXX-XXXX'], '(755) 013'], ['nothing typed', ['', '(XXX) XXX-XXXX'], ''], ['pattern ending in a literal', ['755', '(XXX)'], '(755)'], ['escaped letter X', ['7550', 'E\\XT XXXX'], 'EXT 7550'], ['one digit too many', ['75501334563', '(XXX) XXX-XXXX'], None], ['pairs pattern complete', ['7550133456', 'XX XX XX XX XX'], '75 50 13 34 56'], ['pairs pattern partial', ['7550', 'XX XX XX XX XX'], '75 50']], [['complete ten digits', ['8550143456', '(XXX) XXX-XXXX'], '(855) 014-3456'], ['three digits keep the bracket pending', ['855', '(XXX) XXX-XXXX'], '(855'], ['six digits', ['855014', '(XXX) XXX-XXXX'], '(855) 014'], ['nothing typed', ['', '(XXX) XXX-XXXX'], ''], ['pattern ending in a literal', ['855', '(XXX)'], '(855)'], ['escaped letter X', ['8550', 'E\\XT XXXX'], 'EXT 8550'], ['one digit too many', ['85501434564', '(XXX) XXX-XXXX'], None], ['pairs pattern complete', ['8550143456', 'XX XX XX XX XX'], '85 50 14 34 56'], ['pairs pattern partial', ['8550', 'XX XX XX XX XX'], '85 50']], [['complete ten digits', ['9550153456', '(XXX) XXX-XXXX'], '(955) 015-3456'], ['three digits keep the bracket pending', ['955', '(XXX) XXX-XXXX'], '(955'], ['six digits', ['955015', '(XXX) XXX-XXXX'], '(955) 015'], ['nothing typed', ['', '(XXX) XXX-XXXX'], ''], ['pattern ending in a literal', ['955', '(XXX)'], '(955)'], ['escaped letter X', ['9550', 'E\\XT XXXX'], 'EXT 9550'], ['one digit too many', ['95501534565', '(XXX) XXX-XXXX'], None], ['pairs pattern complete', ['9550153456', 'XX XX XX XX XX'], '95 50 15 34 56'], ['pairs pattern partial', ['9550', 'XX XX XX XX XX'], '95 50']]]
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 fixtureActualExpectedOutcome
complete ten digits(555) 011-3456(555) 011-3456Passed
three digits keep the bracket pending(555(555Passed
six digits(555) 011(555) 011Passed
nothing typedPassed
pattern ending in a literal(555)(555)Passed
escaped letter XEXT 5550EXT 5550Passed
one digit too many(555) 011-3456NoneFailed
pairs pattern complete55 50 11 34 5655 50 11 34 56Passed
pairs pattern partial55 5055 50Passed

SHA-256 / 7ace09044f6d650de7cd611f360d2da42aa3229bd1aef53d4e50086c1277f70c

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    digits, pattern = x
    out, i, k, pend = [], 0, 0, ''
    while k < len(pattern):
        ch = pattern[k]
        if ch == '\\' and k + 1 < len(pattern):
            pend += pattern[k + 1]
            k += 2
            continue
        if ch == 'X':
            if i >= len(digits):
                break
            out.append(pend + digits[i])
            pend = ''
            i += 1
        else:
            pend += ch
        k += 1
    if i < len(digits) - 1:
        return None
    if k >= len(pattern):
        out.append(pend)
    return ''.join(out)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['complete ten digits', ['5550113456', '(XXX) XXX-XXXX'], '(555) 011-3456'], ['three digits keep the bracket pending', ['555', '(XXX) XXX-XXXX'], '(555'], ['six digits', ['555011', '(XXX) XXX-XXXX'], '(555) 011'], ['nothing typed', ['', '(XXX) XXX-XXXX'], ''], ['pattern ending in a literal', ['555', '(XXX)'], '(555)'], ['escaped letter X', ['5550', 'E\\XT XXXX'], 'EXT 5550'], ['one digit too many', ['55501134561', '(XXX) XXX-XXXX'], None], ['pairs pattern complete', ['5550113456', 'XX XX XX XX XX'], '55 50 11 34 56'], ['pairs pattern partial', ['5550', 'XX XX XX XX XX'], '55 50']], [['complete ten digits', ['6550123456', '(XXX) XXX-XXXX'], '(655) 012-3456'], ['three digits keep the bracket pending', ['655', '(XXX) XXX-XXXX'], '(655'], ['six digits', ['655012', '(XXX) XXX-XXXX'], '(655) 012'], ['nothing typed', ['', '(XXX) XXX-XXXX'], ''], ['pattern ending in a literal', ['655', '(XXX)'], '(655)'], ['escaped letter X', ['6550', 'E\\XT XXXX'], 'EXT 6550'], ['one digit too many', ['65501234562', '(XXX) XXX-XXXX'], None], ['pairs pattern complete', ['6550123456', 'XX XX XX XX XX'], '65 50 12 34 56'], ['pairs pattern partial', ['6550', 'XX XX XX XX XX'], '65 50']], [['complete ten digits', ['7550133456', '(XXX) XXX-XXXX'], '(755) 013-3456'], ['three digits keep the bracket pending', ['755', '(XXX) XXX-XXXX'], '(755'], ['six digits', ['755013', '(XXX) XXX-XXXX'], '(755) 013'], ['nothing typed', ['', '(XXX) XXX-XXXX'], ''], ['pattern ending in a literal', ['755', '(XXX)'], '(755)'], ['escaped letter X', ['7550', 'E\\XT XXXX'], 'EXT 7550'], ['one digit too many', ['75501334563', '(XXX) XXX-XXXX'], None], ['pairs pattern complete', ['7550133456', 'XX XX XX XX XX'], '75 50 13 34 56'], ['pairs pattern partial', ['7550', 'XX XX XX XX XX'], '75 50']], [['complete ten digits', ['8550143456', '(XXX) XXX-XXXX'], '(855) 014-3456'], ['three digits keep the bracket pending', ['855', '(XXX) XXX-XXXX'], '(855'], ['six digits', ['855014', '(XXX) XXX-XXXX'], '(855) 014'], ['nothing typed', ['', '(XXX) XXX-XXXX'], ''], ['pattern ending in a literal', ['855', '(XXX)'], '(855)'], ['escaped letter X', ['8550', 'E\\XT XXXX'], 'EXT 8550'], ['one digit too many', ['85501434564', '(XXX) XXX-XXXX'], None], ['pairs pattern complete', ['8550143456', 'XX XX XX XX XX'], '85 50 14 34 56'], ['pairs pattern partial', ['8550', 'XX XX XX XX XX'], '85 50']], [['complete ten digits', ['9550153456', '(XXX) XXX-XXXX'], '(955) 015-3456'], ['three digits keep the bracket pending', ['955', '(XXX) XXX-XXXX'], '(955'], ['six digits', ['955015', '(XXX) XXX-XXXX'], '(955) 015'], ['nothing typed', ['', '(XXX) XXX-XXXX'], ''], ['pattern ending in a literal', ['955', '(XXX)'], '(955)'], ['escaped letter X', ['9550', 'E\\XT XXXX'], 'EXT 9550'], ['one digit too many', ['95501534565', '(XXX) XXX-XXXX'], None], ['pairs pattern complete', ['9550153456', 'XX XX XX XX XX'], '95 50 15 34 56'], ['pairs pattern partial', ['9550', 'XX XX XX XX XX'], '95 50']]]
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 fixtureActualExpectedOutcome
complete ten digits(555) 011-3456(555) 011-3456Passed
three digits keep the bracket pending(555(555Passed
six digits(555) 011(555) 011Passed
nothing typedPassed
pattern ending in a literal(555)(555)Passed
escaped letter XEXT 5550EXT 5550Passed
one digit too many(555) 011-3456NoneFailed
pairs pattern complete55 50 11 34 5655 50 11 34 56Passed
pairs pattern partial55 5055 50Passed

SHA-256 / 8f10a05fbbd3719e8fbab35340c8adfbd955dd23a4d45359abb6417343911f13

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    digits, pattern = x
    out, i, k, pend = [], 0, 0, ''
    while k < len(pattern):
        ch = pattern[k]
        if ch == '\\' and k + 1 < len(pattern):
            pend += pattern[k + 1]
            k += 2
            continue
        if ch == 'X':
            if i >= len(digits):
                break
            out.append(pend + digits[i])
            pend = ''
            i += 1
        else:
            pend += ch
        k += 1
    if i < len(digits):
        return None
    if k >= len(pattern):
        out.append(pend)
    return ''.join(out)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['complete ten digits', ['5550113456', '(XXX) XXX-XXXX'], '(555) 011-3456'], ['three digits keep the bracket pending', ['555', '(XXX) XXX-XXXX'], '(555'], ['six digits', ['555011', '(XXX) XXX-XXXX'], '(555) 011'], ['nothing typed', ['', '(XXX) XXX-XXXX'], ''], ['pattern ending in a literal', ['555', '(XXX)'], '(555)'], ['escaped letter X', ['5550', 'E\\XT XXXX'], 'EXT 5550'], ['one digit too many', ['55501134561', '(XXX) XXX-XXXX'], None], ['pairs pattern complete', ['5550113456', 'XX XX XX XX XX'], '55 50 11 34 56'], ['pairs pattern partial', ['5550', 'XX XX XX XX XX'], '55 50']], [['complete ten digits', ['6550123456', '(XXX) XXX-XXXX'], '(655) 012-3456'], ['three digits keep the bracket pending', ['655', '(XXX) XXX-XXXX'], '(655'], ['six digits', ['655012', '(XXX) XXX-XXXX'], '(655) 012'], ['nothing typed', ['', '(XXX) XXX-XXXX'], ''], ['pattern ending in a literal', ['655', '(XXX)'], '(655)'], ['escaped letter X', ['6550', 'E\\XT XXXX'], 'EXT 6550'], ['one digit too many', ['65501234562', '(XXX) XXX-XXXX'], None], ['pairs pattern complete', ['6550123456', 'XX XX XX XX XX'], '65 50 12 34 56'], ['pairs pattern partial', ['6550', 'XX XX XX XX XX'], '65 50']], [['complete ten digits', ['7550133456', '(XXX) XXX-XXXX'], '(755) 013-3456'], ['three digits keep the bracket pending', ['755', '(XXX) XXX-XXXX'], '(755'], ['six digits', ['755013', '(XXX) XXX-XXXX'], '(755) 013'], ['nothing typed', ['', '(XXX) XXX-XXXX'], ''], ['pattern ending in a literal', ['755', '(XXX)'], '(755)'], ['escaped letter X', ['7550', 'E\\XT XXXX'], 'EXT 7550'], ['one digit too many', ['75501334563', '(XXX) XXX-XXXX'], None], ['pairs pattern complete', ['7550133456', 'XX XX XX XX XX'], '75 50 13 34 56'], ['pairs pattern partial', ['7550', 'XX XX XX XX XX'], '75 50']], [['complete ten digits', ['8550143456', '(XXX) XXX-XXXX'], '(855) 014-3456'], ['three digits keep the bracket pending', ['855', '(XXX) XXX-XXXX'], '(855'], ['six digits', ['855014', '(XXX) XXX-XXXX'], '(855) 014'], ['nothing typed', ['', '(XXX) XXX-XXXX'], ''], ['pattern ending in a literal', ['855', '(XXX)'], '(855)'], ['escaped letter X', ['8550', 'E\\XT XXXX'], 'EXT 8550'], ['one digit too many', ['85501434564', '(XXX) XXX-XXXX'], None], ['pairs pattern complete', ['8550143456', 'XX XX XX XX XX'], '85 50 14 34 56'], ['pairs pattern partial', ['8550', 'XX XX XX XX XX'], '85 50']], [['complete ten digits', ['9550153456', '(XXX) XXX-XXXX'], '(955) 015-3456'], ['three digits keep the bracket pending', ['955', '(XXX) XXX-XXXX'], '(955'], ['six digits', ['955015', '(XXX) XXX-XXXX'], '(955) 015'], ['nothing typed', ['', '(XXX) XXX-XXXX'], ''], ['pattern ending in a literal', ['955', '(XXX)'], '(955)'], ['escaped letter X', ['9550', 'E\\XT XXXX'], 'EXT 9550'], ['one digit too many', ['95501534565', '(XXX) XXX-XXXX'], None], ['pairs pattern complete', ['9550153456', 'XX XX XX XX XX'], '95 50 15 34 56'], ['pairs pattern partial', ['9550', 'XX XX XX XX XX'], '95 50']]]
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 fixtureActualExpectedOutcome
complete ten digits(555) 011-3456(555) 011-3456Passed
three digits keep the bracket pending(555(555Passed
six digits(555) 011(555) 011Passed
nothing typedPassed
pattern ending in a literal(555)(555)Passed
escaped letter XEXT 5550EXT 5550Passed
one digit too manyNoneNonePassed
pairs pattern complete55 50 11 34 5655 50 11 34 56Passed
pairs pattern partial55 5055 50Passed

SHA-256 / f8306aef227a4142d80f6d1a1338405bd8b2b733653b7a052c0afca57c97078d

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:25.692253+00:00.

Case digest / 20f05b1de102983606c5945313e2306bf294cca0032ccdd8356089ad58e12fae