FAILURE MAP
← Case archive

FA-83816 / Card game rule engines / Open access

Melds with four or more wild cards are accepted · case 01

A pair of fives with four wilds is a legal meld.

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

ROOT CAUSE

The wild-card cap is missing.

VERIFIED REPAIR

At most three wild cards per meld.

Unsuccessful approach: Capping at two wild cards rejects legal three-wild melds.

Case contract

Input a meld (cards; "JK" joker and deuces are wild). Valid: >= 3 cards, >= 2 naturals of one rank (not threes), at most 3 wild cards. Card points: joker 50, A and 2 20, 8-K 10, 4-7 and black 3 5. A canasta (7+ cards) earns 500 if natural, 300 if mixed. Return [valid|invalid, bonus, card_points].

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):
    meld = x
    wild = [c for c in meld if c == 'JK' or c[0] == '2']
    nat = [c for c in meld if c not in wild]
    if len(meld) < 3 or len(nat) < 2:
        return ['invalid', 0, 0]
    if len(set(c[0] for c in nat)) != 1 or nat[0][0] == '3':
        return ['invalid', 0, 0]
    def pts(c):
        if c == 'JK':
            return 50
        if c[0] in '2A':
            return 20
        if c[0] in '89TJQK':
            return 10
        return 5
    bonus = 0
    if len(meld) >= 7:
        bonus = 500 if not wild else 300
    return ['valid', bonus, sum(pts(c) for c in meld)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[['AC', 'AD', 'AC', 'AC', 'JK', '2H', 'AD', 'AC'], ['valid', 300, 190]], [['JH', 'JH', 'JC'], ['valid', 0, 30]], [['JK', '2S', '2H', '2D'], ['invalid', 0, 0]], [['2H', '5C', '2D', '2H', '2D'], ['invalid', 0, 0]], [['2H', '2H', '6H', '2S', '6H'], ['valid', 0, 70]], [['AD', 'AC', 'AS', '2S'], ['valid', 0, 80]], [['2S', '2D', '5H', '2C', '5C', '5D', 'JK', '5D'], ['invalid', 0, 0]], [['8C', 'JK', 'JK', '8H', '2S', '8D', '8S'], ['valid', 300, 160]]], [[['2H', '6C', '6D', '6D', '6H', '2S'], ['valid', 0, 60]], [['KH', 'JK', 'KD', 'JK', 'KH', 'KC'], ['valid', 0, 140]], [[], ['invalid', 0, 0]], [['3S', 'JK', '3H', '3H', '3D', '2S'], ['invalid', 0, 0]], [['2S', '2D', '5H', '2C', '5C', '5D', 'JK', '5D'], ['invalid', 0, 0]], [['TD', 'TH'], ['invalid', 0, 0]], [['4C', '2H', '2H', '4S', '2H', '2S'], ['invalid', 0, 0]], [['JK', '5S', '2D', '2D', '5C'], ['valid', 0, 100]]], [[['2H', '2C', '2H'], ['invalid', 0, 0]], [['KD', 'JS', '2C'], ['invalid', 0, 0]], [['2S', 'AH', 'AS', 'AC', 'AD', 'AH', 'AS', 'AD'], ['valid', 300, 160]], [['2D', 'AC', 'AH', 'AH', '2S'], ['valid', 0, 100]], [['7S', '2H'], ['invalid', 0, 0]], [['2S', '2D'], ['invalid', 0, 0]], [['AH', 'AS', 'JK', 'AD', '2D', 'AD', 'AH', '2C', 'JK', 'AS'], ['invalid', 0, 0]], [['4C', '4C', '2D', '4S', '4D', '4C', '4S', '2H', '2H'], ['valid', 300, 90]]], [[['2D', 'QC', 'QH', 'QS', 'JK', 'JK', 'QH', 'JK', 'QH'], ['invalid', 0, 0]], [['AH', 'AS', 'AD', 'JK', 'AC', 'JK', 'AH', 'AC', '2S'], ['valid', 300, 240]], [['8D'], ['invalid', 0, 0]], [['AD', 'AD', 'AD', 'AH', '2S', 'AH'], ['valid', 0, 120]], [['2D', '9C', '9C', '9S', '9D'], ['valid', 0, 60]], [['KH', 'KD', 'KH', 'KS', 'KH'], ['valid', 0, 50]], [['KD', 'KH', '2D', 'JK', 'KH', '2S', '2D'], ['invalid', 0, 0]], [['KD', '2D', 'KH', 'KD', 'KH', '2C', 'KS', '2S', 'KS', 'KS'], ['valid', 300, 130]]], [[['5H', '2S', '5C'], ['valid', 0, 30]], [['TD', 'TH', 'TS', 'TD'], ['valid', 0, 40]], [['2D', '5D', 'JK', '2D', '5S'], ['valid', 0, 100]], [['7S', '2H', '7H', '7S', '6S'], ['invalid', 0, 0]], [['2H', 'JK', 'KC', '2H', 'KD', 'KH'], ['valid', 0, 120]], [['2H', 'TS', 'TD', 'JK'], ['valid', 0, 90]], [['QS', '2D', 'QH', 'QC', 'JK', '2C', 'QC', '2D', 'QS'], ['invalid', 0, 0]], [['2D', 'KC', 'JK', 'KS', 'KS', 'JK', 'KD', 'KH'], ['valid', 300, 170]]]]
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 0['valid', 300, 190]['valid', 300, 190]Passed
meld case 1['valid', 0, 30]['valid', 0, 30]Passed
meld case 2['invalid', 0, 0]['invalid', 0, 0]Passed
meld case 3['invalid', 0, 0]['invalid', 0, 0]Passed
meld case 4['valid', 0, 70]['valid', 0, 70]Passed
meld case 5['valid', 0, 80]['valid', 0, 80]Passed
meld case 6['valid', 300, 130]['invalid', 0, 0]Failed
meld case 7['valid', 300, 160]['valid', 300, 160]Passed

SHA-256 / a98805bfbde81dbb358a86b5da0203d9551999a78fa98126186eec2558793a0b

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(x):
    meld = x
    wild = [c for c in meld if c == 'JK' or c[0] == '2']
    nat = [c for c in meld if c not in wild]
    if len(meld) < 3 or len(nat) < 2 or len(wild) >= 3:
        return ['invalid', 0, 0]
    if len(set(c[0] for c in nat)) != 1 or nat[0][0] == '3':
        return ['invalid', 0, 0]
    def pts(c):
        if c == 'JK':
            return 50
        if c[0] in '2A':
            return 20
        if c[0] in '89TJQK':
            return 10
        return 5
    bonus = 0
    if len(meld) >= 7:
        bonus = 500 if not wild else 300
    return ['valid', bonus, sum(pts(c) for c in meld)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[['AC', 'AD', 'AC', 'AC', 'JK', '2H', 'AD', 'AC'], ['valid', 300, 190]], [['JH', 'JH', 'JC'], ['valid', 0, 30]], [['JK', '2S', '2H', '2D'], ['invalid', 0, 0]], [['2H', '5C', '2D', '2H', '2D'], ['invalid', 0, 0]], [['2H', '2H', '6H', '2S', '6H'], ['valid', 0, 70]], [['AD', 'AC', 'AS', '2S'], ['valid', 0, 80]], [['2S', '2D', '5H', '2C', '5C', '5D', 'JK', '5D'], ['invalid', 0, 0]], [['8C', 'JK', 'JK', '8H', '2S', '8D', '8S'], ['valid', 300, 160]]], [[['2H', '6C', '6D', '6D', '6H', '2S'], ['valid', 0, 60]], [['KH', 'JK', 'KD', 'JK', 'KH', 'KC'], ['valid', 0, 140]], [[], ['invalid', 0, 0]], [['3S', 'JK', '3H', '3H', '3D', '2S'], ['invalid', 0, 0]], [['2S', '2D', '5H', '2C', '5C', '5D', 'JK', '5D'], ['invalid', 0, 0]], [['TD', 'TH'], ['invalid', 0, 0]], [['4C', '2H', '2H', '4S', '2H', '2S'], ['invalid', 0, 0]], [['JK', '5S', '2D', '2D', '5C'], ['valid', 0, 100]]], [[['2H', '2C', '2H'], ['invalid', 0, 0]], [['KD', 'JS', '2C'], ['invalid', 0, 0]], [['2S', 'AH', 'AS', 'AC', 'AD', 'AH', 'AS', 'AD'], ['valid', 300, 160]], [['2D', 'AC', 'AH', 'AH', '2S'], ['valid', 0, 100]], [['7S', '2H'], ['invalid', 0, 0]], [['2S', '2D'], ['invalid', 0, 0]], [['AH', 'AS', 'JK', 'AD', '2D', 'AD', 'AH', '2C', 'JK', 'AS'], ['invalid', 0, 0]], [['4C', '4C', '2D', '4S', '4D', '4C', '4S', '2H', '2H'], ['valid', 300, 90]]], [[['2D', 'QC', 'QH', 'QS', 'JK', 'JK', 'QH', 'JK', 'QH'], ['invalid', 0, 0]], [['AH', 'AS', 'AD', 'JK', 'AC', 'JK', 'AH', 'AC', '2S'], ['valid', 300, 240]], [['8D'], ['invalid', 0, 0]], [['AD', 'AD', 'AD', 'AH', '2S', 'AH'], ['valid', 0, 120]], [['2D', '9C', '9C', '9S', '9D'], ['valid', 0, 60]], [['KH', 'KD', 'KH', 'KS', 'KH'], ['valid', 0, 50]], [['KD', 'KH', '2D', 'JK', 'KH', '2S', '2D'], ['invalid', 0, 0]], [['KD', '2D', 'KH', 'KD', 'KH', '2C', 'KS', '2S', 'KS', 'KS'], ['valid', 300, 130]]], [[['5H', '2S', '5C'], ['valid', 0, 30]], [['TD', 'TH', 'TS', 'TD'], ['valid', 0, 40]], [['2D', '5D', 'JK', '2D', '5S'], ['valid', 0, 100]], [['7S', '2H', '7H', '7S', '6S'], ['invalid', 0, 0]], [['2H', 'JK', 'KC', '2H', 'KD', 'KH'], ['valid', 0, 120]], [['2H', 'TS', 'TD', 'JK'], ['valid', 0, 90]], [['QS', '2D', 'QH', 'QC', 'JK', '2C', 'QC', '2D', 'QS'], ['invalid', 0, 0]], [['2D', 'KC', 'JK', 'KS', 'KS', 'JK', 'KD', 'KH'], ['valid', 300, 170]]]]
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 0['valid', 300, 190]['valid', 300, 190]Passed
meld case 1['valid', 0, 30]['valid', 0, 30]Passed
meld case 2['invalid', 0, 0]['invalid', 0, 0]Passed
meld case 3['invalid', 0, 0]['invalid', 0, 0]Passed
meld case 4['invalid', 0, 0]['valid', 0, 70]Failed
meld case 5['valid', 0, 80]['valid', 0, 80]Passed
meld case 6['invalid', 0, 0]['invalid', 0, 0]Passed
meld case 7['invalid', 0, 0]['valid', 300, 160]Failed

SHA-256 / 3222d8af939bd69526e8332b4ebe525cbf3b2eb5ec0822688af3ae9774472a4a

3 / The verified repair

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

N = 1
observations = []
def solve(x):
    meld = x
    wild = [c for c in meld if c == 'JK' or c[0] == '2']
    nat = [c for c in meld if c not in wild]
    if len(meld) < 3 or len(nat) < 2 or len(wild) > 3:
        return ['invalid', 0, 0]
    if len(set(c[0] for c in nat)) != 1 or nat[0][0] == '3':
        return ['invalid', 0, 0]
    def pts(c):
        if c == 'JK':
            return 50
        if c[0] in '2A':
            return 20
        if c[0] in '89TJQK':
            return 10
        return 5
    bonus = 0
    if len(meld) >= 7:
        bonus = 500 if not wild else 300
    return ['valid', bonus, sum(pts(c) for c in meld)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[['AC', 'AD', 'AC', 'AC', 'JK', '2H', 'AD', 'AC'], ['valid', 300, 190]], [['JH', 'JH', 'JC'], ['valid', 0, 30]], [['JK', '2S', '2H', '2D'], ['invalid', 0, 0]], [['2H', '5C', '2D', '2H', '2D'], ['invalid', 0, 0]], [['2H', '2H', '6H', '2S', '6H'], ['valid', 0, 70]], [['AD', 'AC', 'AS', '2S'], ['valid', 0, 80]], [['2S', '2D', '5H', '2C', '5C', '5D', 'JK', '5D'], ['invalid', 0, 0]], [['8C', 'JK', 'JK', '8H', '2S', '8D', '8S'], ['valid', 300, 160]]], [[['2H', '6C', '6D', '6D', '6H', '2S'], ['valid', 0, 60]], [['KH', 'JK', 'KD', 'JK', 'KH', 'KC'], ['valid', 0, 140]], [[], ['invalid', 0, 0]], [['3S', 'JK', '3H', '3H', '3D', '2S'], ['invalid', 0, 0]], [['2S', '2D', '5H', '2C', '5C', '5D', 'JK', '5D'], ['invalid', 0, 0]], [['TD', 'TH'], ['invalid', 0, 0]], [['4C', '2H', '2H', '4S', '2H', '2S'], ['invalid', 0, 0]], [['JK', '5S', '2D', '2D', '5C'], ['valid', 0, 100]]], [[['2H', '2C', '2H'], ['invalid', 0, 0]], [['KD', 'JS', '2C'], ['invalid', 0, 0]], [['2S', 'AH', 'AS', 'AC', 'AD', 'AH', 'AS', 'AD'], ['valid', 300, 160]], [['2D', 'AC', 'AH', 'AH', '2S'], ['valid', 0, 100]], [['7S', '2H'], ['invalid', 0, 0]], [['2S', '2D'], ['invalid', 0, 0]], [['AH', 'AS', 'JK', 'AD', '2D', 'AD', 'AH', '2C', 'JK', 'AS'], ['invalid', 0, 0]], [['4C', '4C', '2D', '4S', '4D', '4C', '4S', '2H', '2H'], ['valid', 300, 90]]], [[['2D', 'QC', 'QH', 'QS', 'JK', 'JK', 'QH', 'JK', 'QH'], ['invalid', 0, 0]], [['AH', 'AS', 'AD', 'JK', 'AC', 'JK', 'AH', 'AC', '2S'], ['valid', 300, 240]], [['8D'], ['invalid', 0, 0]], [['AD', 'AD', 'AD', 'AH', '2S', 'AH'], ['valid', 0, 120]], [['2D', '9C', '9C', '9S', '9D'], ['valid', 0, 60]], [['KH', 'KD', 'KH', 'KS', 'KH'], ['valid', 0, 50]], [['KD', 'KH', '2D', 'JK', 'KH', '2S', '2D'], ['invalid', 0, 0]], [['KD', '2D', 'KH', 'KD', 'KH', '2C', 'KS', '2S', 'KS', 'KS'], ['valid', 300, 130]]], [[['5H', '2S', '5C'], ['valid', 0, 30]], [['TD', 'TH', 'TS', 'TD'], ['valid', 0, 40]], [['2D', '5D', 'JK', '2D', '5S'], ['valid', 0, 100]], [['7S', '2H', '7H', '7S', '6S'], ['invalid', 0, 0]], [['2H', 'JK', 'KC', '2H', 'KD', 'KH'], ['valid', 0, 120]], [['2H', 'TS', 'TD', 'JK'], ['valid', 0, 90]], [['QS', '2D', 'QH', 'QC', 'JK', '2C', 'QC', '2D', 'QS'], ['invalid', 0, 0]], [['2D', 'KC', 'JK', 'KS', 'KS', 'JK', 'KD', 'KH'], ['valid', 300, 170]]]]
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 0['valid', 300, 190]['valid', 300, 190]Passed
meld case 1['valid', 0, 30]['valid', 0, 30]Passed
meld case 2['invalid', 0, 0]['invalid', 0, 0]Passed
meld case 3['invalid', 0, 0]['invalid', 0, 0]Passed
meld case 4['valid', 0, 70]['valid', 0, 70]Passed
meld case 5['valid', 0, 80]['valid', 0, 80]Passed
meld case 6['invalid', 0, 0]['invalid', 0, 0]Passed
meld case 7['valid', 300, 160]['valid', 300, 160]Passed

SHA-256 / 1e82ae343a6e9f6f71aa699f7e73fde96a836324251b94e55395abde8969d818

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

Case digest / 4fc7a4ac649d323f52b6cdecf201306b39d9918b8d5b200c1fc2ccb07a7921c1