FAILURE MAP
← Case archive

FA-82116 / Poker hand evaluation / Open access

Substring test accepts empty and multi-letter ranks · case 01

A card with no rank or a rank token "KQ" produces a hand label instead of "invalid".

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

ROOT CAUSE

Membership is tested against the rank string, so any substring (including "") passes.

VERIFIED REPAIR

Test membership against the list of single rank characters.

Unsuccessful approach: Rejecting only empty tokens still accepts multi-letter substrings such as "KQ".

Case contract

Input: two hole cards as strings (rank may be "10"; rank and suit case-insensitive). Return canonical hold'em notation: pairs "QQ", otherwise higher rank first with "s" for suited or "o" for offsuit (e.g. "AKs", "T9o"). Return "invalid" for duplicate cards or unknown ranks.

Why this case matters

Range tools, solvers and hand histories key statistics on this notation.

1 / The failure

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

N = 1
observations = []
def solve(x):
    R='23456789TJQKA'
    if len(x)!=2 or x[0].upper()==x[1].upper(): return 'invalid'
    def rank(c):
        t=c[:-1].upper()
        return 'T' if t=='10' else t
    a,b=rank(x[0]),rank(x[1])
    if a not in R or b not in R: return 'invalid'
    if a==b: return a+b
    hi,lo=sorted([a,b], key=R.index, reverse=True)
    return hi+lo+('s' if x[0][-1].lower()==x[1][-1].lower() else 'o')
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('ace king suited', ['Ah', 'Kh'], 'AKs'), ('king ace offsuit order', ['Kd', 'Ah'], 'AKo'),
  ('ten nine suited with 10', ['10s', '9s'], 'T9s'), ('nine ten mixed', ['9c', '10d'], 'T9o'),
  ('pair of queens', ['Qh', 'Qs'], 'QQ'), ('duplicate card case', ['Ah', 'aH'], 'invalid'),
  ('empty rank', ['h', 'Kd'], 'invalid'), ('two-letter rank', ['KQh', '2d'], 'invalid')],
 [('nine ten mixed', ['9c', '10d'], 'T9o'), ('pair of queens', ['Qh', 'Qs'], 'QQ'),
  ('duplicate card case', ['Ah', 'aH'], 'invalid'), ('exact duplicate', ['7c', '7c'], 'invalid'),
  ('queen ten', ['Tc', 'Qc'], 'QTs'), ('lower case ranks', ['kd', 'js'], 'KJo'),
  ('empty rank', ['h', 'Kd'], 'invalid'), ('two-letter rank', ['KQh', '2d'], 'invalid')],
 [('exact duplicate', ['7c', '7c'], 'invalid'), ('queen ten', ['Tc', 'Qc'], 'QTs'),
  ('lower case ranks', ['kd', 'js'], 'KJo'), ('suit case differs', ['Jh', 'TH'], 'JTs'),
  ('empty rank', ['h', 'Kd'], 'invalid'), ('two-letter rank', ['KQh', '2d'], 'invalid'),
  ('ten first suited', ['10h', 'Jh'], 'JTs'), ('deuce seven', ['2d', '7s'], '72o')],
 [('ace king suited', ['Ah', 'Kh'], 'AKs'), ('king ace offsuit order', ['Kd', 'Ah'], 'AKo'),
  ('suit case differs', ['Jh', 'TH'], 'JTs'), ('empty rank', ['h', 'Kd'], 'invalid'),
  ('two-letter rank', ['KQh', '2d'], 'invalid'), ('ten first suited', ['10h', 'Jh'], 'JTs'),
  ('deuce seven', ['2d', '7s'], '72o'), ('pair of tens mixed tokens', ['10h', 'Td'], 'TT')],
 [('ace king suited', ['Ah', 'Kh'], 'AKs'), ('king ace offsuit order', ['Kd', 'Ah'], 'AKo'),
  ('ten nine suited with 10', ['10s', '9s'], 'T9s'), ('nine ten mixed', ['9c', '10d'], 'T9o'),
  ('pair of queens', ['Qh', 'Qs'], 'QQ'), ('empty rank', ['h', 'Kd'], 'invalid'),
  ('two-letter rank', ['KQh', '2d'], 'invalid'),
  ('pair of tens mixed tokens', ['10h', 'Td'], 'TT')]]
for label, args, expected in fixtures[N-1]:
    try:
        actual = solve(args)
    except Exception as exc:
        actual = 'error:' + type(exc).__name__
    check(label, actual, 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
ace king suitedAKsAKsPassed
king ace offsuit orderAKoAKoPassed
ten nine suited with 10T9sT9sPassed
nine ten mixedT9oT9oPassed
pair of queensQQQQPassed
duplicate card caseinvalidinvalidPassed
empty rankKoinvalidFailed
two-letter rankinvalidinvalidPassed

SHA-256 / 178a91e2733b3edcb19b439cf6a05204509037cf0afde7ffa83cabad2f781da1

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(x):
    R='23456789TJQKA'
    if len(x)!=2 or x[0].upper()==x[1].upper(): return 'invalid'
    def rank(c):
        t=c[:-1].upper()
        return 'T' if t=='10' else t
    a,b=rank(x[0]),rank(x[1])
    if not a or not b: return 'invalid'
    if a==b: return a+b
    hi,lo=sorted([a,b], key=R.index, reverse=True)
    return hi+lo+('s' if x[0][-1].lower()==x[1][-1].lower() else 'o')
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('ace king suited', ['Ah', 'Kh'], 'AKs'), ('king ace offsuit order', ['Kd', 'Ah'], 'AKo'),
  ('ten nine suited with 10', ['10s', '9s'], 'T9s'), ('nine ten mixed', ['9c', '10d'], 'T9o'),
  ('pair of queens', ['Qh', 'Qs'], 'QQ'), ('duplicate card case', ['Ah', 'aH'], 'invalid'),
  ('empty rank', ['h', 'Kd'], 'invalid'), ('two-letter rank', ['KQh', '2d'], 'invalid')],
 [('nine ten mixed', ['9c', '10d'], 'T9o'), ('pair of queens', ['Qh', 'Qs'], 'QQ'),
  ('duplicate card case', ['Ah', 'aH'], 'invalid'), ('exact duplicate', ['7c', '7c'], 'invalid'),
  ('queen ten', ['Tc', 'Qc'], 'QTs'), ('lower case ranks', ['kd', 'js'], 'KJo'),
  ('empty rank', ['h', 'Kd'], 'invalid'), ('two-letter rank', ['KQh', '2d'], 'invalid')],
 [('exact duplicate', ['7c', '7c'], 'invalid'), ('queen ten', ['Tc', 'Qc'], 'QTs'),
  ('lower case ranks', ['kd', 'js'], 'KJo'), ('suit case differs', ['Jh', 'TH'], 'JTs'),
  ('empty rank', ['h', 'Kd'], 'invalid'), ('two-letter rank', ['KQh', '2d'], 'invalid'),
  ('ten first suited', ['10h', 'Jh'], 'JTs'), ('deuce seven', ['2d', '7s'], '72o')],
 [('ace king suited', ['Ah', 'Kh'], 'AKs'), ('king ace offsuit order', ['Kd', 'Ah'], 'AKo'),
  ('suit case differs', ['Jh', 'TH'], 'JTs'), ('empty rank', ['h', 'Kd'], 'invalid'),
  ('two-letter rank', ['KQh', '2d'], 'invalid'), ('ten first suited', ['10h', 'Jh'], 'JTs'),
  ('deuce seven', ['2d', '7s'], '72o'), ('pair of tens mixed tokens', ['10h', 'Td'], 'TT')],
 [('ace king suited', ['Ah', 'Kh'], 'AKs'), ('king ace offsuit order', ['Kd', 'Ah'], 'AKo'),
  ('ten nine suited with 10', ['10s', '9s'], 'T9s'), ('nine ten mixed', ['9c', '10d'], 'T9o'),
  ('pair of queens', ['Qh', 'Qs'], 'QQ'), ('empty rank', ['h', 'Kd'], 'invalid'),
  ('two-letter rank', ['KQh', '2d'], 'invalid'),
  ('pair of tens mixed tokens', ['10h', 'Td'], 'TT')]]
for label, args, expected in fixtures[N-1]:
    try:
        actual = solve(args)
    except Exception as exc:
        actual = 'error:' + type(exc).__name__
    check(label, actual, 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
ace king suitedAKsAKsPassed
king ace offsuit orderAKoAKoPassed
ten nine suited with 10T9sT9sPassed
nine ten mixedT9oT9oPassed
pair of queensQQQQPassed
duplicate card caseinvalidinvalidPassed
empty rankinvalidinvalidPassed
two-letter rankerror:ValueErrorinvalidFailed

SHA-256 / 231b922764ebae60349e8bde3f31c51cf0b8df82f010d4505622b9941d47f415

3 / The verified repair

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

N = 1
observations = []
def solve(x):
    R='23456789TJQKA'
    if len(x)!=2 or x[0].upper()==x[1].upper(): return 'invalid'
    def rank(c):
        t=c[:-1].upper()
        return 'T' if t=='10' else t
    a,b=rank(x[0]),rank(x[1])
    if a not in list(R) or b not in list(R): return 'invalid'
    if a==b: return a+b
    hi,lo=sorted([a,b], key=R.index, reverse=True)
    return hi+lo+('s' if x[0][-1].lower()==x[1][-1].lower() else 'o')
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('ace king suited', ['Ah', 'Kh'], 'AKs'), ('king ace offsuit order', ['Kd', 'Ah'], 'AKo'),
  ('ten nine suited with 10', ['10s', '9s'], 'T9s'), ('nine ten mixed', ['9c', '10d'], 'T9o'),
  ('pair of queens', ['Qh', 'Qs'], 'QQ'), ('duplicate card case', ['Ah', 'aH'], 'invalid'),
  ('empty rank', ['h', 'Kd'], 'invalid'), ('two-letter rank', ['KQh', '2d'], 'invalid')],
 [('nine ten mixed', ['9c', '10d'], 'T9o'), ('pair of queens', ['Qh', 'Qs'], 'QQ'),
  ('duplicate card case', ['Ah', 'aH'], 'invalid'), ('exact duplicate', ['7c', '7c'], 'invalid'),
  ('queen ten', ['Tc', 'Qc'], 'QTs'), ('lower case ranks', ['kd', 'js'], 'KJo'),
  ('empty rank', ['h', 'Kd'], 'invalid'), ('two-letter rank', ['KQh', '2d'], 'invalid')],
 [('exact duplicate', ['7c', '7c'], 'invalid'), ('queen ten', ['Tc', 'Qc'], 'QTs'),
  ('lower case ranks', ['kd', 'js'], 'KJo'), ('suit case differs', ['Jh', 'TH'], 'JTs'),
  ('empty rank', ['h', 'Kd'], 'invalid'), ('two-letter rank', ['KQh', '2d'], 'invalid'),
  ('ten first suited', ['10h', 'Jh'], 'JTs'), ('deuce seven', ['2d', '7s'], '72o')],
 [('ace king suited', ['Ah', 'Kh'], 'AKs'), ('king ace offsuit order', ['Kd', 'Ah'], 'AKo'),
  ('suit case differs', ['Jh', 'TH'], 'JTs'), ('empty rank', ['h', 'Kd'], 'invalid'),
  ('two-letter rank', ['KQh', '2d'], 'invalid'), ('ten first suited', ['10h', 'Jh'], 'JTs'),
  ('deuce seven', ['2d', '7s'], '72o'), ('pair of tens mixed tokens', ['10h', 'Td'], 'TT')],
 [('ace king suited', ['Ah', 'Kh'], 'AKs'), ('king ace offsuit order', ['Kd', 'Ah'], 'AKo'),
  ('ten nine suited with 10', ['10s', '9s'], 'T9s'), ('nine ten mixed', ['9c', '10d'], 'T9o'),
  ('pair of queens', ['Qh', 'Qs'], 'QQ'), ('empty rank', ['h', 'Kd'], 'invalid'),
  ('two-letter rank', ['KQh', '2d'], 'invalid'),
  ('pair of tens mixed tokens', ['10h', 'Td'], 'TT')]]
for label, args, expected in fixtures[N-1]:
    try:
        actual = solve(args)
    except Exception as exc:
        actual = 'error:' + type(exc).__name__
    check(label, actual, 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
ace king suitedAKsAKsPassed
king ace offsuit orderAKoAKoPassed
ten nine suited with 10T9sT9sPassed
nine ten mixedT9oT9oPassed
pair of queensQQQQPassed
duplicate card caseinvalidinvalidPassed
empty rankinvalidinvalidPassed
two-letter rankinvalidinvalidPassed

SHA-256 / ad643207e854f95affabeaa0312bd78b89abe043f6b5e21d25f72183c526dd66

Verification & scope

A deterministic toy model with an explicitly stated contract; card strings are rank+suit (for example "As", "Td"); no claim of conformance to any casino or tournament rulebook. 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:50:09.179351+00:00.

Case digest / 7e581daf18468f7f5e6a397528a34c06aee77113327ea11ba9a10996a8b239d0