FAILURE MAP
← Case archive

FA-82551 / Chess move legality / Open access

Positions without castling rights rejected · case 01

Every FEN with "-" in the castling field is reported invalid.

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

ROOT CAUSE

The "-" placeholder is validated as if it were a castling letter.

VERIFIED REPAIR

Map "-" to the empty rights string before validating letters.

Unsuccessful approach: Upper-casing the field turns black's kq rights into white's KQ.

Case contract

Input: a FEN string. Return {"pieces": {square: piece}, "turn", "castling", "ep", "halfmove", "fullmove"} or "invalid". Placement lists rank 8 first; digits skip empty squares; each rank must total 8; exactly one king per side. Turn is w or b; castling is "-" or letters from KQkq (returned as "" when "-"); ep is "-" (null) or a square on rank 6 when white is to move, rank 3 when black is; halfmove is a non-negative integer and fullmove at least 1.

Why this case matters

Every position-based legality check starts from a parsed FEN; a misparse silently changes which moves are legal.

1 / The failure

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

N = 1
observations = []
def solve(x):
    parts=x.split()
    if len(parts)!=6: return 'invalid'
    rows=parts[0].split('/')
    if len(rows)!=8: return 'invalid'
    board={}
    for i,row in enumerate(rows):
        rank=8-i; f=0
        for ch in row:
            if ch.isdigit(): f+=int(ch)
            elif ch in 'pnbrqkPNBRQK':
                if f>7: return 'invalid'
                board[chr(97+f)+str(rank)]=ch; f+=1
            else: return 'invalid'
        if f!=8: return 'invalid'
    vals=list(board.values())
    if vals.count('K')!=1 or vals.count('k')!=1: return 'invalid'
    turn=parts[1]
    if turn not in ('w','b'): return 'invalid'
    cast=parts[2]
    if any(c not in 'KQkq' for c in cast): return 'invalid'
    ep=None if parts[3]=='-' else parts[3]
    if ep is not None and ep[1:]!=('6' if turn=='w' else '3'): return 'invalid'
    if not (parts[4].isdigit() and parts[5].isdigit()) or int(parts[5])<1: return 'invalid'
    return {'pieces':board,'turn':turn,'castling':cast,'ep':ep,'halfmove':int(parts[4]),'fullmove':int(parts[5])}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
   {'castling': 'Q',
    'ep': None,
    'fullmove': 1,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
    'turn': 'w'}),
  ('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
   {'castling': '',
    'ep': 'd3',
    'fullmove': 12,
    'halfmove': 0,
    'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
    'turn': 'b'}),
  ('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
   {'castling': '',
    'ep': 'd6',
    'fullmove': 9,
    'halfmove': 0,
    'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
    'turn': 'w'}),
  ('ep wrong side', '4k3/8/8/3pP3/8/8/8/4K3 w - d3 0 9', 'invalid'),
  ('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
   {'castling': 'kq',
    'ep': None,
    'fullmove': 5,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'w'}),
  ('two white kings', '4k3/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
  ('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
  ('missing black king', '8/8/8/8/8/8/8/4K3 w - - 0 1', 'invalid')],
 [('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
   {'castling': '',
    'ep': 'd6',
    'fullmove': 9,
    'halfmove': 0,
    'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
    'turn': 'w'}),
  ('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
   {'castling': '',
    'ep': None,
    'fullmove': 20,
    'halfmove': 3,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'b'}),
  ('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
   {'castling': 'kq',
    'ep': None,
    'fullmove': 5,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'w'}),
  ('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
  ('missing black king', '8/8/8/8/8/8/8/4K3 w - - 0 1', 'invalid'),
  ('short rank', '4k3/8/8/8/8/8/8/4K2 w - - 0 1', 'invalid'),
  ('fullmove zero', '4k3/8/8/8/8/8/8/4K3 w - - 0 0', 'invalid'),
  ('halfmove dash', '4k3/8/8/8/8/8/8/4K3 w - - - 1', 'invalid')],
 [('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
   {'castling': '',
    'ep': 'd3',
    'fullmove': 12,
    'halfmove': 0,
    'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
    'turn': 'b'}),
  ('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
   {'castling': '',
    'ep': None,
    'fullmove': 20,
    'halfmove': 3,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'b'}),
  ('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
   {'castling': 'kq',
    'ep': None,
    'fullmove': 5,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'w'}),
  ('fullmove zero', '4k3/8/8/8/8/8/8/4K3 w - - 0 0', 'invalid'),
  ('halfmove dash', '4k3/8/8/8/8/8/8/4K3 w - - - 1', 'invalid'),
  ('pawns and knights', 'rn2k3/pp6/8/8/8/8/6PP/4K1NR w K - 7 30',
   {'castling': 'K',
    'ep': None,
    'fullmove': 30,
    'halfmove': 7,
    'pieces': {'a7': 'p',
               'a8': 'r',
               'b7': 'p',
               'b8': 'n',
               'e1': 'K',
               'e8': 'k',
               'g1': 'N',
               'g2': 'P',
               'h1': 'R',
               'h2': 'P'},
    'turn': 'w'}),
  ('bad castling letter', '4k3/8/8/8/8/8/8/4K3 w X - 0 1', 'invalid'),
  ('bad turn', '4k3/8/8/8/8/8/8/4K3 x - - 0 1', 'invalid')],
 [('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
   {'castling': 'Q',
    'ep': None,
    'fullmove': 1,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
    'turn': 'w'}),
  ('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
   {'castling': '',
    'ep': 'd3',
    'fullmove': 12,
    'halfmove': 0,
    'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
    'turn': 'b'}),
  ('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
   {'castling': '',
    'ep': 'd6',
    'fullmove': 9,
    'halfmove': 0,
    'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
    'turn': 'w'}),
  ('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
   {'castling': '',
    'ep': None,
    'fullmove': 20,
    'halfmove': 3,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'b'}),
  ('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
   {'castling': 'kq',
    'ep': None,
    'fullmove': 5,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'w'}),
  ('bad castling letter', '4k3/8/8/8/8/8/8/4K3 w X - 0 1', 'invalid'),
  ('bad turn', '4k3/8/8/8/8/8/8/4K3 x - - 0 1', 'invalid'),
  ('fullmove dash', '4k3/8/8/8/8/8/8/4K3 w - - 0 -', 'invalid')],
 [('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
   {'castling': 'Q',
    'ep': None,
    'fullmove': 1,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
    'turn': 'w'}),
  ('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
   {'castling': '',
    'ep': 'd3',
    'fullmove': 12,
    'halfmove': 0,
    'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
    'turn': 'b'}),
  ('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
   {'castling': '',
    'ep': 'd6',
    'fullmove': 9,
    'halfmove': 0,
    'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
    'turn': 'w'}),
  ('ep wrong side', '4k3/8/8/3pP3/8/8/8/4K3 w - d3 0 9', 'invalid'),
  ('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
   {'castling': '',
    'ep': None,
    'fullmove': 20,
    'halfmove': 3,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'b'}),
  ('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
   {'castling': 'kq',
    'ep': None,
    'fullmove': 5,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'w'}),
  ('two white kings', '4k3/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
  ('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid')]]
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
kings and rook{'castling': 'Q', 'ep': None, 'fullmove': 1, 'halfmove': 0, 'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'}, 'turn': 'w'}{'castling': 'Q', 'ep': None, 'fullmove': 1, 'halfmove': 0, 'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'}, 'turn': 'w'}Passed
black to move epinvalid{'castling': '', 'ep': 'd3', 'fullmove': 12, 'halfmove': 0, 'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'}, 'turn': 'b'}Failed
white ep targetinvalid{'castling': '', 'ep': 'd6', 'fullmove': 9, 'halfmove': 0, 'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'turn': 'w'}Failed
ep wrong sideinvalidinvalidPassed
black rights only{'castling': 'kq', 'ep': None, 'fullmove': 5, 'halfmove': 0, 'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'}, 'turn': 'w'}{'castling': 'kq', 'ep': None, 'fullmove': 5, 'halfmove': 0, 'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'}, 'turn': 'w'}Passed
two white kingsinvalidinvalidPassed
two white kings no blackinvalidinvalidPassed
missing black kinginvalidinvalidPassed

SHA-256 / 00501fc585e3a4b69f7075edd275af80475e4b394efd3d781dcbfb44e96d713b

2 / The unsuccessful fix

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

N = 1
observations = []
def solve(x):
    parts=x.split()
    if len(parts)!=6: return 'invalid'
    rows=parts[0].split('/')
    if len(rows)!=8: return 'invalid'
    board={}
    for i,row in enumerate(rows):
        rank=8-i; f=0
        for ch in row:
            if ch.isdigit(): f+=int(ch)
            elif ch in 'pnbrqkPNBRQK':
                if f>7: return 'invalid'
                board[chr(97+f)+str(rank)]=ch; f+=1
            else: return 'invalid'
        if f!=8: return 'invalid'
    vals=list(board.values())
    if vals.count('K')!=1 or vals.count('k')!=1: return 'invalid'
    turn=parts[1]
    if turn not in ('w','b'): return 'invalid'
    cast='' if parts[2]=='-' else parts[2].upper()
    if any(c not in 'KQkq' for c in cast): return 'invalid'
    ep=None if parts[3]=='-' else parts[3]
    if ep is not None and ep[1:]!=('6' if turn=='w' else '3'): return 'invalid'
    if not (parts[4].isdigit() and parts[5].isdigit()) or int(parts[5])<1: return 'invalid'
    return {'pieces':board,'turn':turn,'castling':cast,'ep':ep,'halfmove':int(parts[4]),'fullmove':int(parts[5])}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
   {'castling': 'Q',
    'ep': None,
    'fullmove': 1,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
    'turn': 'w'}),
  ('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
   {'castling': '',
    'ep': 'd3',
    'fullmove': 12,
    'halfmove': 0,
    'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
    'turn': 'b'}),
  ('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
   {'castling': '',
    'ep': 'd6',
    'fullmove': 9,
    'halfmove': 0,
    'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
    'turn': 'w'}),
  ('ep wrong side', '4k3/8/8/3pP3/8/8/8/4K3 w - d3 0 9', 'invalid'),
  ('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
   {'castling': 'kq',
    'ep': None,
    'fullmove': 5,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'w'}),
  ('two white kings', '4k3/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
  ('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
  ('missing black king', '8/8/8/8/8/8/8/4K3 w - - 0 1', 'invalid')],
 [('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
   {'castling': '',
    'ep': 'd6',
    'fullmove': 9,
    'halfmove': 0,
    'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
    'turn': 'w'}),
  ('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
   {'castling': '',
    'ep': None,
    'fullmove': 20,
    'halfmove': 3,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'b'}),
  ('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
   {'castling': 'kq',
    'ep': None,
    'fullmove': 5,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'w'}),
  ('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
  ('missing black king', '8/8/8/8/8/8/8/4K3 w - - 0 1', 'invalid'),
  ('short rank', '4k3/8/8/8/8/8/8/4K2 w - - 0 1', 'invalid'),
  ('fullmove zero', '4k3/8/8/8/8/8/8/4K3 w - - 0 0', 'invalid'),
  ('halfmove dash', '4k3/8/8/8/8/8/8/4K3 w - - - 1', 'invalid')],
 [('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
   {'castling': '',
    'ep': 'd3',
    'fullmove': 12,
    'halfmove': 0,
    'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
    'turn': 'b'}),
  ('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
   {'castling': '',
    'ep': None,
    'fullmove': 20,
    'halfmove': 3,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'b'}),
  ('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
   {'castling': 'kq',
    'ep': None,
    'fullmove': 5,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'w'}),
  ('fullmove zero', '4k3/8/8/8/8/8/8/4K3 w - - 0 0', 'invalid'),
  ('halfmove dash', '4k3/8/8/8/8/8/8/4K3 w - - - 1', 'invalid'),
  ('pawns and knights', 'rn2k3/pp6/8/8/8/8/6PP/4K1NR w K - 7 30',
   {'castling': 'K',
    'ep': None,
    'fullmove': 30,
    'halfmove': 7,
    'pieces': {'a7': 'p',
               'a8': 'r',
               'b7': 'p',
               'b8': 'n',
               'e1': 'K',
               'e8': 'k',
               'g1': 'N',
               'g2': 'P',
               'h1': 'R',
               'h2': 'P'},
    'turn': 'w'}),
  ('bad castling letter', '4k3/8/8/8/8/8/8/4K3 w X - 0 1', 'invalid'),
  ('bad turn', '4k3/8/8/8/8/8/8/4K3 x - - 0 1', 'invalid')],
 [('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
   {'castling': 'Q',
    'ep': None,
    'fullmove': 1,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
    'turn': 'w'}),
  ('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
   {'castling': '',
    'ep': 'd3',
    'fullmove': 12,
    'halfmove': 0,
    'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
    'turn': 'b'}),
  ('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
   {'castling': '',
    'ep': 'd6',
    'fullmove': 9,
    'halfmove': 0,
    'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
    'turn': 'w'}),
  ('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
   {'castling': '',
    'ep': None,
    'fullmove': 20,
    'halfmove': 3,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'b'}),
  ('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
   {'castling': 'kq',
    'ep': None,
    'fullmove': 5,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'w'}),
  ('bad castling letter', '4k3/8/8/8/8/8/8/4K3 w X - 0 1', 'invalid'),
  ('bad turn', '4k3/8/8/8/8/8/8/4K3 x - - 0 1', 'invalid'),
  ('fullmove dash', '4k3/8/8/8/8/8/8/4K3 w - - 0 -', 'invalid')],
 [('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
   {'castling': 'Q',
    'ep': None,
    'fullmove': 1,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
    'turn': 'w'}),
  ('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
   {'castling': '',
    'ep': 'd3',
    'fullmove': 12,
    'halfmove': 0,
    'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
    'turn': 'b'}),
  ('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
   {'castling': '',
    'ep': 'd6',
    'fullmove': 9,
    'halfmove': 0,
    'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
    'turn': 'w'}),
  ('ep wrong side', '4k3/8/8/3pP3/8/8/8/4K3 w - d3 0 9', 'invalid'),
  ('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
   {'castling': '',
    'ep': None,
    'fullmove': 20,
    'halfmove': 3,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'b'}),
  ('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
   {'castling': 'kq',
    'ep': None,
    'fullmove': 5,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'w'}),
  ('two white kings', '4k3/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
  ('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid')]]
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
kings and rook{'castling': 'Q', 'ep': None, 'fullmove': 1, 'halfmove': 0, 'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'}, 'turn': 'w'}{'castling': 'Q', 'ep': None, 'fullmove': 1, 'halfmove': 0, 'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'}, 'turn': 'w'}Passed
black to move ep{'castling': '', 'ep': 'd3', 'fullmove': 12, 'halfmove': 0, 'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'}, 'turn': 'b'}{'castling': '', 'ep': 'd3', 'fullmove': 12, 'halfmove': 0, 'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'}, 'turn': 'b'}Passed
white ep target{'castling': '', 'ep': 'd6', 'fullmove': 9, 'halfmove': 0, 'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'turn': 'w'}{'castling': '', 'ep': 'd6', 'fullmove': 9, 'halfmove': 0, 'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'turn': 'w'}Passed
ep wrong sideinvalidinvalidPassed
black rights only{'castling': 'KQ', 'ep': None, 'fullmove': 5, 'halfmove': 0, 'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'}, 'turn': 'w'}{'castling': 'kq', 'ep': None, 'fullmove': 5, 'halfmove': 0, 'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'}, 'turn': 'w'}Failed
two white kingsinvalidinvalidPassed
two white kings no blackinvalidinvalidPassed
missing black kinginvalidinvalidPassed

SHA-256 / f65f9775b7199e0526df6d532bbe4587cb0d4287317ca28de263df1f79f1f274

3 / The verified repair

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

N = 1
observations = []
def solve(x):
    parts=x.split()
    if len(parts)!=6: return 'invalid'
    rows=parts[0].split('/')
    if len(rows)!=8: return 'invalid'
    board={}
    for i,row in enumerate(rows):
        rank=8-i; f=0
        for ch in row:
            if ch.isdigit(): f+=int(ch)
            elif ch in 'pnbrqkPNBRQK':
                if f>7: return 'invalid'
                board[chr(97+f)+str(rank)]=ch; f+=1
            else: return 'invalid'
        if f!=8: return 'invalid'
    vals=list(board.values())
    if vals.count('K')!=1 or vals.count('k')!=1: return 'invalid'
    turn=parts[1]
    if turn not in ('w','b'): return 'invalid'
    cast='' if parts[2]=='-' else parts[2]
    if any(c not in 'KQkq' for c in cast): return 'invalid'
    ep=None if parts[3]=='-' else parts[3]
    if ep is not None and ep[1:]!=('6' if turn=='w' else '3'): return 'invalid'
    if not (parts[4].isdigit() and parts[5].isdigit()) or int(parts[5])<1: return 'invalid'
    return {'pieces':board,'turn':turn,'castling':cast,'ep':ep,'halfmove':int(parts[4]),'fullmove':int(parts[5])}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
   {'castling': 'Q',
    'ep': None,
    'fullmove': 1,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
    'turn': 'w'}),
  ('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
   {'castling': '',
    'ep': 'd3',
    'fullmove': 12,
    'halfmove': 0,
    'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
    'turn': 'b'}),
  ('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
   {'castling': '',
    'ep': 'd6',
    'fullmove': 9,
    'halfmove': 0,
    'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
    'turn': 'w'}),
  ('ep wrong side', '4k3/8/8/3pP3/8/8/8/4K3 w - d3 0 9', 'invalid'),
  ('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
   {'castling': 'kq',
    'ep': None,
    'fullmove': 5,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'w'}),
  ('two white kings', '4k3/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
  ('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
  ('missing black king', '8/8/8/8/8/8/8/4K3 w - - 0 1', 'invalid')],
 [('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
   {'castling': '',
    'ep': 'd6',
    'fullmove': 9,
    'halfmove': 0,
    'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
    'turn': 'w'}),
  ('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
   {'castling': '',
    'ep': None,
    'fullmove': 20,
    'halfmove': 3,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'b'}),
  ('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
   {'castling': 'kq',
    'ep': None,
    'fullmove': 5,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'w'}),
  ('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
  ('missing black king', '8/8/8/8/8/8/8/4K3 w - - 0 1', 'invalid'),
  ('short rank', '4k3/8/8/8/8/8/8/4K2 w - - 0 1', 'invalid'),
  ('fullmove zero', '4k3/8/8/8/8/8/8/4K3 w - - 0 0', 'invalid'),
  ('halfmove dash', '4k3/8/8/8/8/8/8/4K3 w - - - 1', 'invalid')],
 [('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
   {'castling': '',
    'ep': 'd3',
    'fullmove': 12,
    'halfmove': 0,
    'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
    'turn': 'b'}),
  ('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
   {'castling': '',
    'ep': None,
    'fullmove': 20,
    'halfmove': 3,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'b'}),
  ('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
   {'castling': 'kq',
    'ep': None,
    'fullmove': 5,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'w'}),
  ('fullmove zero', '4k3/8/8/8/8/8/8/4K3 w - - 0 0', 'invalid'),
  ('halfmove dash', '4k3/8/8/8/8/8/8/4K3 w - - - 1', 'invalid'),
  ('pawns and knights', 'rn2k3/pp6/8/8/8/8/6PP/4K1NR w K - 7 30',
   {'castling': 'K',
    'ep': None,
    'fullmove': 30,
    'halfmove': 7,
    'pieces': {'a7': 'p',
               'a8': 'r',
               'b7': 'p',
               'b8': 'n',
               'e1': 'K',
               'e8': 'k',
               'g1': 'N',
               'g2': 'P',
               'h1': 'R',
               'h2': 'P'},
    'turn': 'w'}),
  ('bad castling letter', '4k3/8/8/8/8/8/8/4K3 w X - 0 1', 'invalid'),
  ('bad turn', '4k3/8/8/8/8/8/8/4K3 x - - 0 1', 'invalid')],
 [('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
   {'castling': 'Q',
    'ep': None,
    'fullmove': 1,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
    'turn': 'w'}),
  ('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
   {'castling': '',
    'ep': 'd3',
    'fullmove': 12,
    'halfmove': 0,
    'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
    'turn': 'b'}),
  ('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
   {'castling': '',
    'ep': 'd6',
    'fullmove': 9,
    'halfmove': 0,
    'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
    'turn': 'w'}),
  ('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
   {'castling': '',
    'ep': None,
    'fullmove': 20,
    'halfmove': 3,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'b'}),
  ('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
   {'castling': 'kq',
    'ep': None,
    'fullmove': 5,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'w'}),
  ('bad castling letter', '4k3/8/8/8/8/8/8/4K3 w X - 0 1', 'invalid'),
  ('bad turn', '4k3/8/8/8/8/8/8/4K3 x - - 0 1', 'invalid'),
  ('fullmove dash', '4k3/8/8/8/8/8/8/4K3 w - - 0 -', 'invalid')],
 [('kings and rook', '4k3/8/8/8/8/8/8/R3K3 w Q - 0 1',
   {'castling': 'Q',
    'ep': None,
    'fullmove': 1,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'},
    'turn': 'w'}),
  ('black to move ep', '4k3/8/8/8/3Pp3/8/8/4K3 b - d3 0 12',
   {'castling': '',
    'ep': 'd3',
    'fullmove': 12,
    'halfmove': 0,
    'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'},
    'turn': 'b'}),
  ('white ep target', '4k3/8/8/3pP3/8/8/8/4K3 w - d6 0 9',
   {'castling': '',
    'ep': 'd6',
    'fullmove': 9,
    'halfmove': 0,
    'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'},
    'turn': 'w'}),
  ('ep wrong side', '4k3/8/8/3pP3/8/8/8/4K3 w - d3 0 9', 'invalid'),
  ('no castling dash', 'r3k2r/8/8/8/8/8/8/R3K2R b - - 3 20',
   {'castling': '',
    'ep': None,
    'fullmove': 20,
    'halfmove': 3,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'b'}),
  ('black rights only', 'r3k2r/8/8/8/8/8/8/R3K2R w kq - 0 5',
   {'castling': 'kq',
    'ep': None,
    'fullmove': 5,
    'halfmove': 0,
    'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'},
    'turn': 'w'}),
  ('two white kings', '4k3/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid'),
  ('two white kings no black', '8/8/8/8/8/8/8/K3K3 w - - 0 1', 'invalid')]]
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
kings and rook{'castling': 'Q', 'ep': None, 'fullmove': 1, 'halfmove': 0, 'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'}, 'turn': 'w'}{'castling': 'Q', 'ep': None, 'fullmove': 1, 'halfmove': 0, 'pieces': {'a1': 'R', 'e1': 'K', 'e8': 'k'}, 'turn': 'w'}Passed
black to move ep{'castling': '', 'ep': 'd3', 'fullmove': 12, 'halfmove': 0, 'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'}, 'turn': 'b'}{'castling': '', 'ep': 'd3', 'fullmove': 12, 'halfmove': 0, 'pieces': {'d4': 'P', 'e1': 'K', 'e4': 'p', 'e8': 'k'}, 'turn': 'b'}Passed
white ep target{'castling': '', 'ep': 'd6', 'fullmove': 9, 'halfmove': 0, 'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'turn': 'w'}{'castling': '', 'ep': 'd6', 'fullmove': 9, 'halfmove': 0, 'pieces': {'d5': 'p', 'e1': 'K', 'e5': 'P', 'e8': 'k'}, 'turn': 'w'}Passed
ep wrong sideinvalidinvalidPassed
black rights only{'castling': 'kq', 'ep': None, 'fullmove': 5, 'halfmove': 0, 'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'}, 'turn': 'w'}{'castling': 'kq', 'ep': None, 'fullmove': 5, 'halfmove': 0, 'pieces': {'a1': 'R', 'a8': 'r', 'e1': 'K', 'e8': 'k', 'h1': 'R', 'h8': 'r'}, 'turn': 'w'}Passed
two white kingsinvalidinvalidPassed
two white kings no blackinvalidinvalidPassed
missing black kinginvalidinvalidPassed

SHA-256 / 53f10238e0510bf6d9c880ae9fa3c2efbd2b5d1de7c970b3dafb8ead58e56452

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

Case digest / 05273a0f89e28e26209fe33475cd1cbaab70367a8e4fb60ff703eebdf3977242