FAILURE MAP
← Case archive

FA-96786 / Phone number formatting / Open access

Numbering prefix pattern classifier: digits inside a class count as literals · case 01

"7[0-4]" outranks the more specific literal "72".

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

ROOT CAUSE

The score counts digit characters inside brackets as literal digits.

VERIFIED REPAIR

Score digits only outside brackets; a whole class scores 1.

Unsuccessful approach: Ignoring classes in the score ties "7[0-4]" with "7X" and the wildcard wins by order.

Case contract

Input [number, rules] with rules [pattern, label] in priority order. Pattern characters: X any digit, [..] a class of single digits and inclusive ranges a-b, other characters literal. A pattern matches when each of its positions matches the corresponding number digit (the number may be longer). Score: literal digit 2, class 1, X 0; the highest score wins and ties keep the earlier rule. No match gives "unknown".

Why this case matters

Numbering-plan tables decide routing, rating and number type from prefixes; specificity and range errors misroute whole blocks of numbers.

1 / The failure

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

N = 1
observations = []
def solve(x):
    num, rules = x
    def match(p, s):
        i = k = 0
        while k < len(p):
            if i >= len(s):
                return False
            if p[k] == 'X':
                ok = s[i].isdigit()
                k += 1
            elif p[k] == '[':
                end = p.index(']', k)
                body, ok, j = p[k + 1:end], False, 0
                while j < len(body):
                    if j + 2 < len(body) and body[j + 1] == '-':
                        ok = ok or body[j] <= s[i] <= body[j + 2]
                        j += 3
                    else:
                        ok = ok or s[i] == body[j]
                        j += 1
                k = end + 1
            else:
                ok = s[i] == p[k]
                k += 1
            if not ok:
                return False
            i += 1
        return True
    def score(p):
        total, depth = 0, 0
        for c in p:
            if c == '[':
                depth += 1
            elif c == ']':
                depth -= 1
                total += 1
            elif c.isdigit():
                total += 2
        return total
    best = None
    for p, label in rules:
        if match(p, num):
            sc = score(p)
            if best is None or sc > best[0]:
                best = (sc, label)
    return best[1] if best else 'unknown'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['class beats wildcard', ['72555012', [['7X', 'generic'], ['7[0-4]', 'mobile']]], 'mobile'], ['literal beats class', ['72555012', [['7[0-4]', 'mobile'], ['72', 'special']]], 'special'], ['range upper end inclusive', ['74555012', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['range lower end inclusive', ['70555012', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['number shorter than the pattern', ['7', [['7X', 'generic']]], 'unknown'], ['tie keeps the first listed rule', ['88555012', [['X8', 'listed-first'], ['8X', 'listed-second']]], 'listed-first'], ['range then literal in one class', ['2555012', [['[0-35]X', 'class-range']]], 'class-range'], ['literal then range in one class', ['5555012', [['[50-3]X', 'class-literal']]], 'class-literal'], ['no rule matches', ['6555012', [['7X', 'generic']]], 'unknown']], [['class beats wildcard', ['72555023', [['7X', 'generic'], ['7[0-4]', 'mobile']]], 'mobile'], ['literal beats class', ['72555023', [['7[0-4]', 'mobile'], ['72', 'special']]], 'special'], ['range upper end inclusive', ['74555023', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['range lower end inclusive', ['70555023', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['number shorter than the pattern', ['7', [['7X', 'generic']]], 'unknown'], ['tie keeps the first listed rule', ['88555023', [['X8', 'listed-first'], ['8X', 'listed-second']]], 'listed-first'], ['range then literal in one class', ['2555023', [['[0-35]X', 'class-range']]], 'class-range'], ['literal then range in one class', ['5555023', [['[50-3]X', 'class-literal']]], 'class-literal'], ['no rule matches', ['6555023', [['7X', 'generic']]], 'unknown']], [['class beats wildcard', ['72555034', [['7X', 'generic'], ['7[0-4]', 'mobile']]], 'mobile'], ['literal beats class', ['72555034', [['7[0-4]', 'mobile'], ['72', 'special']]], 'special'], ['range upper end inclusive', ['74555034', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['range lower end inclusive', ['70555034', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['number shorter than the pattern', ['7', [['7X', 'generic']]], 'unknown'], ['tie keeps the first listed rule', ['88555034', [['X8', 'listed-first'], ['8X', 'listed-second']]], 'listed-first'], ['range then literal in one class', ['2555034', [['[0-35]X', 'class-range']]], 'class-range'], ['literal then range in one class', ['5555034', [['[50-3]X', 'class-literal']]], 'class-literal'], ['no rule matches', ['6555034', [['7X', 'generic']]], 'unknown']], [['class beats wildcard', ['72555045', [['7X', 'generic'], ['7[0-4]', 'mobile']]], 'mobile'], ['literal beats class', ['72555045', [['7[0-4]', 'mobile'], ['72', 'special']]], 'special'], ['range upper end inclusive', ['74555045', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['range lower end inclusive', ['70555045', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['number shorter than the pattern', ['7', [['7X', 'generic']]], 'unknown'], ['tie keeps the first listed rule', ['88555045', [['X8', 'listed-first'], ['8X', 'listed-second']]], 'listed-first'], ['range then literal in one class', ['2555045', [['[0-35]X', 'class-range']]], 'class-range'], ['literal then range in one class', ['5555045', [['[50-3]X', 'class-literal']]], 'class-literal'], ['no rule matches', ['6555045', [['7X', 'generic']]], 'unknown']], [['class beats wildcard', ['72555056', [['7X', 'generic'], ['7[0-4]', 'mobile']]], 'mobile'], ['literal beats class', ['72555056', [['7[0-4]', 'mobile'], ['72', 'special']]], 'special'], ['range upper end inclusive', ['74555056', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['range lower end inclusive', ['70555056', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['number shorter than the pattern', ['7', [['7X', 'generic']]], 'unknown'], ['tie keeps the first listed rule', ['88555056', [['X8', 'listed-first'], ['8X', 'listed-second']]], 'listed-first'], ['range then literal in one class', ['2555056', [['[0-35]X', 'class-range']]], 'class-range'], ['literal then range in one class', ['5555056', [['[50-3]X', 'class-literal']]], 'class-literal'], ['no rule matches', ['6555056', [['7X', 'generic']]], 'unknown']]]
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
class beats wildcardmobilemobilePassed
literal beats classmobilespecialFailed
range upper end inclusivemobilemobilePassed
range lower end inclusivemobilemobilePassed
number shorter than the patternunknownunknownPassed
tie keeps the first listed rulelisted-firstlisted-firstPassed
range then literal in one classclass-rangeclass-rangePassed
literal then range in one classclass-literalclass-literalPassed
no rule matchesunknownunknownPassed

SHA-256 / 673d5c7fa15c47631f855573935ca378bd9dd637110b15000c819960e7af58e5

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(x):
    num, rules = x
    def match(p, s):
        i = k = 0
        while k < len(p):
            if i >= len(s):
                return False
            if p[k] == 'X':
                ok = s[i].isdigit()
                k += 1
            elif p[k] == '[':
                end = p.index(']', k)
                body, ok, j = p[k + 1:end], False, 0
                while j < len(body):
                    if j + 2 < len(body) and body[j + 1] == '-':
                        ok = ok or body[j] <= s[i] <= body[j + 2]
                        j += 3
                    else:
                        ok = ok or s[i] == body[j]
                        j += 1
                k = end + 1
            else:
                ok = s[i] == p[k]
                k += 1
            if not ok:
                return False
            i += 1
        return True
    def score(p):
        total, depth = 0, 0
        for c in p:
            if c == '[':
                depth += 1
            elif c == ']':
                depth -= 1
            elif c.isdigit() and depth == 0:
                total += 2
        return total
    best = None
    for p, label in rules:
        if match(p, num):
            sc = score(p)
            if best is None or sc > best[0]:
                best = (sc, label)
    return best[1] if best else 'unknown'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['class beats wildcard', ['72555012', [['7X', 'generic'], ['7[0-4]', 'mobile']]], 'mobile'], ['literal beats class', ['72555012', [['7[0-4]', 'mobile'], ['72', 'special']]], 'special'], ['range upper end inclusive', ['74555012', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['range lower end inclusive', ['70555012', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['number shorter than the pattern', ['7', [['7X', 'generic']]], 'unknown'], ['tie keeps the first listed rule', ['88555012', [['X8', 'listed-first'], ['8X', 'listed-second']]], 'listed-first'], ['range then literal in one class', ['2555012', [['[0-35]X', 'class-range']]], 'class-range'], ['literal then range in one class', ['5555012', [['[50-3]X', 'class-literal']]], 'class-literal'], ['no rule matches', ['6555012', [['7X', 'generic']]], 'unknown']], [['class beats wildcard', ['72555023', [['7X', 'generic'], ['7[0-4]', 'mobile']]], 'mobile'], ['literal beats class', ['72555023', [['7[0-4]', 'mobile'], ['72', 'special']]], 'special'], ['range upper end inclusive', ['74555023', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['range lower end inclusive', ['70555023', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['number shorter than the pattern', ['7', [['7X', 'generic']]], 'unknown'], ['tie keeps the first listed rule', ['88555023', [['X8', 'listed-first'], ['8X', 'listed-second']]], 'listed-first'], ['range then literal in one class', ['2555023', [['[0-35]X', 'class-range']]], 'class-range'], ['literal then range in one class', ['5555023', [['[50-3]X', 'class-literal']]], 'class-literal'], ['no rule matches', ['6555023', [['7X', 'generic']]], 'unknown']], [['class beats wildcard', ['72555034', [['7X', 'generic'], ['7[0-4]', 'mobile']]], 'mobile'], ['literal beats class', ['72555034', [['7[0-4]', 'mobile'], ['72', 'special']]], 'special'], ['range upper end inclusive', ['74555034', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['range lower end inclusive', ['70555034', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['number shorter than the pattern', ['7', [['7X', 'generic']]], 'unknown'], ['tie keeps the first listed rule', ['88555034', [['X8', 'listed-first'], ['8X', 'listed-second']]], 'listed-first'], ['range then literal in one class', ['2555034', [['[0-35]X', 'class-range']]], 'class-range'], ['literal then range in one class', ['5555034', [['[50-3]X', 'class-literal']]], 'class-literal'], ['no rule matches', ['6555034', [['7X', 'generic']]], 'unknown']], [['class beats wildcard', ['72555045', [['7X', 'generic'], ['7[0-4]', 'mobile']]], 'mobile'], ['literal beats class', ['72555045', [['7[0-4]', 'mobile'], ['72', 'special']]], 'special'], ['range upper end inclusive', ['74555045', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['range lower end inclusive', ['70555045', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['number shorter than the pattern', ['7', [['7X', 'generic']]], 'unknown'], ['tie keeps the first listed rule', ['88555045', [['X8', 'listed-first'], ['8X', 'listed-second']]], 'listed-first'], ['range then literal in one class', ['2555045', [['[0-35]X', 'class-range']]], 'class-range'], ['literal then range in one class', ['5555045', [['[50-3]X', 'class-literal']]], 'class-literal'], ['no rule matches', ['6555045', [['7X', 'generic']]], 'unknown']], [['class beats wildcard', ['72555056', [['7X', 'generic'], ['7[0-4]', 'mobile']]], 'mobile'], ['literal beats class', ['72555056', [['7[0-4]', 'mobile'], ['72', 'special']]], 'special'], ['range upper end inclusive', ['74555056', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['range lower end inclusive', ['70555056', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['number shorter than the pattern', ['7', [['7X', 'generic']]], 'unknown'], ['tie keeps the first listed rule', ['88555056', [['X8', 'listed-first'], ['8X', 'listed-second']]], 'listed-first'], ['range then literal in one class', ['2555056', [['[0-35]X', 'class-range']]], 'class-range'], ['literal then range in one class', ['5555056', [['[50-3]X', 'class-literal']]], 'class-literal'], ['no rule matches', ['6555056', [['7X', 'generic']]], 'unknown']]]
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
class beats wildcardgenericmobileFailed
literal beats classspecialspecialPassed
range upper end inclusivemobilemobilePassed
range lower end inclusivemobilemobilePassed
number shorter than the patternunknownunknownPassed
tie keeps the first listed rulelisted-firstlisted-firstPassed
range then literal in one classclass-rangeclass-rangePassed
literal then range in one classclass-literalclass-literalPassed
no rule matchesunknownunknownPassed

SHA-256 / d8f00527eada26d15514277fd45d6bad45cfb2ec2ae0c155bf66052fd5d1156e

3 / The verified repair

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

N = 1
observations = []
def solve(x):
    num, rules = x
    def match(p, s):
        i = k = 0
        while k < len(p):
            if i >= len(s):
                return False
            if p[k] == 'X':
                ok = s[i].isdigit()
                k += 1
            elif p[k] == '[':
                end = p.index(']', k)
                body, ok, j = p[k + 1:end], False, 0
                while j < len(body):
                    if j + 2 < len(body) and body[j + 1] == '-':
                        ok = ok or body[j] <= s[i] <= body[j + 2]
                        j += 3
                    else:
                        ok = ok or s[i] == body[j]
                        j += 1
                k = end + 1
            else:
                ok = s[i] == p[k]
                k += 1
            if not ok:
                return False
            i += 1
        return True
    def score(p):
        total, depth = 0, 0
        for c in p:
            if c == '[':
                depth += 1
            elif c == ']':
                depth -= 1
                total += 1
            elif c.isdigit() and depth == 0:
                total += 2
        return total
    best = None
    for p, label in rules:
        if match(p, num):
            sc = score(p)
            if best is None or sc > best[0]:
                best = (sc, label)
    return best[1] if best else 'unknown'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['class beats wildcard', ['72555012', [['7X', 'generic'], ['7[0-4]', 'mobile']]], 'mobile'], ['literal beats class', ['72555012', [['7[0-4]', 'mobile'], ['72', 'special']]], 'special'], ['range upper end inclusive', ['74555012', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['range lower end inclusive', ['70555012', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['number shorter than the pattern', ['7', [['7X', 'generic']]], 'unknown'], ['tie keeps the first listed rule', ['88555012', [['X8', 'listed-first'], ['8X', 'listed-second']]], 'listed-first'], ['range then literal in one class', ['2555012', [['[0-35]X', 'class-range']]], 'class-range'], ['literal then range in one class', ['5555012', [['[50-3]X', 'class-literal']]], 'class-literal'], ['no rule matches', ['6555012', [['7X', 'generic']]], 'unknown']], [['class beats wildcard', ['72555023', [['7X', 'generic'], ['7[0-4]', 'mobile']]], 'mobile'], ['literal beats class', ['72555023', [['7[0-4]', 'mobile'], ['72', 'special']]], 'special'], ['range upper end inclusive', ['74555023', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['range lower end inclusive', ['70555023', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['number shorter than the pattern', ['7', [['7X', 'generic']]], 'unknown'], ['tie keeps the first listed rule', ['88555023', [['X8', 'listed-first'], ['8X', 'listed-second']]], 'listed-first'], ['range then literal in one class', ['2555023', [['[0-35]X', 'class-range']]], 'class-range'], ['literal then range in one class', ['5555023', [['[50-3]X', 'class-literal']]], 'class-literal'], ['no rule matches', ['6555023', [['7X', 'generic']]], 'unknown']], [['class beats wildcard', ['72555034', [['7X', 'generic'], ['7[0-4]', 'mobile']]], 'mobile'], ['literal beats class', ['72555034', [['7[0-4]', 'mobile'], ['72', 'special']]], 'special'], ['range upper end inclusive', ['74555034', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['range lower end inclusive', ['70555034', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['number shorter than the pattern', ['7', [['7X', 'generic']]], 'unknown'], ['tie keeps the first listed rule', ['88555034', [['X8', 'listed-first'], ['8X', 'listed-second']]], 'listed-first'], ['range then literal in one class', ['2555034', [['[0-35]X', 'class-range']]], 'class-range'], ['literal then range in one class', ['5555034', [['[50-3]X', 'class-literal']]], 'class-literal'], ['no rule matches', ['6555034', [['7X', 'generic']]], 'unknown']], [['class beats wildcard', ['72555045', [['7X', 'generic'], ['7[0-4]', 'mobile']]], 'mobile'], ['literal beats class', ['72555045', [['7[0-4]', 'mobile'], ['72', 'special']]], 'special'], ['range upper end inclusive', ['74555045', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['range lower end inclusive', ['70555045', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['number shorter than the pattern', ['7', [['7X', 'generic']]], 'unknown'], ['tie keeps the first listed rule', ['88555045', [['X8', 'listed-first'], ['8X', 'listed-second']]], 'listed-first'], ['range then literal in one class', ['2555045', [['[0-35]X', 'class-range']]], 'class-range'], ['literal then range in one class', ['5555045', [['[50-3]X', 'class-literal']]], 'class-literal'], ['no rule matches', ['6555045', [['7X', 'generic']]], 'unknown']], [['class beats wildcard', ['72555056', [['7X', 'generic'], ['7[0-4]', 'mobile']]], 'mobile'], ['literal beats class', ['72555056', [['7[0-4]', 'mobile'], ['72', 'special']]], 'special'], ['range upper end inclusive', ['74555056', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['range lower end inclusive', ['70555056', [['7[0-4]', 'mobile'], ['7X', 'generic']]], 'mobile'], ['number shorter than the pattern', ['7', [['7X', 'generic']]], 'unknown'], ['tie keeps the first listed rule', ['88555056', [['X8', 'listed-first'], ['8X', 'listed-second']]], 'listed-first'], ['range then literal in one class', ['2555056', [['[0-35]X', 'class-range']]], 'class-range'], ['literal then range in one class', ['5555056', [['[50-3]X', 'class-literal']]], 'class-literal'], ['no rule matches', ['6555056', [['7X', 'generic']]], 'unknown']]]
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
class beats wildcardmobilemobilePassed
literal beats classspecialspecialPassed
range upper end inclusivemobilemobilePassed
range lower end inclusivemobilemobilePassed
number shorter than the patternunknownunknownPassed
tie keeps the first listed rulelisted-firstlisted-firstPassed
range then literal in one classclass-rangeclass-rangePassed
literal then range in one classclass-literalclass-literalPassed
no rule matchesunknownunknownPassed

SHA-256 / 1f76afe85952c4a5a0ee9ba5a5aff4620aa9559d96b258b26daa31e775cc3366

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

Case digest / df13165c1c4a3513ecb72ce0a54939851ab406fe9da7b83a1ee1791aaecf6bb7