FA-83631 / Card game rule engines / Open access
The last bidder becomes declarer · case 01
When partner first named the strain, the raiser is reported as declarer.
ROOT CAUSE
The declarer is taken from the last bid rather than the first mention of the strain.
THE FAILURE
The declarer is taken from the last bid rather than the first mention of the strain.
Unsuccessful approach: Overwriting the first-mention table each time keeps the most recent mention instead.
Case contract
Input list of calls (bids like "2H"/"3N", "P", "X", "XX") starting with dealer seat 0. Each bid must outrank the previous bid (level, then C<D<H<S<N). X requires the last non-pass call to be an opponent bid; XX an opponent X. Four initial passes -> ["passed out", None, None]; three passes after a bid -> ["contract", bid+X/XX, declarer] where declarer is the first player of the declaring side to name the strain. Illegal call -> ["illegal", index, None]; unfinished -> ["open", None, None].
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):
calls = x
strains = 'CDHSN'
last_bid = None
last_bidder = None
state = 0
last_call = None
last_caller = None
passes = 0
first = {}
for i, call in enumerate(calls):
seat = i % 4
if call == 'P':
passes += 1
if last_bid is None and passes == 4:
return ['passed out', None, None]
if last_bid is not None and passes == 3:
side = last_bidder % 2
return ['contract', last_bid + ['', 'X', 'XX'][state], last_bidder]
continue
if call == 'X':
if last_call is None or last_call not in ('bid',) or (last_caller - seat) % 2 == 0:
return ['illegal', i, None]
state = 1
elif call == 'XX':
if last_call != 'X' or (last_caller - seat) % 2 == 0:
return ['illegal', i, None]
state = 2
else:
rank = (int(call[0]), strains.index(call[1]))
if last_bid is not None and rank <= (int(last_bid[0]), strains.index(last_bid[1])):
return ['illegal', i, None]
last_bid = call
last_bidder = seat
state = 0
first.setdefault((seat % 2, call[1]), seat)
passes = 0
last_call = 'bid' if call not in ('X', 'XX') else call
last_caller = seat
return ['open', None, None]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[['X', '1D', 'P'], ['illegal', 0, None]], [['P', 'X', '1C', 'P', 'P', 'P', 'P', '1N', '2S', '3H'], ['illegal', 1, None]], [['1S', 'P', 'P', '2C', '2N', 'P', '2S'], ['illegal', 6, None]], [['P', '1S', 'P', 'P', 'P', '2D', 'P'], ['contract', '1S', 1]], [['P', 'P'], ['open', None, None]], [['1H'], ['open', None, None]], [['1C', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 2]], [['1C', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 2]]], [[['P', 'P', '1C', 'P', 'X', 'P', '1H', '2C', '2N'], ['illegal', 4, None]], [['1C', '1C', 'P', '1S', 'P', 'X', 'P', 'P', 'XX'], ['illegal', 1, None]], [['P', 'P', '1C', 'P'], ['open', None, None]], [['1S', 'P', 'P', '2C', 'XX', 'X'], ['illegal', 4, None]], [['XX', '1C', '1N', 'P', 'P', 'P'], ['illegal', 0, None]], [['1C', 'XX', 'P', 'X', 'P', 'P', '1D', 'X', 'P', 'P', 'P'], ['illegal', 1, None]], [['1C', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 2]], [['P', '1D', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 3]]], [[['P', 'P'], ['open', None, None]], [['1H', 'P', 'XX', 'X', '1D', '2D'], ['illegal', 2, None]], [['XX'], ['illegal', 0, None]], [['XX', 'P'], ['illegal', 0, None]], [['X', 'P', '1C', 'P', 'P', 'P', 'X'], ['illegal', 0, None]], [['P', 'X', 'XX', 'X', 'X', 'P', 'X', 'P'], ['illegal', 1, None]], [['1C', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 2]], [['1H', 'P', '1S', 'P', '2S', 'P', 'P', 'P'], ['contract', '2S', 2]]], [[['1H', '1S', 'P', '2H', 'P', 'P', '2N', 'X', 'P', '3D'], ['open', None, None]], [['P', 'X', 'X', '1H', 'P', 'P', 'X', '2D', 'P', 'P'], ['illegal', 1, None]], [['P', 'P', 'X', 'P', 'X'], ['illegal', 2, None]], [['XX', 'P', 'P', 'P'], ['illegal', 0, None]], [['P', 'X'], ['illegal', 1, None]], [['X', '1D', 'P', '2C', 'P', 'P', 'P', 'XX', '2D', 'X', '2H', 'P', '2S'], ['illegal', 0, None]], [['1C', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 2]], [['1C', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 2]]], [[['1D', 'XX', 'P', 'P', 'XX', 'P'], ['illegal', 1, None]], [['1S', 'P', 'XX', '2D', '2S', 'P'], ['illegal', 2, None]], [['P', 'P', '1D', 'P', 'P', 'P', 'P', '1H', 'X', '1N', 'P'], ['contract', '1D', 2]], [['P', 'P', '1H', 'XX', '1S', '2C', '2H', '2D', 'P', 'P', '3C', 'XX', 'P'], ['illegal', 3, None]], [['P', '1C', 'XX', 'P', 'P', 'P', 'P', '1N', 'P'], ['illegal', 2, None]], [['P', '1D', 'X', '2C', '2S', 'P', '3D', 'P', 'P', 'P'], ['contract', '3D', 2]], [['1C', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 2]], [['P', '1D', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 3]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("auction 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 |
|---|---|---|---|
| auction case 0 | ['illegal', 0, None] | ['illegal', 0, None] | Passed |
| auction case 1 | ['illegal', 1, None] | ['illegal', 1, None] | Passed |
| auction case 2 | ['illegal', 6, None] | ['illegal', 6, None] | Passed |
| auction case 3 | ['contract', '1S', 1] | ['contract', '1S', 1] | Passed |
| auction case 4 | ['open', None, None] | ['open', None, None] | Passed |
| auction case 5 | ['open', None, None] | ['open', None, None] | Passed |
| auction case 6 | ['contract', '2H', 0] | ['contract', '2H', 2] | Failed |
| auction case 7 | ['contract', '2H', 0] | ['contract', '2H', 2] | Failed |
SHA-256 / 59312ff004f4c75a70457ebf6fd27c01b1d47ec01afc4770d2de43f598828a10
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
calls = x
strains = 'CDHSN'
last_bid = None
last_bidder = None
state = 0
last_call = None
last_caller = None
passes = 0
first = {}
for i, call in enumerate(calls):
seat = i % 4
if call == 'P':
passes += 1
if last_bid is None and passes == 4:
return ['passed out', None, None]
if last_bid is not None and passes == 3:
side = last_bidder % 2
return ['contract', last_bid + ['', 'X', 'XX'][state], first[(side, last_bid[1])]]
continue
if call == 'X':
if last_call is None or last_call not in ('bid',) or (last_caller - seat) % 2 == 0:
return ['illegal', i, None]
state = 1
elif call == 'XX':
if last_call != 'X' or (last_caller - seat) % 2 == 0:
return ['illegal', i, None]
state = 2
else:
rank = (int(call[0]), strains.index(call[1]))
if last_bid is not None and rank <= (int(last_bid[0]), strains.index(last_bid[1])):
return ['illegal', i, None]
last_bid = call
last_bidder = seat
state = 0
first[(seat % 2, call[1])] = seat
passes = 0
last_call = 'bid' if call not in ('X', 'XX') else call
last_caller = seat
return ['open', None, None]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[[['X', '1D', 'P'], ['illegal', 0, None]], [['P', 'X', '1C', 'P', 'P', 'P', 'P', '1N', '2S', '3H'], ['illegal', 1, None]], [['1S', 'P', 'P', '2C', '2N', 'P', '2S'], ['illegal', 6, None]], [['P', '1S', 'P', 'P', 'P', '2D', 'P'], ['contract', '1S', 1]], [['P', 'P'], ['open', None, None]], [['1H'], ['open', None, None]], [['1C', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 2]], [['1C', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 2]]], [[['P', 'P', '1C', 'P', 'X', 'P', '1H', '2C', '2N'], ['illegal', 4, None]], [['1C', '1C', 'P', '1S', 'P', 'X', 'P', 'P', 'XX'], ['illegal', 1, None]], [['P', 'P', '1C', 'P'], ['open', None, None]], [['1S', 'P', 'P', '2C', 'XX', 'X'], ['illegal', 4, None]], [['XX', '1C', '1N', 'P', 'P', 'P'], ['illegal', 0, None]], [['1C', 'XX', 'P', 'X', 'P', 'P', '1D', 'X', 'P', 'P', 'P'], ['illegal', 1, None]], [['1C', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 2]], [['P', '1D', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 3]]], [[['P', 'P'], ['open', None, None]], [['1H', 'P', 'XX', 'X', '1D', '2D'], ['illegal', 2, None]], [['XX'], ['illegal', 0, None]], [['XX', 'P'], ['illegal', 0, None]], [['X', 'P', '1C', 'P', 'P', 'P', 'X'], ['illegal', 0, None]], [['P', 'X', 'XX', 'X', 'X', 'P', 'X', 'P'], ['illegal', 1, None]], [['1C', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 2]], [['1H', 'P', '1S', 'P', '2S', 'P', 'P', 'P'], ['contract', '2S', 2]]], [[['1H', '1S', 'P', '2H', 'P', 'P', '2N', 'X', 'P', '3D'], ['open', None, None]], [['P', 'X', 'X', '1H', 'P', 'P', 'X', '2D', 'P', 'P'], ['illegal', 1, None]], [['P', 'P', 'X', 'P', 'X'], ['illegal', 2, None]], [['XX', 'P', 'P', 'P'], ['illegal', 0, None]], [['P', 'X'], ['illegal', 1, None]], [['X', '1D', 'P', '2C', 'P', 'P', 'P', 'XX', '2D', 'X', '2H', 'P', '2S'], ['illegal', 0, None]], [['1C', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 2]], [['1C', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 2]]], [[['1D', 'XX', 'P', 'P', 'XX', 'P'], ['illegal', 1, None]], [['1S', 'P', 'XX', '2D', '2S', 'P'], ['illegal', 2, None]], [['P', 'P', '1D', 'P', 'P', 'P', 'P', '1H', 'X', '1N', 'P'], ['contract', '1D', 2]], [['P', 'P', '1H', 'XX', '1S', '2C', '2H', '2D', 'P', 'P', '3C', 'XX', 'P'], ['illegal', 3, None]], [['P', '1C', 'XX', 'P', 'P', 'P', 'P', '1N', 'P'], ['illegal', 2, None]], [['P', '1D', 'X', '2C', '2S', 'P', '3D', 'P', 'P', 'P'], ['contract', '3D', 2]], [['1C', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 2]], [['P', '1D', 'P', '1H', 'P', '2H', 'P', 'P', 'P'], ['contract', '2H', 3]]]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("auction 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 |
|---|---|---|---|
| auction case 0 | ['illegal', 0, None] | ['illegal', 0, None] | Passed |
| auction case 1 | ['illegal', 1, None] | ['illegal', 1, None] | Passed |
| auction case 2 | ['illegal', 6, None] | ['illegal', 6, None] | Passed |
| auction case 3 | ['contract', '1S', 1] | ['contract', '1S', 1] | Passed |
| auction case 4 | ['open', None, None] | ['open', None, None] | Passed |
| auction case 5 | ['open', None, None] | ['open', None, None] | Passed |
| auction case 6 | ['contract', '2H', 0] | ['contract', '2H', 2] | Failed |
| auction case 7 | ['contract', '2H', 0] | ['contract', '2H', 2] | Failed |
SHA-256 / 9ce17404154ed29bd361a5fc15cf0c4b11c85de23f83a2b86f397ed55f4453cf
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 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.336746+00:00.
Case digest / 584e0a56ee872b4ee0afe6b7bd93777ab172cc12bf66546fa5515b5eb6edeac2