FA-82811 / Chess move legality / Open access
Enemy piece on its own king's line counted as discovered check · case 01
After a quiet white knight move, a black rook standing on its own king's file is reported as a discovered check.
ROOT CAUSE
The discovered scan does not filter attackers by the mover's colour.
THE FAILURE
The discovered scan does not filter attackers by the mover's colour.
Unsuccessful approach: Filtering for white pieces works only when white moves.
Case contract
Input: {"board", "move": [from, to] or [from, to, promotion letter]}. Apply the move (promotion letter becomes a piece of the mover's colour) and classify the check it gives to the enemy king: "direct" (the moved piece attacks it), "discovered" (another of the mover's pieces now attacks it), "double" (both) or "none". Pawns attack diagonally forward, sliders need a clear path.
Why this case matters
SAN "+" suffixes and double-check rules both depend on this classification.
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'][:2]; p=b.pop(fr)
if len(x['move'])>2: p=x['move'][2].upper() if p.isupper() else x['move'][2].lower()
b[to]=p
white=p.isupper()
ks=[s for s,v in b.items() if v==('k' if white else 'K')][0]
def hits(src, tgt):
v=b[src]; t=v.upper()
f,r=ord(src[0])-97,int(src[1])-1
tf,tr=ord(tgt[0])-97,int(tgt[1])-1
df,dr=tf-f,tr-r
if t=='P': return abs(df)==1 and dr==(1 if v.isupper() else -1)
if t=='N': return (abs(df),abs(dr)) in ((1,2),(2,1))
if t=='K': return max(abs(df),abs(dr))==1
orth=(df==0)!=(dr==0); diag=abs(df)==abs(dr) and df!=0
if not ((t in ('R','Q') and orth) or (t in ('B','Q') and diag)): return False
sf=(df>0)-(df<0); sr=(dr>0)-(dr<0)
cf,cr=f+sf,r+sr
while (cf,cr)!=(tf,tr):
if chr(97+cf)+str(cr+1) in b: return False
cf+=sf; cr+=sr
return True
direct=hits(to,ks)
disc=any(hits(s,ks) for s,v in b.items() if s!=to and v.upper()!='K')
if direct and disc: return 'double'
if direct: return 'direct'
if disc: return 'discovered'
return 'none'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
'direct'),
('knight promotion check',
{'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
('discovered by bishop',
{'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
'double'),
('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
'direct'),
('defender rook on own king line',
{'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
('black discovered',
{'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')],
[('discovered by bishop',
{'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
'double'),
('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
'direct'),
('rook lands on king diagonal',
{'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
'direct'),
('defender rook on own king line',
{'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
('black discovered',
{'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')],
[('rook lands on king diagonal',
{'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
'direct'),
('defender rook on own king line',
{'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
('black discovered',
{'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered'),
('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
('white piece near own line',
{'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
'discovered')],
[('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
'direct'),
('knight promotion check',
{'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
('defender rook on own king line',
{'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
('black discovered',
{'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered'),
('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
('white piece near own line',
{'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
'discovered')],
[('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
'direct'),
('knight promotion check',
{'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
('discovered by bishop',
{'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
'double'),
('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
'direct'),
('defender rook on own king line',
{'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
('black discovered',
{'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')]]
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 |
|---|---|---|---|
| promotion gives check | direct | direct | Passed |
| knight promotion check | direct | direct | Passed |
| simple direct | direct | direct | Passed |
| discovered by bishop | discovered | discovered | Passed |
| double check | double | double | Passed |
| queen diagonal direct | direct | direct | Passed |
| defender rook on own king line | discovered | none | Failed |
| black discovered | discovered | discovered | Passed |
SHA-256 / 73e77117e57f64a3c1118178592038d47ee43f5692ecabcb8bb7836d559adee9
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'][:2]; p=b.pop(fr)
if len(x['move'])>2: p=x['move'][2].upper() if p.isupper() else x['move'][2].lower()
b[to]=p
white=p.isupper()
ks=[s for s,v in b.items() if v==('k' if white else 'K')][0]
def hits(src, tgt):
v=b[src]; t=v.upper()
f,r=ord(src[0])-97,int(src[1])-1
tf,tr=ord(tgt[0])-97,int(tgt[1])-1
df,dr=tf-f,tr-r
if t=='P': return abs(df)==1 and dr==(1 if v.isupper() else -1)
if t=='N': return (abs(df),abs(dr)) in ((1,2),(2,1))
if t=='K': return max(abs(df),abs(dr))==1
orth=(df==0)!=(dr==0); diag=abs(df)==abs(dr) and df!=0
if not ((t in ('R','Q') and orth) or (t in ('B','Q') and diag)): return False
sf=(df>0)-(df<0); sr=(dr>0)-(dr<0)
cf,cr=f+sf,r+sr
while (cf,cr)!=(tf,tr):
if chr(97+cf)+str(cr+1) in b: return False
cf+=sf; cr+=sr
return True
direct=hits(to,ks)
disc=any(hits(s,ks) for s,v in b.items() if s!=to and v.isupper() and v.upper()!='K')
if direct and disc: return 'double'
if direct: return 'direct'
if disc: return 'discovered'
return 'none'
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
'direct'),
('knight promotion check',
{'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
('discovered by bishop',
{'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
'double'),
('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
'direct'),
('defender rook on own king line',
{'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
('black discovered',
{'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')],
[('discovered by bishop',
{'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
'double'),
('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
'direct'),
('rook lands on king diagonal',
{'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
'direct'),
('defender rook on own king line',
{'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
('black discovered',
{'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')],
[('rook lands on king diagonal',
{'board': {'b1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['b1', 'b2']}, 'none'),
('rook quiet', {'board': {'a1': 'R', 'e1': 'K', 'h8': 'k'}, 'move': ['a1', 'b1']}, 'none'),
('black rook direct', {'board': {'a8': 'r', 'e1': 'K', 'h8': 'k'}, 'move': ['a8', 'a1']},
'direct'),
('defender rook on own king line',
{'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
('black discovered',
{'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered'),
('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
('white piece near own line',
{'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
'discovered')],
[('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
'direct'),
('knight promotion check',
{'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
('defender rook on own king line',
{'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
('black discovered',
{'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered'),
('bishop direct', {'board': {'a1': 'K', 'e8': 'k', 'f1': 'B'}, 'move': ['f1', 'b5']}, 'direct'),
('pawn push check', {'board': {'a1': 'K', 'd5': 'P', 'e7': 'k'}, 'move': ['d5', 'd6']}, 'direct'),
('white piece near own line',
{'board': {'a1': 'K', 'a2': 'r', 'c1': 'B', 'e3': 'P', 'h6': 'k'}, 'move': ['e3', 'e4']},
'discovered')],
[('promotion gives check', {'board': {'a1': 'K', 'b7': 'P', 'e8': 'k'}, 'move': ['b7', 'b8', 'q']},
'direct'),
('knight promotion check',
{'board': {'a1': 'K', 'e7': 'P', 'g7': 'k'}, 'move': ['e7', 'e8', 'n']}, 'direct'),
('simple direct', {'board': {'b1': 'N', 'd4': 'k', 'h1': 'K'}, 'move': ['b1', 'c2']}, 'direct'),
('discovered by bishop',
{'board': {'a1': 'K', 'c3': 'B', 'd4': 'N', 'h8': 'k'}, 'move': ['d4', 'b5']}, 'discovered'),
('double check', {'board': {'a1': 'K', 'e1': 'R', 'e4': 'N', 'e8': 'k'}, 'move': ['e4', 'f6']},
'double'),
('queen diagonal direct', {'board': {'a2': 'K', 'd1': 'Q', 'h8': 'k'}, 'move': ['d1', 'd4']},
'direct'),
('defender rook on own king line',
{'board': {'a1': 'K', 'b1': 'N', 'e5': 'r', 'e8': 'k'}, 'move': ['b1', 'c3']}, 'none'),
('black discovered',
{'board': {'a8': 'k', 'e1': 'K', 'e7': 'n', 'e8': 'r'}, 'move': ['e7', 'c6']}, 'discovered')]]
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 |
|---|---|---|---|
| promotion gives check | direct | direct | Passed |
| knight promotion check | direct | direct | Passed |
| simple direct | direct | direct | Passed |
| discovered by bishop | discovered | discovered | Passed |
| double check | double | double | Passed |
| queen diagonal direct | direct | direct | Passed |
| defender rook on own king line | none | none | Passed |
| black discovered | none | discovered | Failed |
SHA-256 / a34b26110396eb7ffc8d4eaeb7f07b45ac12207c8eef435634422e8e4e8b386a
HELD IN THE MEMBER ARCHIVE
The verified repair and its recorded checks are member-only.
This mechanism has 8 recorded checks per implementation. The open-access tier publishes the failure and the unsuccessful fix; the repaired source that passes every check, and the observations that prove it, are available to members.
Every case sharing this mechanism uses the same contract and the same repair, so this one record is held back for all of them.
Member access is invitation-based. Sign in with your invited account to inspect the repair.
Sign in to the archive ↗Verification & scope
A 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:15.509354+00:00.
Case digest / 58f3e044ad557fc86a591328857fbe3da117a63a905a90efd1a5247a265508fd