FAILURE MAP
← Case archive

FA-82441 / Chess move legality / Open access

Queenside castling forbidden when b1 is attacked · case 01

A rook attacking b1 prevents white from castling long.

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

ROOT CAUSE

The attack test includes b1, a square only the rook crosses.

VERIFIED REPAIR

Only the king's start, transit and destination squares must be unattacked.

Unsuccessful approach: Dropping the e-file square allows castling out of check.

Case contract

Input: {"board", "side": "w" or "b", "wing": "K" or "Q", "rights": subset of "KQkq"}. Standard castling is legal when the right is held, the king is on e1/e8 and the matching own rook on h- or a-file, the squares between them are empty (f,g or b,c,d), and none of the king's squares e, f, g (kingside) or e, d, c (queenside) is attacked by the opponent.

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):
    def attacked(bd, sq, by_white):
        f,r=ord(sq[0])-97,int(sq[1])-1
        def at(ff,rr):
            return bd.get(chr(97+ff)+str(rr+1)) if 0<=ff<8 and 0<=rr<8 else None
        P,N,B,R,Q,K=('PNBRQK' if by_white else 'pnbrqk')
        pr=r-1 if by_white else r+1
        if at(f-1,pr)==P or at(f+1,pr)==P: return True
        for df,dr in ((1,2),(2,1),(-1,2),(-2,1),(1,-2),(2,-1),(-1,-2),(-2,-1)):
            if at(f+df,r+dr)==N: return True
        for df in (-1,0,1):
            for dr in (-1,0,1):
                if (df or dr) and at(f+df,r+dr)==K: return True
        for df,dr,kinds in ((1,0,(R,Q)),(-1,0,(R,Q)),(0,1,(R,Q)),(0,-1,(R,Q)),(1,1,(B,Q)),(1,-1,(B,Q)),(-1,1,(B,Q)),(-1,-1,(B,Q))):
            ff,rr=f+df,r+dr
            while 0<=ff<8 and 0<=rr<8:
                v=at(ff,rr)
                if v:
                    if v in kinds: return True
                    break
                ff+=df; rr+=dr
        return False
    
    b=x['board']; white=x['side']=='w'; wing=x['wing']
    rank='1' if white else '8'
    right=wing if white else wing.lower()
    if right not in x['rights']: return False
    if b.get('e'+rank)!=('K' if white else 'k'): return False
    rook_sq=('h' if wing=='K' else 'a')+rank
    if b.get(rook_sq)!=('R' if white else 'r'): return False
    between='fg' if wing=='K' else 'bcd'
    if any(f+rank in b for f in between): return False
    path='efg' if wing=='K' else 'edcb'
    return not any(attacked(b, f+rank, not white) for f in path)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('white kingside clear',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'R'}, 'rights': 'KQkq', 'side': 'w', 'wing': 'K'}, True),
  ('queenside b-file blocked',
   {'board': {'a1': 'R', 'b1': 'N', 'e1': 'K', 'e8': 'k'},
    'rights': 'KQ',
    'side': 'w',
    'wing': 'Q'},
   False),
  ('queenside b-file attacked',
   {'board': {'a1': 'R', 'b8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   True),
  ('in check',
   {'board': {'a8': 'k', 'e1': 'K', 'e8': 'r', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('f1 attacked',
   {'board': {'c4': 'b', 'e1': 'K', 'e8': 'k', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('black uses own right',
   {'board': {'e1': 'K', 'e8': 'k', 'h8': 'r'}, 'rights': 'K', 'side': 'b', 'wing': 'K'}, False),
  ('black has right',
   {'board': {'a8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'q', 'side': 'b', 'wing': 'Q'}, True),
  ('enemy rook in corner',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'r'}, 'rights': 'K', 'side': 'w', 'wing': 'K'}, False)],
 [('queenside b-file attacked',
   {'board': {'a1': 'R', 'b8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   True),
  ('in check',
   {'board': {'a8': 'k', 'e1': 'K', 'e8': 'r', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('black uses own right',
   {'board': {'e1': 'K', 'e8': 'k', 'h8': 'r'}, 'rights': 'K', 'side': 'b', 'wing': 'K'}, False),
  ('black has right',
   {'board': {'a8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'q', 'side': 'b', 'wing': 'Q'}, True),
  ('enemy rook in corner',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'r'}, 'rights': 'K', 'side': 'w', 'wing': 'K'}, False),
  ('knight in rook corner',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'N'}, 'rights': 'K', 'side': 'w', 'wing': 'K'}, False),
  ('pawn attacks g1 from h2',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'R', 'h2': 'p'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('white pawn on f2 harmless',
   {'board': {'e1': 'K', 'e8': 'k', 'g2': 'P', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   True)],
 [('queenside b-file attacked',
   {'board': {'a1': 'R', 'b8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   True),
  ('in check',
   {'board': {'a8': 'k', 'e1': 'K', 'e8': 'r', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('knight in rook corner',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'N'}, 'rights': 'K', 'side': 'w', 'wing': 'K'}, False),
  ('pawn attacks g1 from h2',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'R', 'h2': 'p'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('white pawn on f2 harmless',
   {'board': {'e1': 'K', 'e8': 'k', 'g2': 'P', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   True),
  ('black pawn attacks f8 check',
   {'board': {'e1': 'K', 'e7': 'P', 'e8': 'k', 'h8': 'r'}, 'rights': 'k', 'side': 'b', 'wing': 'K'},
   False),
  ('shielded rook attack',
   {'board': {'a8': 'k', 'e1': 'K', 'f4': 'P', 'f8': 'r', 'h1': 'R'},
    'rights': 'K',
    'side': 'w',
    'wing': 'K'},
   True),
  ('own piece shields g1',
   {'board': {'a8': 'k', 'e1': 'K', 'g3': 'N', 'g5': 'q', 'h1': 'R'},
    'rights': 'K',
    'side': 'w',
    'wing': 'K'},
   True)],
 [('white kingside clear',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'R'}, 'rights': 'KQkq', 'side': 'w', 'wing': 'K'}, True),
  ('queenside b-file attacked',
   {'board': {'a1': 'R', 'b8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   True),
  ('in check',
   {'board': {'a8': 'k', 'e1': 'K', 'e8': 'r', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('black pawn attacks f8 check',
   {'board': {'e1': 'K', 'e7': 'P', 'e8': 'k', 'h8': 'r'}, 'rights': 'k', 'side': 'b', 'wing': 'K'},
   False),
  ('shielded rook attack',
   {'board': {'a8': 'k', 'e1': 'K', 'f4': 'P', 'f8': 'r', 'h1': 'R'},
    'rights': 'K',
    'side': 'w',
    'wing': 'K'},
   True),
  ('own piece shields g1',
   {'board': {'a8': 'k', 'e1': 'K', 'g3': 'N', 'g5': 'q', 'h1': 'R'},
    'rights': 'K',
    'side': 'w',
    'wing': 'K'},
   True),
  ('c1 attacked',
   {'board': {'a1': 'R', 'e1': 'K', 'e8': 'k', 'h6': 'b'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   False),
  ('d1 blocked',
   {'board': {'a1': 'R', 'd1': 'Q', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   False)],
 [('white kingside clear',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'R'}, 'rights': 'KQkq', 'side': 'w', 'wing': 'K'}, True),
  ('queenside b-file blocked',
   {'board': {'a1': 'R', 'b1': 'N', 'e1': 'K', 'e8': 'k'},
    'rights': 'KQ',
    'side': 'w',
    'wing': 'Q'},
   False),
  ('queenside b-file attacked',
   {'board': {'a1': 'R', 'b8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   True),
  ('in check',
   {'board': {'a8': 'k', 'e1': 'K', 'e8': 'r', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('f1 attacked',
   {'board': {'c4': 'b', 'e1': 'K', 'e8': 'k', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('black uses own right',
   {'board': {'e1': 'K', 'e8': 'k', 'h8': 'r'}, 'rights': 'K', 'side': 'b', 'wing': 'K'}, False),
  ('c1 attacked',
   {'board': {'a1': 'R', 'e1': 'K', 'e8': 'k', 'h6': 'b'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   False),
  ('d1 blocked',
   {'board': {'a1': 'R', 'd1': 'Q', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   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
white kingside clearTrueTruePassed
queenside b-file blockedFalseFalsePassed
queenside b-file attackedFalseTrueFailed
in checkFalseFalsePassed
f1 attackedFalseFalsePassed
black uses own rightFalseFalsePassed
black has rightTrueTruePassed
enemy rook in cornerFalseFalsePassed

SHA-256 / 124da6bc41355b197496fcabaaf2cbcb58780d1e85c15c4aead920ff41538206

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(x):
    def attacked(bd, sq, by_white):
        f,r=ord(sq[0])-97,int(sq[1])-1
        def at(ff,rr):
            return bd.get(chr(97+ff)+str(rr+1)) if 0<=ff<8 and 0<=rr<8 else None
        P,N,B,R,Q,K=('PNBRQK' if by_white else 'pnbrqk')
        pr=r-1 if by_white else r+1
        if at(f-1,pr)==P or at(f+1,pr)==P: return True
        for df,dr in ((1,2),(2,1),(-1,2),(-2,1),(1,-2),(2,-1),(-1,-2),(-2,-1)):
            if at(f+df,r+dr)==N: return True
        for df in (-1,0,1):
            for dr in (-1,0,1):
                if (df or dr) and at(f+df,r+dr)==K: return True
        for df,dr,kinds in ((1,0,(R,Q)),(-1,0,(R,Q)),(0,1,(R,Q)),(0,-1,(R,Q)),(1,1,(B,Q)),(1,-1,(B,Q)),(-1,1,(B,Q)),(-1,-1,(B,Q))):
            ff,rr=f+df,r+dr
            while 0<=ff<8 and 0<=rr<8:
                v=at(ff,rr)
                if v:
                    if v in kinds: return True
                    break
                ff+=df; rr+=dr
        return False
    
    b=x['board']; white=x['side']=='w'; wing=x['wing']
    rank='1' if white else '8'
    right=wing if white else wing.lower()
    if right not in x['rights']: return False
    if b.get('e'+rank)!=('K' if white else 'k'): return False
    rook_sq=('h' if wing=='K' else 'a')+rank
    if b.get(rook_sq)!=('R' if white else 'r'): return False
    between='fg' if wing=='K' else 'bcd'
    if any(f+rank in b for f in between): return False
    path='fg' if wing=='K' else 'dc'
    return not any(attacked(b, f+rank, not white) for f in path)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('white kingside clear',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'R'}, 'rights': 'KQkq', 'side': 'w', 'wing': 'K'}, True),
  ('queenside b-file blocked',
   {'board': {'a1': 'R', 'b1': 'N', 'e1': 'K', 'e8': 'k'},
    'rights': 'KQ',
    'side': 'w',
    'wing': 'Q'},
   False),
  ('queenside b-file attacked',
   {'board': {'a1': 'R', 'b8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   True),
  ('in check',
   {'board': {'a8': 'k', 'e1': 'K', 'e8': 'r', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('f1 attacked',
   {'board': {'c4': 'b', 'e1': 'K', 'e8': 'k', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('black uses own right',
   {'board': {'e1': 'K', 'e8': 'k', 'h8': 'r'}, 'rights': 'K', 'side': 'b', 'wing': 'K'}, False),
  ('black has right',
   {'board': {'a8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'q', 'side': 'b', 'wing': 'Q'}, True),
  ('enemy rook in corner',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'r'}, 'rights': 'K', 'side': 'w', 'wing': 'K'}, False)],
 [('queenside b-file attacked',
   {'board': {'a1': 'R', 'b8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   True),
  ('in check',
   {'board': {'a8': 'k', 'e1': 'K', 'e8': 'r', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('black uses own right',
   {'board': {'e1': 'K', 'e8': 'k', 'h8': 'r'}, 'rights': 'K', 'side': 'b', 'wing': 'K'}, False),
  ('black has right',
   {'board': {'a8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'q', 'side': 'b', 'wing': 'Q'}, True),
  ('enemy rook in corner',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'r'}, 'rights': 'K', 'side': 'w', 'wing': 'K'}, False),
  ('knight in rook corner',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'N'}, 'rights': 'K', 'side': 'w', 'wing': 'K'}, False),
  ('pawn attacks g1 from h2',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'R', 'h2': 'p'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('white pawn on f2 harmless',
   {'board': {'e1': 'K', 'e8': 'k', 'g2': 'P', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   True)],
 [('queenside b-file attacked',
   {'board': {'a1': 'R', 'b8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   True),
  ('in check',
   {'board': {'a8': 'k', 'e1': 'K', 'e8': 'r', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('knight in rook corner',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'N'}, 'rights': 'K', 'side': 'w', 'wing': 'K'}, False),
  ('pawn attacks g1 from h2',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'R', 'h2': 'p'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('white pawn on f2 harmless',
   {'board': {'e1': 'K', 'e8': 'k', 'g2': 'P', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   True),
  ('black pawn attacks f8 check',
   {'board': {'e1': 'K', 'e7': 'P', 'e8': 'k', 'h8': 'r'}, 'rights': 'k', 'side': 'b', 'wing': 'K'},
   False),
  ('shielded rook attack',
   {'board': {'a8': 'k', 'e1': 'K', 'f4': 'P', 'f8': 'r', 'h1': 'R'},
    'rights': 'K',
    'side': 'w',
    'wing': 'K'},
   True),
  ('own piece shields g1',
   {'board': {'a8': 'k', 'e1': 'K', 'g3': 'N', 'g5': 'q', 'h1': 'R'},
    'rights': 'K',
    'side': 'w',
    'wing': 'K'},
   True)],
 [('white kingside clear',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'R'}, 'rights': 'KQkq', 'side': 'w', 'wing': 'K'}, True),
  ('queenside b-file attacked',
   {'board': {'a1': 'R', 'b8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   True),
  ('in check',
   {'board': {'a8': 'k', 'e1': 'K', 'e8': 'r', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('black pawn attacks f8 check',
   {'board': {'e1': 'K', 'e7': 'P', 'e8': 'k', 'h8': 'r'}, 'rights': 'k', 'side': 'b', 'wing': 'K'},
   False),
  ('shielded rook attack',
   {'board': {'a8': 'k', 'e1': 'K', 'f4': 'P', 'f8': 'r', 'h1': 'R'},
    'rights': 'K',
    'side': 'w',
    'wing': 'K'},
   True),
  ('own piece shields g1',
   {'board': {'a8': 'k', 'e1': 'K', 'g3': 'N', 'g5': 'q', 'h1': 'R'},
    'rights': 'K',
    'side': 'w',
    'wing': 'K'},
   True),
  ('c1 attacked',
   {'board': {'a1': 'R', 'e1': 'K', 'e8': 'k', 'h6': 'b'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   False),
  ('d1 blocked',
   {'board': {'a1': 'R', 'd1': 'Q', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   False)],
 [('white kingside clear',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'R'}, 'rights': 'KQkq', 'side': 'w', 'wing': 'K'}, True),
  ('queenside b-file blocked',
   {'board': {'a1': 'R', 'b1': 'N', 'e1': 'K', 'e8': 'k'},
    'rights': 'KQ',
    'side': 'w',
    'wing': 'Q'},
   False),
  ('queenside b-file attacked',
   {'board': {'a1': 'R', 'b8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   True),
  ('in check',
   {'board': {'a8': 'k', 'e1': 'K', 'e8': 'r', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('f1 attacked',
   {'board': {'c4': 'b', 'e1': 'K', 'e8': 'k', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('black uses own right',
   {'board': {'e1': 'K', 'e8': 'k', 'h8': 'r'}, 'rights': 'K', 'side': 'b', 'wing': 'K'}, False),
  ('c1 attacked',
   {'board': {'a1': 'R', 'e1': 'K', 'e8': 'k', 'h6': 'b'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   False),
  ('d1 blocked',
   {'board': {'a1': 'R', 'd1': 'Q', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   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
white kingside clearTrueTruePassed
queenside b-file blockedFalseFalsePassed
queenside b-file attackedTrueTruePassed
in checkTrueFalseFailed
f1 attackedFalseFalsePassed
black uses own rightFalseFalsePassed
black has rightTrueTruePassed
enemy rook in cornerFalseFalsePassed

SHA-256 / b23701bf5e629fb374ca8055b5c06602f716d4a3a3148eca64bfaa37773e0295

3 / The verified repair

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

N = 1
observations = []
def solve(x):
    def attacked(bd, sq, by_white):
        f,r=ord(sq[0])-97,int(sq[1])-1
        def at(ff,rr):
            return bd.get(chr(97+ff)+str(rr+1)) if 0<=ff<8 and 0<=rr<8 else None
        P,N,B,R,Q,K=('PNBRQK' if by_white else 'pnbrqk')
        pr=r-1 if by_white else r+1
        if at(f-1,pr)==P or at(f+1,pr)==P: return True
        for df,dr in ((1,2),(2,1),(-1,2),(-2,1),(1,-2),(2,-1),(-1,-2),(-2,-1)):
            if at(f+df,r+dr)==N: return True
        for df in (-1,0,1):
            for dr in (-1,0,1):
                if (df or dr) and at(f+df,r+dr)==K: return True
        for df,dr,kinds in ((1,0,(R,Q)),(-1,0,(R,Q)),(0,1,(R,Q)),(0,-1,(R,Q)),(1,1,(B,Q)),(1,-1,(B,Q)),(-1,1,(B,Q)),(-1,-1,(B,Q))):
            ff,rr=f+df,r+dr
            while 0<=ff<8 and 0<=rr<8:
                v=at(ff,rr)
                if v:
                    if v in kinds: return True
                    break
                ff+=df; rr+=dr
        return False
    
    b=x['board']; white=x['side']=='w'; wing=x['wing']
    rank='1' if white else '8'
    right=wing if white else wing.lower()
    if right not in x['rights']: return False
    if b.get('e'+rank)!=('K' if white else 'k'): return False
    rook_sq=('h' if wing=='K' else 'a')+rank
    if b.get(rook_sq)!=('R' if white else 'r'): return False
    between='fg' if wing=='K' else 'bcd'
    if any(f+rank in b for f in between): return False
    path='efg' if wing=='K' else 'edc'
    return not any(attacked(b, f+rank, not white) for f in path)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('white kingside clear',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'R'}, 'rights': 'KQkq', 'side': 'w', 'wing': 'K'}, True),
  ('queenside b-file blocked',
   {'board': {'a1': 'R', 'b1': 'N', 'e1': 'K', 'e8': 'k'},
    'rights': 'KQ',
    'side': 'w',
    'wing': 'Q'},
   False),
  ('queenside b-file attacked',
   {'board': {'a1': 'R', 'b8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   True),
  ('in check',
   {'board': {'a8': 'k', 'e1': 'K', 'e8': 'r', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('f1 attacked',
   {'board': {'c4': 'b', 'e1': 'K', 'e8': 'k', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('black uses own right',
   {'board': {'e1': 'K', 'e8': 'k', 'h8': 'r'}, 'rights': 'K', 'side': 'b', 'wing': 'K'}, False),
  ('black has right',
   {'board': {'a8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'q', 'side': 'b', 'wing': 'Q'}, True),
  ('enemy rook in corner',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'r'}, 'rights': 'K', 'side': 'w', 'wing': 'K'}, False)],
 [('queenside b-file attacked',
   {'board': {'a1': 'R', 'b8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   True),
  ('in check',
   {'board': {'a8': 'k', 'e1': 'K', 'e8': 'r', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('black uses own right',
   {'board': {'e1': 'K', 'e8': 'k', 'h8': 'r'}, 'rights': 'K', 'side': 'b', 'wing': 'K'}, False),
  ('black has right',
   {'board': {'a8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'q', 'side': 'b', 'wing': 'Q'}, True),
  ('enemy rook in corner',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'r'}, 'rights': 'K', 'side': 'w', 'wing': 'K'}, False),
  ('knight in rook corner',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'N'}, 'rights': 'K', 'side': 'w', 'wing': 'K'}, False),
  ('pawn attacks g1 from h2',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'R', 'h2': 'p'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('white pawn on f2 harmless',
   {'board': {'e1': 'K', 'e8': 'k', 'g2': 'P', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   True)],
 [('queenside b-file attacked',
   {'board': {'a1': 'R', 'b8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   True),
  ('in check',
   {'board': {'a8': 'k', 'e1': 'K', 'e8': 'r', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('knight in rook corner',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'N'}, 'rights': 'K', 'side': 'w', 'wing': 'K'}, False),
  ('pawn attacks g1 from h2',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'R', 'h2': 'p'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('white pawn on f2 harmless',
   {'board': {'e1': 'K', 'e8': 'k', 'g2': 'P', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   True),
  ('black pawn attacks f8 check',
   {'board': {'e1': 'K', 'e7': 'P', 'e8': 'k', 'h8': 'r'}, 'rights': 'k', 'side': 'b', 'wing': 'K'},
   False),
  ('shielded rook attack',
   {'board': {'a8': 'k', 'e1': 'K', 'f4': 'P', 'f8': 'r', 'h1': 'R'},
    'rights': 'K',
    'side': 'w',
    'wing': 'K'},
   True),
  ('own piece shields g1',
   {'board': {'a8': 'k', 'e1': 'K', 'g3': 'N', 'g5': 'q', 'h1': 'R'},
    'rights': 'K',
    'side': 'w',
    'wing': 'K'},
   True)],
 [('white kingside clear',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'R'}, 'rights': 'KQkq', 'side': 'w', 'wing': 'K'}, True),
  ('queenside b-file attacked',
   {'board': {'a1': 'R', 'b8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   True),
  ('in check',
   {'board': {'a8': 'k', 'e1': 'K', 'e8': 'r', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('black pawn attacks f8 check',
   {'board': {'e1': 'K', 'e7': 'P', 'e8': 'k', 'h8': 'r'}, 'rights': 'k', 'side': 'b', 'wing': 'K'},
   False),
  ('shielded rook attack',
   {'board': {'a8': 'k', 'e1': 'K', 'f4': 'P', 'f8': 'r', 'h1': 'R'},
    'rights': 'K',
    'side': 'w',
    'wing': 'K'},
   True),
  ('own piece shields g1',
   {'board': {'a8': 'k', 'e1': 'K', 'g3': 'N', 'g5': 'q', 'h1': 'R'},
    'rights': 'K',
    'side': 'w',
    'wing': 'K'},
   True),
  ('c1 attacked',
   {'board': {'a1': 'R', 'e1': 'K', 'e8': 'k', 'h6': 'b'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   False),
  ('d1 blocked',
   {'board': {'a1': 'R', 'd1': 'Q', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   False)],
 [('white kingside clear',
   {'board': {'e1': 'K', 'e8': 'k', 'h1': 'R'}, 'rights': 'KQkq', 'side': 'w', 'wing': 'K'}, True),
  ('queenside b-file blocked',
   {'board': {'a1': 'R', 'b1': 'N', 'e1': 'K', 'e8': 'k'},
    'rights': 'KQ',
    'side': 'w',
    'wing': 'Q'},
   False),
  ('queenside b-file attacked',
   {'board': {'a1': 'R', 'b8': 'r', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   True),
  ('in check',
   {'board': {'a8': 'k', 'e1': 'K', 'e8': 'r', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('f1 attacked',
   {'board': {'c4': 'b', 'e1': 'K', 'e8': 'k', 'h1': 'R'}, 'rights': 'K', 'side': 'w', 'wing': 'K'},
   False),
  ('black uses own right',
   {'board': {'e1': 'K', 'e8': 'k', 'h8': 'r'}, 'rights': 'K', 'side': 'b', 'wing': 'K'}, False),
  ('c1 attacked',
   {'board': {'a1': 'R', 'e1': 'K', 'e8': 'k', 'h6': 'b'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   False),
  ('d1 blocked',
   {'board': {'a1': 'R', 'd1': 'Q', 'e1': 'K', 'e8': 'k'}, 'rights': 'Q', 'side': 'w', 'wing': 'Q'},
   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
white kingside clearTrueTruePassed
queenside b-file blockedFalseFalsePassed
queenside b-file attackedTrueTruePassed
in checkFalseFalsePassed
f1 attackedFalseFalsePassed
black uses own rightFalseFalsePassed
black has rightTrueTruePassed
enemy rook in cornerFalseFalsePassed

SHA-256 / d22ba5f36b82ed3d0eebd867b977bb76834bf8f67cdf65d4c725a5909337e52d

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

Case digest / e816d0d60b1b7ee587b2d1bcce7e71741153e700ba8e2da12c8bc2685592cb90