FA-82641 / Chess move legality / Open access
SAN without "x" accepted as a capture · case 01
"Nf3" onto a black pawn resolves instead of requiring "Nxf3".
ROOT CAUSE
Non-capture SAN is not checked against an occupied target.
VERIFIED REPAIR
A move written without "x" must go to an empty square.
Unsuccessful approach: Rejecting only friendly-occupied targets still accepts enemy captures written without "x".
Case contract
Input: {"board", "white": side to move, "san"} for a non-castling move. Check suffixes + and # are ignored. Resolve the SAN to the unique origin square of a pseudo-legal move (sliders need a clear path; pawns push one or, from their start rank through an empty square, two; pawns capture one step diagonally forward). "x" requires an enemy piece on the target and its absence requires an empty target. File/rank disambiguators filter candidates. Return the origin, "ambiguous" or "illegal".
Why this case matters
PGN import and move entry depend on resolving SAN to exactly one move.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
b=x['board']; white=x['white']; s=x['san'].rstrip('+#')
def c(q): return ord(q[0])-97,int(q[1])-1
def n(f,r): return chr(97+f)+str(r+1)
piece=s[0] if s[0] in 'NBRQK' else 'P'
body=s[1:] if piece!='P' else s
capture='x' in body
body=body.replace('x','')
to=body[-2:]; dis=body[:-2]
tf,tr=c(to)
occ=b.get(to)
if capture and (occ is None or occ.isupper()==white): return 'illegal'
pass
letter=piece if white else piece.lower()
cands=[]
for q,v in b.items():
if v!=letter: continue
f,r=c(q)
if piece=='P':
d=1 if white else -1
if capture:
ok=abs(tf-f)==1 and tr-r==d
else:
ok=tf==f and (tr-r==d or (tr-r==2*d and r==(1 if white else 6) and n(f,r+d) not in b))
elif piece=='N':
ok=(abs(tf-f),abs(tr-r)) in ((1,2),(2,1))
elif piece=='K':
ok=max(abs(tf-f),abs(tr-r))==1
else:
df,dr=tf-f,tr-r
orth=(df==0)!=(dr==0); diag=abs(df)==abs(dr) and df!=0
ok=(piece=='R' and orth) or (piece=='B' and diag) or (piece=='Q' and (orth or diag))
if ok:
sf=(df>0)-(df<0); sr=(dr>0)-(dr<0)
cf,cr=f+sf,r+sr
while (cf,cr)!=(tf,tr):
if n(cf,cr) in b: ok=False
cf+=sf; cr+=sr
if ok and all((ch==q[0]) if ch.isalpha() else (ch==q[1]) for ch in dis):
cands.append(q)
if len(cands)==1: return cands[0]
return 'ambiguous' if cands else 'illegal'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('knight file disambiguation',
{'board': {'b1': 'N', 'e1': 'K', 'e8': 'k', 'f3': 'N'}, 'san': 'Nbd2', 'white': True}, 'b1'),
('knight ambiguous',
{'board': {'b1': 'N', 'e1': 'K', 'e8': 'k', 'f3': 'N'}, 'san': 'Nd2', 'white': True},
'ambiguous'),
('rook rank disambiguation',
{'board': {'a1': 'R', 'a5': 'R', 'e1': 'K', 'e8': 'k'}, 'san': 'R1a3', 'white': True}, 'a1'),
('rook rank disambiguation upper',
{'board': {'a1': 'R', 'a5': 'R', 'e1': 'K', 'e8': 'k'}, 'san': 'R5a3', 'white': True}, 'a5'),
('mate suffix', {'board': {'e1': 'K', 'e8': 'k', 'h5': 'Q'}, 'san': 'Qf7#', 'white': True}, 'h5'),
('check suffix', {'board': {'e1': 'K', 'e8': 'k', 'h5': 'Q'}, 'san': 'Qe5+', 'white': True},
'h5'),
('quiet move onto enemy',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('quiet move onto own',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'P', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal')],
[('rook rank disambiguation upper',
{'board': {'a1': 'R', 'a5': 'R', 'e1': 'K', 'e8': 'k'}, 'san': 'R5a3', 'white': True}, 'a5'),
('mate suffix', {'board': {'e1': 'K', 'e8': 'k', 'h5': 'Q'}, 'san': 'Qf7#', 'white': True}, 'h5'),
('check suffix', {'board': {'e1': 'K', 'e8': 'k', 'h5': 'Q'}, 'san': 'Qe5+', 'white': True},
'h5'),
('quiet move onto enemy',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('quiet move onto own',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'P', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('capture with x',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nxf3', 'white': True}, 'g1'),
('black double push', {'board': {'d7': 'p', 'e1': 'K', 'e8': 'k'}, 'san': 'd5', 'white': False},
'd7'),
('white double push', {'board': {'e1': 'K', 'e2': 'P', 'e8': 'k'}, 'san': 'e4', 'white': True},
'e2')],
[('quiet move onto enemy',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('quiet move onto own',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'P', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('capture with x',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nxf3', 'white': True}, 'g1'),
('black double push', {'board': {'d7': 'p', 'e1': 'K', 'e8': 'k'}, 'san': 'd5', 'white': False},
'd7'),
('white double push', {'board': {'e1': 'K', 'e2': 'P', 'e8': 'k'}, 'san': 'e4', 'white': True},
'e2'),
('pawn capture file',
{'board': {'c4': 'P', 'd5': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'san': 'exd5', 'white': True},
'e4'),
('backward pawn capture',
{'board': {'d3': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'san': 'exd3', 'white': True},
'illegal'),
('black pawn capture',
{'board': {'d4': 'P', 'e1': 'K', 'e5': 'p', 'e8': 'k'}, 'san': 'exd4', 'white': False}, 'e5')],
[('knight file disambiguation',
{'board': {'b1': 'N', 'e1': 'K', 'e8': 'k', 'f3': 'N'}, 'san': 'Nbd2', 'white': True}, 'b1'),
('quiet move onto enemy',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('quiet move onto own',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'P', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('pawn capture file',
{'board': {'c4': 'P', 'd5': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'san': 'exd5', 'white': True},
'e4'),
('backward pawn capture',
{'board': {'d3': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'san': 'exd3', 'white': True},
'illegal'),
('black pawn capture',
{'board': {'d4': 'P', 'e1': 'K', 'e5': 'p', 'e8': 'k'}, 'san': 'exd4', 'white': False}, 'e5'),
('rook blocked candidate',
{'board': {'a1': 'R', 'c1': 'B', 'e2': 'K', 'e8': 'k', 'h1': 'R'}, 'san': 'Rd1', 'white': True},
'h1'),
('bishop simple', {'board': {'c1': 'B', 'e1': 'K', 'e8': 'k'}, 'san': 'Bg5', 'white': True},
'c1')],
[('knight file disambiguation',
{'board': {'b1': 'N', 'e1': 'K', 'e8': 'k', 'f3': 'N'}, 'san': 'Nbd2', 'white': True}, 'b1'),
('knight ambiguous',
{'board': {'b1': 'N', 'e1': 'K', 'e8': 'k', 'f3': 'N'}, 'san': 'Nd2', 'white': True},
'ambiguous'),
('rook rank disambiguation',
{'board': {'a1': 'R', 'a5': 'R', 'e1': 'K', 'e8': 'k'}, 'san': 'R1a3', 'white': True}, 'a1'),
('rook rank disambiguation upper',
{'board': {'a1': 'R', 'a5': 'R', 'e1': 'K', 'e8': 'k'}, 'san': 'R5a3', 'white': True}, 'a5'),
('quiet move onto enemy',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('quiet move onto own',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'P', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('rook blocked candidate',
{'board': {'a1': 'R', 'c1': 'B', 'e2': 'K', 'e8': 'k', 'h1': 'R'}, 'san': 'Rd1', 'white': True},
'h1'),
('bishop simple', {'board': {'c1': 'B', 'e1': 'K', 'e8': 'k'}, 'san': 'Bg5', 'white': True},
'c1')]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| knight file disambiguation | b1 | b1 | Passed |
| knight ambiguous | ambiguous | ambiguous | Passed |
| rook rank disambiguation | a1 | a1 | Passed |
| rook rank disambiguation upper | a5 | a5 | Passed |
| mate suffix | h5 | h5 | Passed |
| check suffix | h5 | h5 | Passed |
| quiet move onto enemy | g1 | illegal | Failed |
| quiet move onto own | g1 | illegal | Failed |
SHA-256 / 14212e3c6f522f0d91aa1256fe0aa41f09025cef928f382232910c32b12e2dee
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
b=x['board']; white=x['white']; s=x['san'].rstrip('+#')
def c(q): return ord(q[0])-97,int(q[1])-1
def n(f,r): return chr(97+f)+str(r+1)
piece=s[0] if s[0] in 'NBRQK' else 'P'
body=s[1:] if piece!='P' else s
capture='x' in body
body=body.replace('x','')
to=body[-2:]; dis=body[:-2]
tf,tr=c(to)
occ=b.get(to)
if capture and (occ is None or occ.isupper()==white): return 'illegal'
if not capture and occ is not None and occ.isupper()==white: return 'illegal'
letter=piece if white else piece.lower()
cands=[]
for q,v in b.items():
if v!=letter: continue
f,r=c(q)
if piece=='P':
d=1 if white else -1
if capture:
ok=abs(tf-f)==1 and tr-r==d
else:
ok=tf==f and (tr-r==d or (tr-r==2*d and r==(1 if white else 6) and n(f,r+d) not in b))
elif piece=='N':
ok=(abs(tf-f),abs(tr-r)) in ((1,2),(2,1))
elif piece=='K':
ok=max(abs(tf-f),abs(tr-r))==1
else:
df,dr=tf-f,tr-r
orth=(df==0)!=(dr==0); diag=abs(df)==abs(dr) and df!=0
ok=(piece=='R' and orth) or (piece=='B' and diag) or (piece=='Q' and (orth or diag))
if ok:
sf=(df>0)-(df<0); sr=(dr>0)-(dr<0)
cf,cr=f+sf,r+sr
while (cf,cr)!=(tf,tr):
if n(cf,cr) in b: ok=False
cf+=sf; cr+=sr
if ok and all((ch==q[0]) if ch.isalpha() else (ch==q[1]) for ch in dis):
cands.append(q)
if len(cands)==1: return cands[0]
return 'ambiguous' if cands else 'illegal'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('knight file disambiguation',
{'board': {'b1': 'N', 'e1': 'K', 'e8': 'k', 'f3': 'N'}, 'san': 'Nbd2', 'white': True}, 'b1'),
('knight ambiguous',
{'board': {'b1': 'N', 'e1': 'K', 'e8': 'k', 'f3': 'N'}, 'san': 'Nd2', 'white': True},
'ambiguous'),
('rook rank disambiguation',
{'board': {'a1': 'R', 'a5': 'R', 'e1': 'K', 'e8': 'k'}, 'san': 'R1a3', 'white': True}, 'a1'),
('rook rank disambiguation upper',
{'board': {'a1': 'R', 'a5': 'R', 'e1': 'K', 'e8': 'k'}, 'san': 'R5a3', 'white': True}, 'a5'),
('mate suffix', {'board': {'e1': 'K', 'e8': 'k', 'h5': 'Q'}, 'san': 'Qf7#', 'white': True}, 'h5'),
('check suffix', {'board': {'e1': 'K', 'e8': 'k', 'h5': 'Q'}, 'san': 'Qe5+', 'white': True},
'h5'),
('quiet move onto enemy',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('quiet move onto own',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'P', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal')],
[('rook rank disambiguation upper',
{'board': {'a1': 'R', 'a5': 'R', 'e1': 'K', 'e8': 'k'}, 'san': 'R5a3', 'white': True}, 'a5'),
('mate suffix', {'board': {'e1': 'K', 'e8': 'k', 'h5': 'Q'}, 'san': 'Qf7#', 'white': True}, 'h5'),
('check suffix', {'board': {'e1': 'K', 'e8': 'k', 'h5': 'Q'}, 'san': 'Qe5+', 'white': True},
'h5'),
('quiet move onto enemy',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('quiet move onto own',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'P', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('capture with x',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nxf3', 'white': True}, 'g1'),
('black double push', {'board': {'d7': 'p', 'e1': 'K', 'e8': 'k'}, 'san': 'd5', 'white': False},
'd7'),
('white double push', {'board': {'e1': 'K', 'e2': 'P', 'e8': 'k'}, 'san': 'e4', 'white': True},
'e2')],
[('quiet move onto enemy',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('quiet move onto own',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'P', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('capture with x',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nxf3', 'white': True}, 'g1'),
('black double push', {'board': {'d7': 'p', 'e1': 'K', 'e8': 'k'}, 'san': 'd5', 'white': False},
'd7'),
('white double push', {'board': {'e1': 'K', 'e2': 'P', 'e8': 'k'}, 'san': 'e4', 'white': True},
'e2'),
('pawn capture file',
{'board': {'c4': 'P', 'd5': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'san': 'exd5', 'white': True},
'e4'),
('backward pawn capture',
{'board': {'d3': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'san': 'exd3', 'white': True},
'illegal'),
('black pawn capture',
{'board': {'d4': 'P', 'e1': 'K', 'e5': 'p', 'e8': 'k'}, 'san': 'exd4', 'white': False}, 'e5')],
[('knight file disambiguation',
{'board': {'b1': 'N', 'e1': 'K', 'e8': 'k', 'f3': 'N'}, 'san': 'Nbd2', 'white': True}, 'b1'),
('quiet move onto enemy',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('quiet move onto own',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'P', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('pawn capture file',
{'board': {'c4': 'P', 'd5': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'san': 'exd5', 'white': True},
'e4'),
('backward pawn capture',
{'board': {'d3': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'san': 'exd3', 'white': True},
'illegal'),
('black pawn capture',
{'board': {'d4': 'P', 'e1': 'K', 'e5': 'p', 'e8': 'k'}, 'san': 'exd4', 'white': False}, 'e5'),
('rook blocked candidate',
{'board': {'a1': 'R', 'c1': 'B', 'e2': 'K', 'e8': 'k', 'h1': 'R'}, 'san': 'Rd1', 'white': True},
'h1'),
('bishop simple', {'board': {'c1': 'B', 'e1': 'K', 'e8': 'k'}, 'san': 'Bg5', 'white': True},
'c1')],
[('knight file disambiguation',
{'board': {'b1': 'N', 'e1': 'K', 'e8': 'k', 'f3': 'N'}, 'san': 'Nbd2', 'white': True}, 'b1'),
('knight ambiguous',
{'board': {'b1': 'N', 'e1': 'K', 'e8': 'k', 'f3': 'N'}, 'san': 'Nd2', 'white': True},
'ambiguous'),
('rook rank disambiguation',
{'board': {'a1': 'R', 'a5': 'R', 'e1': 'K', 'e8': 'k'}, 'san': 'R1a3', 'white': True}, 'a1'),
('rook rank disambiguation upper',
{'board': {'a1': 'R', 'a5': 'R', 'e1': 'K', 'e8': 'k'}, 'san': 'R5a3', 'white': True}, 'a5'),
('quiet move onto enemy',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('quiet move onto own',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'P', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('rook blocked candidate',
{'board': {'a1': 'R', 'c1': 'B', 'e2': 'K', 'e8': 'k', 'h1': 'R'}, 'san': 'Rd1', 'white': True},
'h1'),
('bishop simple', {'board': {'c1': 'B', 'e1': 'K', 'e8': 'k'}, 'san': 'Bg5', 'white': True},
'c1')]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| knight file disambiguation | b1 | b1 | Passed |
| knight ambiguous | ambiguous | ambiguous | Passed |
| rook rank disambiguation | a1 | a1 | Passed |
| rook rank disambiguation upper | a5 | a5 | Passed |
| mate suffix | h5 | h5 | Passed |
| check suffix | h5 | h5 | Passed |
| quiet move onto enemy | g1 | illegal | Failed |
| quiet move onto own | illegal | illegal | Passed |
SHA-256 / 0fbe909554029b5a0e549294e2287625c81dbdd93ffaae501c186f9d876a05c6
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
b=x['board']; white=x['white']; s=x['san'].rstrip('+#')
def c(q): return ord(q[0])-97,int(q[1])-1
def n(f,r): return chr(97+f)+str(r+1)
piece=s[0] if s[0] in 'NBRQK' else 'P'
body=s[1:] if piece!='P' else s
capture='x' in body
body=body.replace('x','')
to=body[-2:]; dis=body[:-2]
tf,tr=c(to)
occ=b.get(to)
if capture and (occ is None or occ.isupper()==white): return 'illegal'
if not capture and occ is not None: return 'illegal'
letter=piece if white else piece.lower()
cands=[]
for q,v in b.items():
if v!=letter: continue
f,r=c(q)
if piece=='P':
d=1 if white else -1
if capture:
ok=abs(tf-f)==1 and tr-r==d
else:
ok=tf==f and (tr-r==d or (tr-r==2*d and r==(1 if white else 6) and n(f,r+d) not in b))
elif piece=='N':
ok=(abs(tf-f),abs(tr-r)) in ((1,2),(2,1))
elif piece=='K':
ok=max(abs(tf-f),abs(tr-r))==1
else:
df,dr=tf-f,tr-r
orth=(df==0)!=(dr==0); diag=abs(df)==abs(dr) and df!=0
ok=(piece=='R' and orth) or (piece=='B' and diag) or (piece=='Q' and (orth or diag))
if ok:
sf=(df>0)-(df<0); sr=(dr>0)-(dr<0)
cf,cr=f+sf,r+sr
while (cf,cr)!=(tf,tr):
if n(cf,cr) in b: ok=False
cf+=sf; cr+=sr
if ok and all((ch==q[0]) if ch.isalpha() else (ch==q[1]) for ch in dis):
cands.append(q)
if len(cands)==1: return cands[0]
return 'ambiguous' if cands else 'illegal'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('knight file disambiguation',
{'board': {'b1': 'N', 'e1': 'K', 'e8': 'k', 'f3': 'N'}, 'san': 'Nbd2', 'white': True}, 'b1'),
('knight ambiguous',
{'board': {'b1': 'N', 'e1': 'K', 'e8': 'k', 'f3': 'N'}, 'san': 'Nd2', 'white': True},
'ambiguous'),
('rook rank disambiguation',
{'board': {'a1': 'R', 'a5': 'R', 'e1': 'K', 'e8': 'k'}, 'san': 'R1a3', 'white': True}, 'a1'),
('rook rank disambiguation upper',
{'board': {'a1': 'R', 'a5': 'R', 'e1': 'K', 'e8': 'k'}, 'san': 'R5a3', 'white': True}, 'a5'),
('mate suffix', {'board': {'e1': 'K', 'e8': 'k', 'h5': 'Q'}, 'san': 'Qf7#', 'white': True}, 'h5'),
('check suffix', {'board': {'e1': 'K', 'e8': 'k', 'h5': 'Q'}, 'san': 'Qe5+', 'white': True},
'h5'),
('quiet move onto enemy',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('quiet move onto own',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'P', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal')],
[('rook rank disambiguation upper',
{'board': {'a1': 'R', 'a5': 'R', 'e1': 'K', 'e8': 'k'}, 'san': 'R5a3', 'white': True}, 'a5'),
('mate suffix', {'board': {'e1': 'K', 'e8': 'k', 'h5': 'Q'}, 'san': 'Qf7#', 'white': True}, 'h5'),
('check suffix', {'board': {'e1': 'K', 'e8': 'k', 'h5': 'Q'}, 'san': 'Qe5+', 'white': True},
'h5'),
('quiet move onto enemy',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('quiet move onto own',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'P', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('capture with x',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nxf3', 'white': True}, 'g1'),
('black double push', {'board': {'d7': 'p', 'e1': 'K', 'e8': 'k'}, 'san': 'd5', 'white': False},
'd7'),
('white double push', {'board': {'e1': 'K', 'e2': 'P', 'e8': 'k'}, 'san': 'e4', 'white': True},
'e2')],
[('quiet move onto enemy',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('quiet move onto own',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'P', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('capture with x',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nxf3', 'white': True}, 'g1'),
('black double push', {'board': {'d7': 'p', 'e1': 'K', 'e8': 'k'}, 'san': 'd5', 'white': False},
'd7'),
('white double push', {'board': {'e1': 'K', 'e2': 'P', 'e8': 'k'}, 'san': 'e4', 'white': True},
'e2'),
('pawn capture file',
{'board': {'c4': 'P', 'd5': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'san': 'exd5', 'white': True},
'e4'),
('backward pawn capture',
{'board': {'d3': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'san': 'exd3', 'white': True},
'illegal'),
('black pawn capture',
{'board': {'d4': 'P', 'e1': 'K', 'e5': 'p', 'e8': 'k'}, 'san': 'exd4', 'white': False}, 'e5')],
[('knight file disambiguation',
{'board': {'b1': 'N', 'e1': 'K', 'e8': 'k', 'f3': 'N'}, 'san': 'Nbd2', 'white': True}, 'b1'),
('quiet move onto enemy',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('quiet move onto own',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'P', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('pawn capture file',
{'board': {'c4': 'P', 'd5': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'san': 'exd5', 'white': True},
'e4'),
('backward pawn capture',
{'board': {'d3': 'p', 'e1': 'K', 'e4': 'P', 'e8': 'k'}, 'san': 'exd3', 'white': True},
'illegal'),
('black pawn capture',
{'board': {'d4': 'P', 'e1': 'K', 'e5': 'p', 'e8': 'k'}, 'san': 'exd4', 'white': False}, 'e5'),
('rook blocked candidate',
{'board': {'a1': 'R', 'c1': 'B', 'e2': 'K', 'e8': 'k', 'h1': 'R'}, 'san': 'Rd1', 'white': True},
'h1'),
('bishop simple', {'board': {'c1': 'B', 'e1': 'K', 'e8': 'k'}, 'san': 'Bg5', 'white': True},
'c1')],
[('knight file disambiguation',
{'board': {'b1': 'N', 'e1': 'K', 'e8': 'k', 'f3': 'N'}, 'san': 'Nbd2', 'white': True}, 'b1'),
('knight ambiguous',
{'board': {'b1': 'N', 'e1': 'K', 'e8': 'k', 'f3': 'N'}, 'san': 'Nd2', 'white': True},
'ambiguous'),
('rook rank disambiguation',
{'board': {'a1': 'R', 'a5': 'R', 'e1': 'K', 'e8': 'k'}, 'san': 'R1a3', 'white': True}, 'a1'),
('rook rank disambiguation upper',
{'board': {'a1': 'R', 'a5': 'R', 'e1': 'K', 'e8': 'k'}, 'san': 'R5a3', 'white': True}, 'a5'),
('quiet move onto enemy',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'p', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('quiet move onto own',
{'board': {'e1': 'K', 'e8': 'k', 'f3': 'P', 'g1': 'N'}, 'san': 'Nf3', 'white': True},
'illegal'),
('rook blocked candidate',
{'board': {'a1': 'R', 'c1': 'B', 'e2': 'K', 'e8': 'k', 'h1': 'R'}, 'san': 'Rd1', 'white': True},
'h1'),
('bishop simple', {'board': {'c1': 'B', 'e1': 'K', 'e8': 'k'}, 'san': 'Bg5', 'white': True},
'c1')]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| knight file disambiguation | b1 | b1 | Passed |
| knight ambiguous | ambiguous | ambiguous | Passed |
| rook rank disambiguation | a1 | a1 | Passed |
| rook rank disambiguation upper | a5 | a5 | Passed |
| mate suffix | h5 | h5 | Passed |
| check suffix | h5 | h5 | Passed |
| quiet move onto enemy | illegal | illegal | Passed |
| quiet move onto own | illegal | illegal | Passed |
SHA-256 / 68cc972cabf60f73260ce324cd806b9c781c91f560f313716ac0e83c6be7dbdf
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:14.038497+00:00.
Case digest / d42e3c3da71b4c4a317371b3438b1edc6ea35896aad8947b2210dbd329d93283