FAILURE MAP
← Case archive

FA-82431 / Chess move legality / Open access

Rook on a diagonal treated as a discovered checker · case 01

En passant is rejected because a rook sits on a diagonal from the king.

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

ROOT CAUSE

Every slider is accepted as an attacker on every line, ignoring that rooks need ranks and files.

VERIFIED REPAIR

Rooks and queens attack along ranks and files; bishops and queens along diagonals.

Unsuccessful approach: Testing only df==0 treats the horizontal rank as a diagonal, so rank pins are missed.

Case contract

Input: {"board", "move": [from, to], "ep": target square or null}. Return true when the move is a legal en passant capture: a pawn on its fifth rank moves diagonally forward onto the ep square, an enemy pawn stands beside it on the origin rank, and after removing both pawns from their squares and placing the capturer, no enemy rook, bishop or queen attacks the mover's king along an open line.

Why this case matters

Move validators gate every move in engines, servers and arbiters; accepting an illegal move or rejecting a legal one corrupts the game record.

1 / The failure

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

N = 1
observations = []
def solve(x):
    b=dict(x['board']); fr,to=x['move']; p=b.get(fr)
    if p not in ('P','p') or to!=x['ep']: return False
    white=p=='P'
    d=1 if white else -1
    f0,r0=ord(fr[0])-97,int(fr[1])-1
    f1,r1=ord(to[0])-97,int(to[1])-1
    if r1-r0!=d or abs(f1-f0)!=1: return False
    if r0!=(4 if white else 3): return False
    victim=to[0]+fr[1]
    if b.get(victim)!=('p' if white else 'P'): return False
    del b[fr]; del b[victim]; b[to]=p
    ks=[s for s,v in b.items() if v==('K' if white else 'k')][0]
    kf,kr=ord(ks[0])-97,int(ks[1])-1
    for df,dr in ((1,0),(-1,0),(0,1),(0,-1),(1,1),(1,-1),(-1,1),(-1,-1)):
        cf,cr=kf+df,kr+dr
        while 0<=cf<8 and 0<=cr<8:
            v=b.get(chr(97+cf)+str(cr+1))
            if v:
                if v.isupper()!=white and v.lower() in ('r','q','b'): return False
                break
            cf+=df; cr+=dr
    return True
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('plain ep',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'd6', 'move': ['e5', 'd6']},
   True),
  ('black ep',
   {'board': {'d4': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'ep': 'e3', 'move': ['d4', 'e3']},
   True),
  ('rank pin both pawns',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False),
  ('rank pin black side',
   {'board': {'a4': 'Q', 'd4': 'p', 'e1': 'K', 'e4': 'P', 'h4': 'k'},
    'ep': 'e3',
    'move': ['d4', 'e3']},
   False),
  ('bishop diagonal after ep',
   {'board': {'c3': 'K', 'e5': 'P', 'e8': 'k', 'f5': 'p', 'f6': 'n', 'h8': 'b'},
    'ep': 'f6',
    'move': ['e5', 'f6']},
   True),
  ('no ep square',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': None, 'move': ['e5', 'd6']},
   False),
  ('bishop on the rank',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'b'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on the diagonal',
   {'board': {'c3': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'g7': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True)],
 [('bishop diagonal after ep',
   {'board': {'c3': 'K', 'e5': 'P', 'e8': 'k', 'f5': 'p', 'f6': 'n', 'h8': 'b'},
    'ep': 'f6',
    'move': ['e5', 'f6']},
   True),
  ('no ep square',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': None, 'move': ['e5', 'd6']},
   False),
  ('wrong target',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k', 'f5': 'p'},
    'ep': 'd6',
    'move': ['e5', 'f6']},
   False),
  ('wrong rank for white',
   {'board': {'d4': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'ep': 'd5', 'move': ['e4', 'd5']},
   False),
  ('black wrong rank',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'e4', 'move': ['d5', 'e4']},
   False),
  ('bishop on the rank',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'b'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on the diagonal',
   {'board': {'c3': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'g7': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on file of ep square',
   {'board': {'a1': 'K', 'd1': 'r', 'd5': 'p', 'e5': 'P', 'e8': 'k'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False)],
 [('rank pin both pawns',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False),
  ('wrong rank for white',
   {'board': {'d4': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'ep': 'd5', 'move': ['e4', 'd5']},
   False),
  ('black wrong rank',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'e4', 'move': ['d5', 'e4']},
   False),
  ('file rook behind pawn',
   {'board': {'d1': 'K', 'd5': 'p', 'd8': 'r', 'e5': 'P', 'e8': 'k'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('same file ep target',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'd3', 'move': ['e5', 'd6']},
   False),
  ('bishop on the rank',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'b'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on the diagonal',
   {'board': {'c3': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'g7': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on file of ep square',
   {'board': {'a1': 'K', 'd1': 'r', 'd5': 'p', 'e5': 'P', 'e8': 'k'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False)],
 [('plain ep',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'd6', 'move': ['e5', 'd6']},
   True),
  ('black ep',
   {'board': {'d4': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'ep': 'e3', 'move': ['d4', 'e3']},
   True),
  ('rank pin both pawns',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False),
  ('same file ep target',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'd3', 'move': ['e5', 'd6']},
   False),
  ('pin by own rook harmless',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'R'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('bishop on the rank',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'b'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on the diagonal',
   {'board': {'c3': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'g7': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on file of ep square',
   {'board': {'a1': 'K', 'd1': 'r', 'd5': 'p', 'e5': 'P', 'e8': 'k'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False)],
 [('plain ep',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'd6', 'move': ['e5', 'd6']},
   True),
  ('black ep',
   {'board': {'d4': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'ep': 'e3', 'move': ['d4', 'e3']},
   True),
  ('rank pin black side',
   {'board': {'a4': 'Q', 'd4': 'p', 'e1': 'K', 'e4': 'P', 'h4': 'k'},
    'ep': 'e3',
    'move': ['d4', 'e3']},
   False),
  ('bishop diagonal after ep',
   {'board': {'c3': 'K', 'e5': 'P', 'e8': 'k', 'f5': 'p', 'f6': 'n', 'h8': 'b'},
    'ep': 'f6',
    'move': ['e5', 'f6']},
   True),
  ('no ep square',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': None, 'move': ['e5', 'd6']},
   False),
  ('bishop on the rank',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'b'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on the diagonal',
   {'board': {'c3': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'g7': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on file of ep square',
   {'board': {'a1': 'K', 'd1': 'r', 'd5': 'p', 'e5': 'P', 'e8': 'k'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False)]]
for label, args, expected in fixtures[N-1]:
    try:
        actual = solve(args)
    except Exception as exc:
        actual = 'error:' + type(exc).__name__
    check(label, actual, 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
plain epTrueTruePassed
black epTrueTruePassed
rank pin both pawnsFalseFalsePassed
rank pin black sideFalseFalsePassed
bishop diagonal after epTrueTruePassed
no ep squareFalseFalsePassed
bishop on the rankFalseTrueFailed
rook on the diagonalFalseTrueFailed

SHA-256 / dbcec8dc16bf9a4b2552b87eede9c819f013f7d98a813d6d210ac058e37cc7a7

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(x):
    b=dict(x['board']); fr,to=x['move']; p=b.get(fr)
    if p not in ('P','p') or to!=x['ep']: return False
    white=p=='P'
    d=1 if white else -1
    f0,r0=ord(fr[0])-97,int(fr[1])-1
    f1,r1=ord(to[0])-97,int(to[1])-1
    if r1-r0!=d or abs(f1-f0)!=1: return False
    if r0!=(4 if white else 3): return False
    victim=to[0]+fr[1]
    if b.get(victim)!=('p' if white else 'P'): return False
    del b[fr]; del b[victim]; b[to]=p
    ks=[s for s,v in b.items() if v==('K' if white else 'k')][0]
    kf,kr=ord(ks[0])-97,int(ks[1])-1
    for df,dr in ((1,0),(-1,0),(0,1),(0,-1),(1,1),(1,-1),(-1,1),(-1,-1)):
        cf,cr=kf+df,kr+dr
        while 0<=cf<8 and 0<=cr<8:
            v=b.get(chr(97+cf)+str(cr+1))
            if v:
                if v.isupper()!=white and v.lower() in (('r','q') if df==0 else ('b','q')): return False
                break
            cf+=df; cr+=dr
    return True
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('plain ep',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'd6', 'move': ['e5', 'd6']},
   True),
  ('black ep',
   {'board': {'d4': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'ep': 'e3', 'move': ['d4', 'e3']},
   True),
  ('rank pin both pawns',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False),
  ('rank pin black side',
   {'board': {'a4': 'Q', 'd4': 'p', 'e1': 'K', 'e4': 'P', 'h4': 'k'},
    'ep': 'e3',
    'move': ['d4', 'e3']},
   False),
  ('bishop diagonal after ep',
   {'board': {'c3': 'K', 'e5': 'P', 'e8': 'k', 'f5': 'p', 'f6': 'n', 'h8': 'b'},
    'ep': 'f6',
    'move': ['e5', 'f6']},
   True),
  ('no ep square',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': None, 'move': ['e5', 'd6']},
   False),
  ('bishop on the rank',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'b'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on the diagonal',
   {'board': {'c3': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'g7': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True)],
 [('bishop diagonal after ep',
   {'board': {'c3': 'K', 'e5': 'P', 'e8': 'k', 'f5': 'p', 'f6': 'n', 'h8': 'b'},
    'ep': 'f6',
    'move': ['e5', 'f6']},
   True),
  ('no ep square',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': None, 'move': ['e5', 'd6']},
   False),
  ('wrong target',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k', 'f5': 'p'},
    'ep': 'd6',
    'move': ['e5', 'f6']},
   False),
  ('wrong rank for white',
   {'board': {'d4': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'ep': 'd5', 'move': ['e4', 'd5']},
   False),
  ('black wrong rank',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'e4', 'move': ['d5', 'e4']},
   False),
  ('bishop on the rank',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'b'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on the diagonal',
   {'board': {'c3': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'g7': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on file of ep square',
   {'board': {'a1': 'K', 'd1': 'r', 'd5': 'p', 'e5': 'P', 'e8': 'k'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False)],
 [('rank pin both pawns',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False),
  ('wrong rank for white',
   {'board': {'d4': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'ep': 'd5', 'move': ['e4', 'd5']},
   False),
  ('black wrong rank',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'e4', 'move': ['d5', 'e4']},
   False),
  ('file rook behind pawn',
   {'board': {'d1': 'K', 'd5': 'p', 'd8': 'r', 'e5': 'P', 'e8': 'k'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('same file ep target',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'd3', 'move': ['e5', 'd6']},
   False),
  ('bishop on the rank',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'b'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on the diagonal',
   {'board': {'c3': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'g7': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on file of ep square',
   {'board': {'a1': 'K', 'd1': 'r', 'd5': 'p', 'e5': 'P', 'e8': 'k'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False)],
 [('plain ep',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'd6', 'move': ['e5', 'd6']},
   True),
  ('black ep',
   {'board': {'d4': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'ep': 'e3', 'move': ['d4', 'e3']},
   True),
  ('rank pin both pawns',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False),
  ('same file ep target',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'd3', 'move': ['e5', 'd6']},
   False),
  ('pin by own rook harmless',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'R'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('bishop on the rank',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'b'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on the diagonal',
   {'board': {'c3': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'g7': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on file of ep square',
   {'board': {'a1': 'K', 'd1': 'r', 'd5': 'p', 'e5': 'P', 'e8': 'k'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False)],
 [('plain ep',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'd6', 'move': ['e5', 'd6']},
   True),
  ('black ep',
   {'board': {'d4': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'ep': 'e3', 'move': ['d4', 'e3']},
   True),
  ('rank pin black side',
   {'board': {'a4': 'Q', 'd4': 'p', 'e1': 'K', 'e4': 'P', 'h4': 'k'},
    'ep': 'e3',
    'move': ['d4', 'e3']},
   False),
  ('bishop diagonal after ep',
   {'board': {'c3': 'K', 'e5': 'P', 'e8': 'k', 'f5': 'p', 'f6': 'n', 'h8': 'b'},
    'ep': 'f6',
    'move': ['e5', 'f6']},
   True),
  ('no ep square',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': None, 'move': ['e5', 'd6']},
   False),
  ('bishop on the rank',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'b'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on the diagonal',
   {'board': {'c3': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'g7': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on file of ep square',
   {'board': {'a1': 'K', 'd1': 'r', 'd5': 'p', 'e5': 'P', 'e8': 'k'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False)]]
for label, args, expected in fixtures[N-1]:
    try:
        actual = solve(args)
    except Exception as exc:
        actual = 'error:' + type(exc).__name__
    check(label, actual, 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
plain epTrueTruePassed
black epTrueTruePassed
rank pin both pawnsTrueFalseFailed
rank pin black sideFalseFalsePassed
bishop diagonal after epTrueTruePassed
no ep squareFalseFalsePassed
bishop on the rankFalseTrueFailed
rook on the diagonalTrueTruePassed

SHA-256 / 4484aeb4b6db33d01f587587571f9d300f1e4c28384347a673ff29a8ee6a0f5c

3 / The verified repair

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

N = 1
observations = []
def solve(x):
    b=dict(x['board']); fr,to=x['move']; p=b.get(fr)
    if p not in ('P','p') or to!=x['ep']: return False
    white=p=='P'
    d=1 if white else -1
    f0,r0=ord(fr[0])-97,int(fr[1])-1
    f1,r1=ord(to[0])-97,int(to[1])-1
    if r1-r0!=d or abs(f1-f0)!=1: return False
    if r0!=(4 if white else 3): return False
    victim=to[0]+fr[1]
    if b.get(victim)!=('p' if white else 'P'): return False
    del b[fr]; del b[victim]; b[to]=p
    ks=[s for s,v in b.items() if v==('K' if white else 'k')][0]
    kf,kr=ord(ks[0])-97,int(ks[1])-1
    for df,dr in ((1,0),(-1,0),(0,1),(0,-1),(1,1),(1,-1),(-1,1),(-1,-1)):
        cf,cr=kf+df,kr+dr
        while 0<=cf<8 and 0<=cr<8:
            v=b.get(chr(97+cf)+str(cr+1))
            if v:
                if v.isupper()!=white and v.lower() in (('r','q') if df==0 or dr==0 else ('b','q')): return False
                break
            cf+=df; cr+=dr
    return True
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('plain ep',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'd6', 'move': ['e5', 'd6']},
   True),
  ('black ep',
   {'board': {'d4': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'ep': 'e3', 'move': ['d4', 'e3']},
   True),
  ('rank pin both pawns',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False),
  ('rank pin black side',
   {'board': {'a4': 'Q', 'd4': 'p', 'e1': 'K', 'e4': 'P', 'h4': 'k'},
    'ep': 'e3',
    'move': ['d4', 'e3']},
   False),
  ('bishop diagonal after ep',
   {'board': {'c3': 'K', 'e5': 'P', 'e8': 'k', 'f5': 'p', 'f6': 'n', 'h8': 'b'},
    'ep': 'f6',
    'move': ['e5', 'f6']},
   True),
  ('no ep square',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': None, 'move': ['e5', 'd6']},
   False),
  ('bishop on the rank',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'b'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on the diagonal',
   {'board': {'c3': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'g7': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True)],
 [('bishop diagonal after ep',
   {'board': {'c3': 'K', 'e5': 'P', 'e8': 'k', 'f5': 'p', 'f6': 'n', 'h8': 'b'},
    'ep': 'f6',
    'move': ['e5', 'f6']},
   True),
  ('no ep square',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': None, 'move': ['e5', 'd6']},
   False),
  ('wrong target',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k', 'f5': 'p'},
    'ep': 'd6',
    'move': ['e5', 'f6']},
   False),
  ('wrong rank for white',
   {'board': {'d4': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'ep': 'd5', 'move': ['e4', 'd5']},
   False),
  ('black wrong rank',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'e4', 'move': ['d5', 'e4']},
   False),
  ('bishop on the rank',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'b'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on the diagonal',
   {'board': {'c3': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'g7': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on file of ep square',
   {'board': {'a1': 'K', 'd1': 'r', 'd5': 'p', 'e5': 'P', 'e8': 'k'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False)],
 [('rank pin both pawns',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False),
  ('wrong rank for white',
   {'board': {'d4': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'ep': 'd5', 'move': ['e4', 'd5']},
   False),
  ('black wrong rank',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'e4', 'move': ['d5', 'e4']},
   False),
  ('file rook behind pawn',
   {'board': {'d1': 'K', 'd5': 'p', 'd8': 'r', 'e5': 'P', 'e8': 'k'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('same file ep target',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'd3', 'move': ['e5', 'd6']},
   False),
  ('bishop on the rank',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'b'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on the diagonal',
   {'board': {'c3': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'g7': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on file of ep square',
   {'board': {'a1': 'K', 'd1': 'r', 'd5': 'p', 'e5': 'P', 'e8': 'k'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False)],
 [('plain ep',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'd6', 'move': ['e5', 'd6']},
   True),
  ('black ep',
   {'board': {'d4': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'ep': 'e3', 'move': ['d4', 'e3']},
   True),
  ('rank pin both pawns',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False),
  ('same file ep target',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'd3', 'move': ['e5', 'd6']},
   False),
  ('pin by own rook harmless',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'R'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('bishop on the rank',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'b'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on the diagonal',
   {'board': {'c3': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'g7': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on file of ep square',
   {'board': {'a1': 'K', 'd1': 'r', 'd5': 'p', 'e5': 'P', 'e8': 'k'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False)],
 [('plain ep',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': 'd6', 'move': ['e5', 'd6']},
   True),
  ('black ep',
   {'board': {'d4': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'ep': 'e3', 'move': ['d4', 'e3']},
   True),
  ('rank pin black side',
   {'board': {'a4': 'Q', 'd4': 'p', 'e1': 'K', 'e4': 'P', 'h4': 'k'},
    'ep': 'e3',
    'move': ['d4', 'e3']},
   False),
  ('bishop diagonal after ep',
   {'board': {'c3': 'K', 'e5': 'P', 'e8': 'k', 'f5': 'p', 'f6': 'n', 'h8': 'b'},
    'ep': 'f6',
    'move': ['e5', 'f6']},
   True),
  ('no ep square',
   {'board': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'ep': None, 'move': ['e5', 'd6']},
   False),
  ('bishop on the rank',
   {'board': {'a5': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'h5': 'b'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on the diagonal',
   {'board': {'c3': 'K', 'd5': 'p', 'e5': 'P', 'e8': 'k', 'g7': 'r'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   True),
  ('rook on file of ep square',
   {'board': {'a1': 'K', 'd1': 'r', 'd5': 'p', 'e5': 'P', 'e8': 'k'},
    'ep': 'd6',
    'move': ['e5', 'd6']},
   False)]]
for label, args, expected in fixtures[N-1]:
    try:
        actual = solve(args)
    except Exception as exc:
        actual = 'error:' + type(exc).__name__
    check(label, actual, 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
plain epTrueTruePassed
black epTrueTruePassed
rank pin both pawnsFalseFalsePassed
rank pin black sideFalseFalsePassed
bishop diagonal after epTrueTruePassed
no ep squareFalseFalsePassed
bishop on the rankTrueTruePassed
rook on the diagonalTrueTruePassed

SHA-256 / ec7ace705e82b3e7ba71d563cbf54dfb3b5adf89fa51312a1cffeda803295d05

Verification & scope

A deterministic toy model with an explicitly stated contract; boards are {square: piece} with white upper-case and black lower-case pieces; no claim of full FIDE Laws conformance. 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:12.096336+00:00.

Case digest / 71c89ac05bda2968b2dfc573be8e0afd046d321e78a7c422e4f1a56bba712890