FAILURE MAP
← Case archive

FA-83461 / Card game rule engines / Open access

Sets with a repeated suit are accepted · case 01

Two copies of the nine of clubs plus another nine form a "set".

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

ROOT CAUSE

The set test only checks the rank and size.

VERIFIED REPAIR

Every card in a set must have a different suit.

Unsuccessful approach: Tolerating one repeated suit still accepts duplicated cards.

Case contract

Input a list of cards. A set is 3-4 cards of one rank in distinct suits. A run is 3+ consecutive cards of one suit; ace is low (A-2-3) or high (Q-K-A) but runs do not wrap (K-A-2). Return "set", "run" or "invalid".

Why this case matters

Card-game engines, scoring apps and online tables apply this rule automatically on every hand.

1 / The failure

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

N = 1
observations = []
def solve(x):
    cards = x
    order = 'A23456789TJQK'
    if len(cards) < 3:
        return 'invalid'
    ranks = [c[0] for c in cards]
    suits = [c[1] for c in cards]
    if len(set(ranks)) == 1:
        if len(cards) <= 4:
            return 'set'
        return 'invalid'
    if len(set(suits)) != 1:
        return 'invalid'
    idx = sorted(order.index(r) for r in ranks)
    if all(idx[i + 1] == idx[i] + 1 for i in range(len(idx) - 1)):
        return 'run'
    if idx[0] == 0:
        high = sorted(idx[1:] + [13])
        if all(high[i + 1] == high[i] + 1 for i in range(len(high) - 1)):
            return 'run'
    return 'invalid'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[['9H', '9C', '9D', '9D'], 'invalid'], [['4D', '5D', '3D', '6D'], 'run'], [['KD', '6S', 'QS', '6H'], 'invalid'], [['8H', '8S'], 'invalid'], [['JD', 'QD', '2D', 'KD', 'AD'], 'invalid'], [['8H', '6D', 'AH'], 'invalid'], [['4S', '4H', '4D'], 'set'], [['JH', 'JH', 'JC'], 'invalid']], [[['9C', 'JC', 'QC', 'TC'], 'run'], [['7S', '4D', 'JC'], 'invalid'], [['KH', 'QH', 'JH'], 'run'], [['5D', '5S'], 'invalid'], [['KD', 'TD', 'AD', 'JD', 'QD'], 'run'], [['KH', 'KD', 'KC', 'KC', 'KS'], 'invalid'], [['2H', '2H', '2S'], 'invalid'], [['JC', 'JH', 'JH'], 'invalid']], [[['JH', '9H', 'TH'], 'run'], [['TH', 'KH', 'QH', 'JH'], 'run'], [['6C', '2C', '8D', '8C'], 'invalid'], [['5H', '2H', '3H', '6H', '4H'], 'run'], [['4H', '4S', '4C', '4D'], 'set'], [['3D', '3H', '3C'], 'set'], [['JH', 'JH', 'JC'], 'invalid'], [['9C', '9H', '9D', '9C'], 'invalid']], [[['AD', 'AH', 'AD'], 'invalid'], [['QC', 'QS', 'QD', 'QD'], 'invalid'], [['9S', 'JS', 'QS', '8S', 'TS'], 'run'], [['KS', '4S', '8D', '3C'], 'invalid'], [['9C', 'JC', 'TC', '8C'], 'run'], [['AH', '2H', '3H'], 'run'], [['6H', '6S', '6H'], 'invalid'], [['4C', '4H', '4C', '4D'], 'invalid']], [[['9C', '3S', '3H'], 'invalid'], [['9H', 'JH', 'QC', '2D'], 'invalid'], [['5S', 'AH'], 'invalid'], [['TH', 'JH', 'KH', 'QH'], 'run'], [['QC', '6D'], 'invalid'], [['9D', '7D', '3S', '9S'], 'invalid'], [['4C', '4H', '4C', '4D'], 'invalid'], [['2S', '2S', '2H'], 'invalid']]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("meld case %d" % i, solve(args), 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
meld case 0setinvalidFailed
meld case 1runrunPassed
meld case 2invalidinvalidPassed
meld case 3invalidinvalidPassed
meld case 4invalidinvalidPassed
meld case 5invalidinvalidPassed
meld case 6setsetPassed
meld case 7setinvalidFailed

SHA-256 / 65553c6350ac2761ec12e6e070feee26082768a2ce3acfec5e9df025ef91eeab

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(x):
    cards = x
    order = 'A23456789TJQK'
    if len(cards) < 3:
        return 'invalid'
    ranks = [c[0] for c in cards]
    suits = [c[1] for c in cards]
    if len(set(ranks)) == 1:
        if len(cards) <= 4 and len(set(suits)) >= len(cards) - 1:
            return 'set'
        return 'invalid'
    if len(set(suits)) != 1:
        return 'invalid'
    idx = sorted(order.index(r) for r in ranks)
    if all(idx[i + 1] == idx[i] + 1 for i in range(len(idx) - 1)):
        return 'run'
    if idx[0] == 0:
        high = sorted(idx[1:] + [13])
        if all(high[i + 1] == high[i] + 1 for i in range(len(high) - 1)):
            return 'run'
    return 'invalid'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[['9H', '9C', '9D', '9D'], 'invalid'], [['4D', '5D', '3D', '6D'], 'run'], [['KD', '6S', 'QS', '6H'], 'invalid'], [['8H', '8S'], 'invalid'], [['JD', 'QD', '2D', 'KD', 'AD'], 'invalid'], [['8H', '6D', 'AH'], 'invalid'], [['4S', '4H', '4D'], 'set'], [['JH', 'JH', 'JC'], 'invalid']], [[['9C', 'JC', 'QC', 'TC'], 'run'], [['7S', '4D', 'JC'], 'invalid'], [['KH', 'QH', 'JH'], 'run'], [['5D', '5S'], 'invalid'], [['KD', 'TD', 'AD', 'JD', 'QD'], 'run'], [['KH', 'KD', 'KC', 'KC', 'KS'], 'invalid'], [['2H', '2H', '2S'], 'invalid'], [['JC', 'JH', 'JH'], 'invalid']], [[['JH', '9H', 'TH'], 'run'], [['TH', 'KH', 'QH', 'JH'], 'run'], [['6C', '2C', '8D', '8C'], 'invalid'], [['5H', '2H', '3H', '6H', '4H'], 'run'], [['4H', '4S', '4C', '4D'], 'set'], [['3D', '3H', '3C'], 'set'], [['JH', 'JH', 'JC'], 'invalid'], [['9C', '9H', '9D', '9C'], 'invalid']], [[['AD', 'AH', 'AD'], 'invalid'], [['QC', 'QS', 'QD', 'QD'], 'invalid'], [['9S', 'JS', 'QS', '8S', 'TS'], 'run'], [['KS', '4S', '8D', '3C'], 'invalid'], [['9C', 'JC', 'TC', '8C'], 'run'], [['AH', '2H', '3H'], 'run'], [['6H', '6S', '6H'], 'invalid'], [['4C', '4H', '4C', '4D'], 'invalid']], [[['9C', '3S', '3H'], 'invalid'], [['9H', 'JH', 'QC', '2D'], 'invalid'], [['5S', 'AH'], 'invalid'], [['TH', 'JH', 'KH', 'QH'], 'run'], [['QC', '6D'], 'invalid'], [['9D', '7D', '3S', '9S'], 'invalid'], [['4C', '4H', '4C', '4D'], 'invalid'], [['2S', '2S', '2H'], 'invalid']]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("meld case %d" % i, solve(args), 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
meld case 0setinvalidFailed
meld case 1runrunPassed
meld case 2invalidinvalidPassed
meld case 3invalidinvalidPassed
meld case 4invalidinvalidPassed
meld case 5invalidinvalidPassed
meld case 6setsetPassed
meld case 7setinvalidFailed

SHA-256 / d84fc7e0913a2e21447c2348c1b4b6341bbaa3cfae975dc94e770f50f6727d56

3 / The verified repair

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

N = 1
observations = []
def solve(x):
    cards = x
    order = 'A23456789TJQK'
    if len(cards) < 3:
        return 'invalid'
    ranks = [c[0] for c in cards]
    suits = [c[1] for c in cards]
    if len(set(ranks)) == 1:
        if len(cards) <= 4 and len(set(suits)) == len(cards):
            return 'set'
        return 'invalid'
    if len(set(suits)) != 1:
        return 'invalid'
    idx = sorted(order.index(r) for r in ranks)
    if all(idx[i + 1] == idx[i] + 1 for i in range(len(idx) - 1)):
        return 'run'
    if idx[0] == 0:
        high = sorted(idx[1:] + [13])
        if all(high[i + 1] == high[i] + 1 for i in range(len(high) - 1)):
            return 'run'
    return 'invalid'
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[['9H', '9C', '9D', '9D'], 'invalid'], [['4D', '5D', '3D', '6D'], 'run'], [['KD', '6S', 'QS', '6H'], 'invalid'], [['8H', '8S'], 'invalid'], [['JD', 'QD', '2D', 'KD', 'AD'], 'invalid'], [['8H', '6D', 'AH'], 'invalid'], [['4S', '4H', '4D'], 'set'], [['JH', 'JH', 'JC'], 'invalid']], [[['9C', 'JC', 'QC', 'TC'], 'run'], [['7S', '4D', 'JC'], 'invalid'], [['KH', 'QH', 'JH'], 'run'], [['5D', '5S'], 'invalid'], [['KD', 'TD', 'AD', 'JD', 'QD'], 'run'], [['KH', 'KD', 'KC', 'KC', 'KS'], 'invalid'], [['2H', '2H', '2S'], 'invalid'], [['JC', 'JH', 'JH'], 'invalid']], [[['JH', '9H', 'TH'], 'run'], [['TH', 'KH', 'QH', 'JH'], 'run'], [['6C', '2C', '8D', '8C'], 'invalid'], [['5H', '2H', '3H', '6H', '4H'], 'run'], [['4H', '4S', '4C', '4D'], 'set'], [['3D', '3H', '3C'], 'set'], [['JH', 'JH', 'JC'], 'invalid'], [['9C', '9H', '9D', '9C'], 'invalid']], [[['AD', 'AH', 'AD'], 'invalid'], [['QC', 'QS', 'QD', 'QD'], 'invalid'], [['9S', 'JS', 'QS', '8S', 'TS'], 'run'], [['KS', '4S', '8D', '3C'], 'invalid'], [['9C', 'JC', 'TC', '8C'], 'run'], [['AH', '2H', '3H'], 'run'], [['6H', '6S', '6H'], 'invalid'], [['4C', '4H', '4C', '4D'], 'invalid']], [[['9C', '3S', '3H'], 'invalid'], [['9H', 'JH', 'QC', '2D'], 'invalid'], [['5S', 'AH'], 'invalid'], [['TH', 'JH', 'KH', 'QH'], 'run'], [['QC', '6D'], 'invalid'], [['9D', '7D', '3S', '9S'], 'invalid'], [['4C', '4H', '4C', '4D'], 'invalid'], [['2S', '2S', '2H'], 'invalid']]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("meld case %d" % i, solve(args), 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
meld case 0invalidinvalidPassed
meld case 1runrunPassed
meld case 2invalidinvalidPassed
meld case 3invalidinvalidPassed
meld case 4invalidinvalidPassed
meld case 5invalidinvalidPassed
meld case 6setsetPassed
meld case 7invalidinvalidPassed

SHA-256 / f98848a41083f57b8105da465d71e81ca1086bf9be46a3b91a9c2a10bb7432d0

Verification & scope

A bounded toy rule contract stated explicitly in the contract field; cards are two-character codes (rank, suit). Not a complete implementation of any published rulebook or casino table rules. 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:21.912015+00:00.

Case digest / d0c6f40ad3712065e989061d637eb81651c7bba6a8f586c05382cb2cdb196843