FA-83551 / Card game rule engines / Open access
A jack turned as starter scores nobs · case 01
The starter jack matches its own suit and adds a point to every hand.
ROOT CAUSE
The nobs loop runs over hand plus starter.
VERIFIED REPAIR
Only jacks in the hand can score nobs.
Unsuccessful approach: Scoring any jack in the hand ignores the suit match.
Case contract
Input [four_card_hand, starter, is_crib]. Fifteens (any 2-5 cards, A=1, T/J/Q/K=10) score 2; each pair 2; runs score their length for every distinct combination of the longest run length; a four-card hand flush scores 4 (+1 with the starter) but the crib scores only a five-card flush; a hand jack matching the starter suit scores 1. Return the total.
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
import itertools
N = 1
observations = []
def solve(x):
hand, starter, crib = x
order = 'A23456789TJQK'
cards = hand + [starter]
def val(c):
return min(order.index(c[0]) + 1, 10)
score = 0
for k in range(2, 6):
for combo in itertools.combinations(cards, k):
if sum(val(c) for c in combo) == 15:
score += 2
for a, b in itertools.combinations(cards, 2):
if a[0] == b[0]:
score += 2
ranks = sorted(order.index(c[0]) for c in cards)
for size in (5, 4, 3):
runs = 0
for combo in itertools.combinations(ranks, size):
if all(combo[i + 1] == combo[i] + 1 for i in range(size - 1)):
runs += 1
if runs:
score += runs * size
break
suits = [c[1] for c in hand]
if len(set(suits)) == 1:
if starter[1] == suits[0]:
score += 5
elif not crib:
score += 4
for c in cards:
if c[0] == 'J' and c[1] == starter[1]:
score += 1
return score
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['4D', '3D', 'TD', '2D'], 'JD', False], 12], [[['KD', 'AH', '4S', '8D'], 'QH', False], 4], [[['3C', '3S', '4S', '5H'], '2D', False], 12], [[['5H', '9S', '6S', '2S'], 'AH', False], 4], [[['3S', '3H', '5H', 'JH'], 'QS', False], 6], [[['4C', 'QC', 'AC', '6C'], '5D', True], 9], [[['AD', 'AH', '2S', '3H'], 'KC', False], 12], [[['7D', 'QS', 'JC', '2C'], '5D', True], 4]], [[[['6S', '8D', 'JD', '9C'], '6D', False], 7], [[['4S', '5D', '9D', 'TC'], 'QH', True], 4], [[['5H', 'KC', '2H', '3S'], '6H', True], 4], [[['9H', '7H', 'QH', 'TH'], 'JH', False], 9], [[['2C', '2S', '3S', '4H'], 'KD', False], 12], [[['4S', '3S', '9S', 'TD'], '7C', False], 0], [[['TD', 'KS', 'TH', 'TS'], 'JC', False], 6], [[['JD', 'TS', '5D', '9S'], '4C', False], 7]], [[[['3H', 'QS', '3C', '6S'], '8D', False], 2], [[['JH', '9H', '9S', 'TD'], '3H', False], 9], [[['6C', '2C', '7C', 'AC'], '4H', True], 2], [[['4D', 'AS', '7H', 'QD'], '9S', False], 2], [[['6S', '5S', 'QS', '8C'], 'AC', False], 4], [[['8S', 'QS', 'TH', '9C'], 'QC', False], 5], [[['4S', 'QD', '8D', '9H'], 'JD', False], 0], [[['JC', 'KH', '4D', '6S'], 'AH', True], 4]], [[[['9S', '3S', 'QS', 'TS'], 'QH', False], 6], [[['AS', '9S', 'TS', '2S'], '4C', False], 8], [[['TD', 'KS', 'TH', 'TS'], 'JC', False], 6], [[['KS', '5D', '3H', '8D'], 'KD', True], 6], [[['2S', '8S', 'TC', 'JS'], 'QH', False], 3], [[['9H', '7S', 'QH', '5H'], '3D', False], 4], [[['JH', 'TH', '5D', '6C'], '4C', False], 9], [[['4C', 'AD', '4H', '2D'], 'JC', False], 6]], [[[['3S', '3H', '5H', 'JH'], 'QS', False], 6], [[['2H', '5H', 'AC', '3S'], '8C', False], 5], [[['AD', '4S', '9D', '4H'], 'TH', False], 6], [[['9S', '9C', 'JH', 'KS'], '3H', False], 3], [[['KD', 'TC', 'QS', '4D'], 'TH', True], 2], [[['QD', '8S', 'JC', '5H'], '6C', False], 5], [[['JS', '8S', '2S', 'TS'], '2D', False], 6], [[['JH', '2C', '3D', '9S'], 'JS', False], 6]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("hand score 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| hand score case 0 | 13 | 12 | Failed |
| hand score case 1 | 4 | 4 | Passed |
| hand score case 2 | 12 | 12 | Passed |
| hand score case 3 | 4 | 4 | Passed |
| hand score case 4 | 6 | 6 | Passed |
| hand score case 5 | 9 | 9 | Passed |
| hand score case 6 | 12 | 12 | Passed |
| hand score case 7 | 4 | 4 | Passed |
SHA-256 / e447aba87eeee9304c5b33d5054e1f27d1f4e09213f652e40bec68a0a36fc6dd
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import itertools
N = 1
observations = []
def solve(x):
hand, starter, crib = x
order = 'A23456789TJQK'
cards = hand + [starter]
def val(c):
return min(order.index(c[0]) + 1, 10)
score = 0
for k in range(2, 6):
for combo in itertools.combinations(cards, k):
if sum(val(c) for c in combo) == 15:
score += 2
for a, b in itertools.combinations(cards, 2):
if a[0] == b[0]:
score += 2
ranks = sorted(order.index(c[0]) for c in cards)
for size in (5, 4, 3):
runs = 0
for combo in itertools.combinations(ranks, size):
if all(combo[i + 1] == combo[i] + 1 for i in range(size - 1)):
runs += 1
if runs:
score += runs * size
break
suits = [c[1] for c in hand]
if len(set(suits)) == 1:
if starter[1] == suits[0]:
score += 5
elif not crib:
score += 4
for c in hand:
if c[0] == 'J':
score += 1
return score
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['4D', '3D', 'TD', '2D'], 'JD', False], 12], [[['KD', 'AH', '4S', '8D'], 'QH', False], 4], [[['3C', '3S', '4S', '5H'], '2D', False], 12], [[['5H', '9S', '6S', '2S'], 'AH', False], 4], [[['3S', '3H', '5H', 'JH'], 'QS', False], 6], [[['4C', 'QC', 'AC', '6C'], '5D', True], 9], [[['AD', 'AH', '2S', '3H'], 'KC', False], 12], [[['7D', 'QS', 'JC', '2C'], '5D', True], 4]], [[[['6S', '8D', 'JD', '9C'], '6D', False], 7], [[['4S', '5D', '9D', 'TC'], 'QH', True], 4], [[['5H', 'KC', '2H', '3S'], '6H', True], 4], [[['9H', '7H', 'QH', 'TH'], 'JH', False], 9], [[['2C', '2S', '3S', '4H'], 'KD', False], 12], [[['4S', '3S', '9S', 'TD'], '7C', False], 0], [[['TD', 'KS', 'TH', 'TS'], 'JC', False], 6], [[['JD', 'TS', '5D', '9S'], '4C', False], 7]], [[[['3H', 'QS', '3C', '6S'], '8D', False], 2], [[['JH', '9H', '9S', 'TD'], '3H', False], 9], [[['6C', '2C', '7C', 'AC'], '4H', True], 2], [[['4D', 'AS', '7H', 'QD'], '9S', False], 2], [[['6S', '5S', 'QS', '8C'], 'AC', False], 4], [[['8S', 'QS', 'TH', '9C'], 'QC', False], 5], [[['4S', 'QD', '8D', '9H'], 'JD', False], 0], [[['JC', 'KH', '4D', '6S'], 'AH', True], 4]], [[[['9S', '3S', 'QS', 'TS'], 'QH', False], 6], [[['AS', '9S', 'TS', '2S'], '4C', False], 8], [[['TD', 'KS', 'TH', 'TS'], 'JC', False], 6], [[['KS', '5D', '3H', '8D'], 'KD', True], 6], [[['2S', '8S', 'TC', 'JS'], 'QH', False], 3], [[['9H', '7S', 'QH', '5H'], '3D', False], 4], [[['JH', 'TH', '5D', '6C'], '4C', False], 9], [[['4C', 'AD', '4H', '2D'], 'JC', False], 6]], [[[['3S', '3H', '5H', 'JH'], 'QS', False], 6], [[['2H', '5H', 'AC', '3S'], '8C', False], 5], [[['AD', '4S', '9D', '4H'], 'TH', False], 6], [[['9S', '9C', 'JH', 'KS'], '3H', False], 3], [[['KD', 'TC', 'QS', '4D'], 'TH', True], 2], [[['QD', '8S', 'JC', '5H'], '6C', False], 5], [[['JS', '8S', '2S', 'TS'], '2D', False], 6], [[['JH', '2C', '3D', '9S'], 'JS', False], 6]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("hand score 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| hand score case 0 | 12 | 12 | Passed |
| hand score case 1 | 4 | 4 | Passed |
| hand score case 2 | 12 | 12 | Passed |
| hand score case 3 | 4 | 4 | Passed |
| hand score case 4 | 7 | 6 | Failed |
| hand score case 5 | 9 | 9 | Passed |
| hand score case 6 | 12 | 12 | Passed |
| hand score case 7 | 5 | 4 | Failed |
SHA-256 / b0162c96c76d920c6ab6b9f3f1aac3e2acf3711cba2c8bf94a82df8ccfa29fd7
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import itertools
N = 1
observations = []
def solve(x):
hand, starter, crib = x
order = 'A23456789TJQK'
cards = hand + [starter]
def val(c):
return min(order.index(c[0]) + 1, 10)
score = 0
for k in range(2, 6):
for combo in itertools.combinations(cards, k):
if sum(val(c) for c in combo) == 15:
score += 2
for a, b in itertools.combinations(cards, 2):
if a[0] == b[0]:
score += 2
ranks = sorted(order.index(c[0]) for c in cards)
for size in (5, 4, 3):
runs = 0
for combo in itertools.combinations(ranks, size):
if all(combo[i + 1] == combo[i] + 1 for i in range(size - 1)):
runs += 1
if runs:
score += runs * size
break
suits = [c[1] for c in hand]
if len(set(suits)) == 1:
if starter[1] == suits[0]:
score += 5
elif not crib:
score += 4
for c in hand:
if c[0] == 'J' and c[1] == starter[1]:
score += 1
return score
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[[['4D', '3D', 'TD', '2D'], 'JD', False], 12], [[['KD', 'AH', '4S', '8D'], 'QH', False], 4], [[['3C', '3S', '4S', '5H'], '2D', False], 12], [[['5H', '9S', '6S', '2S'], 'AH', False], 4], [[['3S', '3H', '5H', 'JH'], 'QS', False], 6], [[['4C', 'QC', 'AC', '6C'], '5D', True], 9], [[['AD', 'AH', '2S', '3H'], 'KC', False], 12], [[['7D', 'QS', 'JC', '2C'], '5D', True], 4]], [[[['6S', '8D', 'JD', '9C'], '6D', False], 7], [[['4S', '5D', '9D', 'TC'], 'QH', True], 4], [[['5H', 'KC', '2H', '3S'], '6H', True], 4], [[['9H', '7H', 'QH', 'TH'], 'JH', False], 9], [[['2C', '2S', '3S', '4H'], 'KD', False], 12], [[['4S', '3S', '9S', 'TD'], '7C', False], 0], [[['TD', 'KS', 'TH', 'TS'], 'JC', False], 6], [[['JD', 'TS', '5D', '9S'], '4C', False], 7]], [[[['3H', 'QS', '3C', '6S'], '8D', False], 2], [[['JH', '9H', '9S', 'TD'], '3H', False], 9], [[['6C', '2C', '7C', 'AC'], '4H', True], 2], [[['4D', 'AS', '7H', 'QD'], '9S', False], 2], [[['6S', '5S', 'QS', '8C'], 'AC', False], 4], [[['8S', 'QS', 'TH', '9C'], 'QC', False], 5], [[['4S', 'QD', '8D', '9H'], 'JD', False], 0], [[['JC', 'KH', '4D', '6S'], 'AH', True], 4]], [[[['9S', '3S', 'QS', 'TS'], 'QH', False], 6], [[['AS', '9S', 'TS', '2S'], '4C', False], 8], [[['TD', 'KS', 'TH', 'TS'], 'JC', False], 6], [[['KS', '5D', '3H', '8D'], 'KD', True], 6], [[['2S', '8S', 'TC', 'JS'], 'QH', False], 3], [[['9H', '7S', 'QH', '5H'], '3D', False], 4], [[['JH', 'TH', '5D', '6C'], '4C', False], 9], [[['4C', 'AD', '4H', '2D'], 'JC', False], 6]], [[[['3S', '3H', '5H', 'JH'], 'QS', False], 6], [[['2H', '5H', 'AC', '3S'], '8C', False], 5], [[['AD', '4S', '9D', '4H'], 'TH', False], 6], [[['9S', '9C', 'JH', 'KS'], '3H', False], 3], [[['KD', 'TC', 'QS', '4D'], 'TH', True], 2], [[['QD', '8S', 'JC', '5H'], '6C', False], 5], [[['JS', '8S', '2S', 'TS'], '2D', False], 6], [[['JH', '2C', '3D', '9S'], 'JS', False], 6]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("hand score 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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| hand score case 0 | 12 | 12 | Passed |
| hand score case 1 | 4 | 4 | Passed |
| hand score case 2 | 12 | 12 | Passed |
| hand score case 3 | 4 | 4 | Passed |
| hand score case 4 | 6 | 6 | Passed |
| hand score case 5 | 9 | 9 | Passed |
| hand score case 6 | 12 | 12 | Passed |
| hand score case 7 | 4 | 4 | Passed |
SHA-256 / 28944d92e9ff2e97d220b4610272c2f96e4ae1d0df72110050ba49f62b4572d7
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:22.597222+00:00.
Case digest / 8f496f85ee40e67a88dd64e778d11eb87add8aac48524e1e3ac2c6ad29cb2717