FAILURE MAP
← Case archive

FA-83651 / Card game rule engines / Open access

The left bower cannot trump in · case 01

Playing the left bower on a led plain suit loses the trick.

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

ROOT CAUSE

The ruff test compares printed suits instead of effective suits.

VERIFIED REPAIR

Use the effective suit of both cards when testing for a ruff.

Unsuccessful approach: Using the printed suit only for the current winner lets any trump overtake a winning left bower.

Case contract

Input [four_cards, leader, trump]. The jack of trump (right bower) is highest, the jack of the same-colour suit (left bower) is second and belongs to the trump suit; then A K Q T 9 of trump. Otherwise the highest card of the effective led suit (A K Q J T 9) wins. Return the winning seat.

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, leader, trump = x
    partner = {'S': 'C', 'C': 'S', 'H': 'D', 'D': 'H'}[trump]
    def suit(c):
        if c[0] == 'J' and c[1] == partner:
            return trump
        return c[1]
    def power(c):
        if suit(c) == trump:
            if c[0] == 'J':
                return 100 if c[1] == trump else 99
            return 50 + '9TJQKA'.index(c[0])
        return '9TJQKA'.index(c[0])
    best = 0
    for i in range(1, len(cards)):
        c = cards[i]
        b = cards[best]
        if suit(c) == suit(b) and power(c) > power(b):
            best = i
        elif c[1] == trump and b[1] != trump:
            best = i
    return (leader + best) % 4
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['9S', 'JD', 'AC', '9H'], 0, 'H'], 1], [[['9H', 'JS', 'TH', 'QC'], 3, 'C'], 0], [[['KS', '9H', 'QC', '9D'], 3, 'S'], 3], [[['JD', 'QD', 'AD', 'AC'], 0, 'H'], 0], [[['JD', 'AS', 'JC', 'QH'], 3, 'S'], 1], [[['KH', '9S', 'JH', 'QS'], 3, 'D'], 1], [[['TS', 'JS', 'TC', 'QC'], 2, 'S'], 3], [[['JS', 'KD', 'AS', 'TC'], 1, 'C'], 1]], [[[['KH', '9S', 'JH', 'QS'], 3, 'D'], 1], [[['JD', '9H', 'TH', 'AS'], 0, 'H'], 0], [[['JD', 'TS', '9C', 'QD'], 3, 'C'], 1], [[['QS', 'KD', '9S', '9C'], 1, 'S'], 1], [[['TH', 'AS', 'TD', 'KD'], 2, 'C'], 2], [[['QS', 'TC', 'KH', 'AS'], 0, 'D'], 3], [[['KD', 'TH', 'AD', 'AH'], 2, 'C'], 0], [[['JH', 'KD', 'TS', 'TD'], 3, 'D'], 3]], [[[['KC', 'KD', 'JS', 'QH'], 1, 'C'], 3], [[['JC', 'TH', '9H', 'QD'], 1, 'D'], 0], [[['9D', 'AS', 'JS', 'TD'], 0, 'S'], 2], [[['JS', 'TH', 'TC', 'JD'], 2, 'C'], 2], [[['TC', 'JS', 'AC', 'TH'], 1, 'C'], 2], [[['QC', 'QD', 'KC', 'JS'], 2, 'C'], 1], [[['AC', 'TC', 'AH', 'JS'], 1, 'C'], 0], [[['JD', 'TH', 'JS', 'JC'], 3, 'H'], 3]], [[[['AH', 'KD', '9S', 'KC'], 3, 'S'], 1], [[['JD', 'QD', 'KC', 'JC'], 3, 'S'], 2], [[['TH', 'AH', 'JD', 'QD'], 2, 'S'], 3], [[['KS', '9D', 'TD', 'JS'], 0, 'C'], 3], [[['9C', 'JH', 'JS', 'TC'], 2, 'C'], 0], [[['QD', 'AH', 'KS', 'TC'], 3, 'H'], 0], [[['AS', 'TC', 'TD', 'QS'], 1, 'S'], 1], [[['JC', 'KH', 'AS', 'QH'], 0, 'S'], 0]], [[[['QH', 'AD', 'AS', 'QC'], 3, 'D'], 0], [[['TC', 'JD', 'QS', 'JC'], 3, 'C'], 2], [[['AH', 'JH', '9C', 'TS'], 0, 'D'], 1], [[['AD', 'KS', 'JH', 'JD'], 2, 'H'], 0], [[['TH', 'JS', 'QC', 'JC'], 2, 'C'], 1], [[['KC', '9H', 'JS', 'JC'], 2, 'S'], 0], [[['KS', '9S', 'TS', 'JS'], 1, 'C'], 0], [[['KS', 'JS', 'TC', 'JD'], 0, 'C'], 1]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("trick 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
trick case 031Failed
trick case 120Failed
trick case 233Passed
trick case 300Passed
trick case 411Passed
trick case 531Failed
trick case 633Passed
trick case 701Failed

SHA-256 / a854bc5de4d3cb8436046e3a6fce151d1f19586caee34fd4ace0050e5a71f9e1

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(x):
    cards, leader, trump = x
    partner = {'S': 'C', 'C': 'S', 'H': 'D', 'D': 'H'}[trump]
    def suit(c):
        if c[0] == 'J' and c[1] == partner:
            return trump
        return c[1]
    def power(c):
        if suit(c) == trump:
            if c[0] == 'J':
                return 100 if c[1] == trump else 99
            return 50 + '9TJQKA'.index(c[0])
        return '9TJQKA'.index(c[0])
    best = 0
    for i in range(1, len(cards)):
        c = cards[i]
        b = cards[best]
        if suit(c) == suit(b) and power(c) > power(b):
            best = i
        elif suit(c) == trump and b[1] != trump:
            best = i
    return (leader + best) % 4
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['9S', 'JD', 'AC', '9H'], 0, 'H'], 1], [[['9H', 'JS', 'TH', 'QC'], 3, 'C'], 0], [[['KS', '9H', 'QC', '9D'], 3, 'S'], 3], [[['JD', 'QD', 'AD', 'AC'], 0, 'H'], 0], [[['JD', 'AS', 'JC', 'QH'], 3, 'S'], 1], [[['KH', '9S', 'JH', 'QS'], 3, 'D'], 1], [[['TS', 'JS', 'TC', 'QC'], 2, 'S'], 3], [[['JS', 'KD', 'AS', 'TC'], 1, 'C'], 1]], [[[['KH', '9S', 'JH', 'QS'], 3, 'D'], 1], [[['JD', '9H', 'TH', 'AS'], 0, 'H'], 0], [[['JD', 'TS', '9C', 'QD'], 3, 'C'], 1], [[['QS', 'KD', '9S', '9C'], 1, 'S'], 1], [[['TH', 'AS', 'TD', 'KD'], 2, 'C'], 2], [[['QS', 'TC', 'KH', 'AS'], 0, 'D'], 3], [[['KD', 'TH', 'AD', 'AH'], 2, 'C'], 0], [[['JH', 'KD', 'TS', 'TD'], 3, 'D'], 3]], [[[['KC', 'KD', 'JS', 'QH'], 1, 'C'], 3], [[['JC', 'TH', '9H', 'QD'], 1, 'D'], 0], [[['9D', 'AS', 'JS', 'TD'], 0, 'S'], 2], [[['JS', 'TH', 'TC', 'JD'], 2, 'C'], 2], [[['TC', 'JS', 'AC', 'TH'], 1, 'C'], 2], [[['QC', 'QD', 'KC', 'JS'], 2, 'C'], 1], [[['AC', 'TC', 'AH', 'JS'], 1, 'C'], 0], [[['JD', 'TH', 'JS', 'JC'], 3, 'H'], 3]], [[[['AH', 'KD', '9S', 'KC'], 3, 'S'], 1], [[['JD', 'QD', 'KC', 'JC'], 3, 'S'], 2], [[['TH', 'AH', 'JD', 'QD'], 2, 'S'], 3], [[['KS', '9D', 'TD', 'JS'], 0, 'C'], 3], [[['9C', 'JH', 'JS', 'TC'], 2, 'C'], 0], [[['QD', 'AH', 'KS', 'TC'], 3, 'H'], 0], [[['AS', 'TC', 'TD', 'QS'], 1, 'S'], 1], [[['JC', 'KH', 'AS', 'QH'], 0, 'S'], 0]], [[[['QH', 'AD', 'AS', 'QC'], 3, 'D'], 0], [[['TC', 'JD', 'QS', 'JC'], 3, 'C'], 2], [[['AH', 'JH', '9C', 'TS'], 0, 'D'], 1], [[['AD', 'KS', 'JH', 'JD'], 2, 'H'], 0], [[['TH', 'JS', 'QC', 'JC'], 2, 'C'], 1], [[['KC', '9H', 'JS', 'JC'], 2, 'S'], 0], [[['KS', '9S', 'TS', 'JS'], 1, 'C'], 0], [[['KS', 'JS', 'TC', 'JD'], 0, 'C'], 1]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("trick 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
trick case 031Failed
trick case 120Failed
trick case 233Passed
trick case 300Passed
trick case 411Passed
trick case 511Passed
trick case 633Passed
trick case 701Failed

SHA-256 / b78683fdaecd23a14399f39957b72e7306592658d188cbeb9ca3117bdae5e597

3 / The verified repair

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

N = 1
observations = []
def solve(x):
    cards, leader, trump = x
    partner = {'S': 'C', 'C': 'S', 'H': 'D', 'D': 'H'}[trump]
    def suit(c):
        if c[0] == 'J' and c[1] == partner:
            return trump
        return c[1]
    def power(c):
        if suit(c) == trump:
            if c[0] == 'J':
                return 100 if c[1] == trump else 99
            return 50 + '9TJQKA'.index(c[0])
        return '9TJQKA'.index(c[0])
    best = 0
    for i in range(1, len(cards)):
        c = cards[i]
        b = cards[best]
        if suit(c) == suit(b) and power(c) > power(b):
            best = i
        elif suit(c) == trump and suit(b) != trump:
            best = i
    return (leader + best) % 4
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['9S', 'JD', 'AC', '9H'], 0, 'H'], 1], [[['9H', 'JS', 'TH', 'QC'], 3, 'C'], 0], [[['KS', '9H', 'QC', '9D'], 3, 'S'], 3], [[['JD', 'QD', 'AD', 'AC'], 0, 'H'], 0], [[['JD', 'AS', 'JC', 'QH'], 3, 'S'], 1], [[['KH', '9S', 'JH', 'QS'], 3, 'D'], 1], [[['TS', 'JS', 'TC', 'QC'], 2, 'S'], 3], [[['JS', 'KD', 'AS', 'TC'], 1, 'C'], 1]], [[[['KH', '9S', 'JH', 'QS'], 3, 'D'], 1], [[['JD', '9H', 'TH', 'AS'], 0, 'H'], 0], [[['JD', 'TS', '9C', 'QD'], 3, 'C'], 1], [[['QS', 'KD', '9S', '9C'], 1, 'S'], 1], [[['TH', 'AS', 'TD', 'KD'], 2, 'C'], 2], [[['QS', 'TC', 'KH', 'AS'], 0, 'D'], 3], [[['KD', 'TH', 'AD', 'AH'], 2, 'C'], 0], [[['JH', 'KD', 'TS', 'TD'], 3, 'D'], 3]], [[[['KC', 'KD', 'JS', 'QH'], 1, 'C'], 3], [[['JC', 'TH', '9H', 'QD'], 1, 'D'], 0], [[['9D', 'AS', 'JS', 'TD'], 0, 'S'], 2], [[['JS', 'TH', 'TC', 'JD'], 2, 'C'], 2], [[['TC', 'JS', 'AC', 'TH'], 1, 'C'], 2], [[['QC', 'QD', 'KC', 'JS'], 2, 'C'], 1], [[['AC', 'TC', 'AH', 'JS'], 1, 'C'], 0], [[['JD', 'TH', 'JS', 'JC'], 3, 'H'], 3]], [[[['AH', 'KD', '9S', 'KC'], 3, 'S'], 1], [[['JD', 'QD', 'KC', 'JC'], 3, 'S'], 2], [[['TH', 'AH', 'JD', 'QD'], 2, 'S'], 3], [[['KS', '9D', 'TD', 'JS'], 0, 'C'], 3], [[['9C', 'JH', 'JS', 'TC'], 2, 'C'], 0], [[['QD', 'AH', 'KS', 'TC'], 3, 'H'], 0], [[['AS', 'TC', 'TD', 'QS'], 1, 'S'], 1], [[['JC', 'KH', 'AS', 'QH'], 0, 'S'], 0]], [[[['QH', 'AD', 'AS', 'QC'], 3, 'D'], 0], [[['TC', 'JD', 'QS', 'JC'], 3, 'C'], 2], [[['AH', 'JH', '9C', 'TS'], 0, 'D'], 1], [[['AD', 'KS', 'JH', 'JD'], 2, 'H'], 0], [[['TH', 'JS', 'QC', 'JC'], 2, 'C'], 1], [[['KC', '9H', 'JS', 'JC'], 2, 'S'], 0], [[['KS', '9S', 'TS', 'JS'], 1, 'C'], 0], [[['KS', 'JS', 'TC', 'JD'], 0, 'C'], 1]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
    check("trick 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
trick case 011Passed
trick case 100Passed
trick case 233Passed
trick case 300Passed
trick case 411Passed
trick case 511Passed
trick case 633Passed
trick case 711Passed

SHA-256 / 1a06a32b62c1fe4df3fdf91f1dff3ce7e16371552a929eb86ea5a4320cfa4b43

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

Case digest / 9361b8c9cbb71404cdcbe2a6a5d5b8a6a5f5c23bcbe0dca5ac67b38683ac7823