FA-82141 / Poker hand evaluation / Open access
Space after a comma breaks range parsing · case 01
"QQ+, AKs" fails to parse because the second token starts with a space.
ROOT CAUSE
Tokens are used without trimming, so the leading space is read as the first rank.
THE FAILURE
Tokens are used without trimming, so the leading space is read as the first rank.
Unsuccessful approach: Stripping commas leaves the spaces in place.
Case contract
Input: a comma-separated hold'em range string. Tokens: pairs "77", "77+" (up to AA), "TT-77"; non-pairs "AKs"/"AKo"/"AK" (no suffix means both suited and offsuit), "A9s+" (kicker rises to one below the top card), "A9s-A6s" (inclusive). Whitespace around tokens is ignored. Duplicated classes count once. Return total combos: pair 6, suited 4, offsuit 12.
Why this case matters
Range combo counts drive equity, frequency and blocker arithmetic in solvers and trackers.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
R='23456789TJQKA'
classes=set()
def add(h, suf):
if h[0]==h[1]: classes.add(h)
elif suf: classes.add(h+suf)
else:
classes.add(h+'s'); classes.add(h+'o')
for tok in x.split(','):
tok=tok
if not tok: continue
plus=tok.endswith('+')
t=tok.rstrip('+')
if '-' in t:
a,b=t.split('-')
if a[0]==a[1]:
lo,hi=sorted([R.index(a[0]),R.index(b[0])])
for i in range(lo,hi+1): add(R[i]*2,'')
else:
lo,hi=sorted([R.index(a[1]),R.index(b[1])])
for i in range(lo,hi+1): add(a[0]+R[i],a[2:])
continue
if t[0]==t[1]:
start=R.index(t[0])
stop=len(R)-1 if plus else start
for i in range(start,stop+1): add(R[i]*2,'')
else:
top=R.index(t[0]); k=R.index(t[1])
stop=top-1 if plus else k
for i in range(k,stop+1): add(t[0]+R[i],t[2:])
total=0
for c in classes:
if c[0]==c[1]: total+=6
elif c.endswith('s'): total+=4
else: total+=12
return total
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('pairs plus', '77+', 48), ('queens plus', 'QQ+', 18), ('suited ace plus', 'A9s+', 20),
('offsuit king plus', 'KTo+', 36), ('unsuffixed class', 'AK', 16),
('dash kicker range', 'A9s-A6s', 16), ('dash pair range', 'TT-77', 24),
('spaced tokens', 'QQ+, AKs', 22)],
[('offsuit king plus', 'KTo+', 36), ('unsuffixed class', 'AK', 16),
('dash kicker range', 'A9s-A6s', 16), ('dash pair range', 'TT-77', 24),
('reversed dash pairs', '77-TT', 24), ('spaced tokens', 'QQ+, AKs', 22),
('overlap dedupe', 'AKs,AK', 16), ('single pair', '22', 6)],
[('dash pair range', 'TT-77', 24), ('reversed dash pairs', '77-TT', 24),
('spaced tokens', 'QQ+, AKs', 22), ('overlap dedupe', 'AKs,AK', 16), ('single pair', '22', 6),
('mixed', 'JJ+,AQs+,KQo', 44), ('aces only', 'AA', 6), ('suited connector plus', 'T9s+', 4)],
[('pairs plus', '77+', 48), ('spaced tokens', 'QQ+, AKs', 22), ('single pair', '22', 6),
('mixed', 'JJ+,AQs+,KQo', 44), ('aces only', 'AA', 6), ('suited connector plus', 'T9s+', 4),
('trailing comma', 'KK+,', 12), ('reversed kicker dash', 'K6o-K9o', 48)],
[('pairs plus', '77+', 48), ('queens plus', 'QQ+', 18), ('suited ace plus', 'A9s+', 20),
('offsuit king plus', 'KTo+', 36), ('spaced tokens', 'QQ+, AKs', 22),
('suited connector plus', 'T9s+', 4), ('trailing comma', 'KK+,', 12),
('reversed kicker dash', 'K6o-K9o', 48)]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| pairs plus | 48 | 48 | Passed |
| queens plus | 18 | 18 | Passed |
| suited ace plus | 20 | 20 | Passed |
| offsuit king plus | 36 | 36 | Passed |
| unsuffixed class | 16 | 16 | Passed |
| dash kicker range | 16 | 16 | Passed |
| dash pair range | 24 | 24 | Passed |
| spaced tokens | error:ValueError | 22 | Failed |
SHA-256 / 585fd70fa9bb01d9078632b27a4411ecae8c1545561929317dcc8ec41b6c372f
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
R='23456789TJQKA'
classes=set()
def add(h, suf):
if h[0]==h[1]: classes.add(h)
elif suf: classes.add(h+suf)
else:
classes.add(h+'s'); classes.add(h+'o')
for tok in x.split(','):
tok=tok.strip(',')
if not tok: continue
plus=tok.endswith('+')
t=tok.rstrip('+')
if '-' in t:
a,b=t.split('-')
if a[0]==a[1]:
lo,hi=sorted([R.index(a[0]),R.index(b[0])])
for i in range(lo,hi+1): add(R[i]*2,'')
else:
lo,hi=sorted([R.index(a[1]),R.index(b[1])])
for i in range(lo,hi+1): add(a[0]+R[i],a[2:])
continue
if t[0]==t[1]:
start=R.index(t[0])
stop=len(R)-1 if plus else start
for i in range(start,stop+1): add(R[i]*2,'')
else:
top=R.index(t[0]); k=R.index(t[1])
stop=top-1 if plus else k
for i in range(k,stop+1): add(t[0]+R[i],t[2:])
total=0
for c in classes:
if c[0]==c[1]: total+=6
elif c.endswith('s'): total+=4
else: total+=12
return total
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('pairs plus', '77+', 48), ('queens plus', 'QQ+', 18), ('suited ace plus', 'A9s+', 20),
('offsuit king plus', 'KTo+', 36), ('unsuffixed class', 'AK', 16),
('dash kicker range', 'A9s-A6s', 16), ('dash pair range', 'TT-77', 24),
('spaced tokens', 'QQ+, AKs', 22)],
[('offsuit king plus', 'KTo+', 36), ('unsuffixed class', 'AK', 16),
('dash kicker range', 'A9s-A6s', 16), ('dash pair range', 'TT-77', 24),
('reversed dash pairs', '77-TT', 24), ('spaced tokens', 'QQ+, AKs', 22),
('overlap dedupe', 'AKs,AK', 16), ('single pair', '22', 6)],
[('dash pair range', 'TT-77', 24), ('reversed dash pairs', '77-TT', 24),
('spaced tokens', 'QQ+, AKs', 22), ('overlap dedupe', 'AKs,AK', 16), ('single pair', '22', 6),
('mixed', 'JJ+,AQs+,KQo', 44), ('aces only', 'AA', 6), ('suited connector plus', 'T9s+', 4)],
[('pairs plus', '77+', 48), ('spaced tokens', 'QQ+, AKs', 22), ('single pair', '22', 6),
('mixed', 'JJ+,AQs+,KQo', 44), ('aces only', 'AA', 6), ('suited connector plus', 'T9s+', 4),
('trailing comma', 'KK+,', 12), ('reversed kicker dash', 'K6o-K9o', 48)],
[('pairs plus', '77+', 48), ('queens plus', 'QQ+', 18), ('suited ace plus', 'A9s+', 20),
('offsuit king plus', 'KTo+', 36), ('spaced tokens', 'QQ+, AKs', 22),
('suited connector plus', 'T9s+', 4), ('trailing comma', 'KK+,', 12),
('reversed kicker dash', 'K6o-K9o', 48)]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| pairs plus | 48 | 48 | Passed |
| queens plus | 18 | 18 | Passed |
| suited ace plus | 20 | 20 | Passed |
| offsuit king plus | 36 | 36 | Passed |
| unsuffixed class | 16 | 16 | Passed |
| dash kicker range | 16 | 16 | Passed |
| dash pair range | 24 | 24 | Passed |
| spaced tokens | error:ValueError | 22 | Failed |
SHA-256 / e3238edadf4de333a800aef89abafad54a6eac275053a6c108f1544abb0bb1f7
HELD IN THE MEMBER ARCHIVE
The verified repair and its recorded checks are member-only.
This mechanism has 8 recorded checks per implementation. The open-access tier publishes the failure and the unsuccessful fix; the repaired source that passes every check, and the observations that prove it, are available to members.
Every case sharing this mechanism uses the same contract and the same repair, so this one record is held back for all of them.
Member access is invitation-based. Sign in with your invited account to inspect the repair.
Sign in to the archive ↗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.464499+00:00.
Case digest / 6fe4fe512b9081c7c08cca5281ef0660a24cf9a2c70c2d008dadf6888e31ffd1