Game.fromFen accepts positions the engine cannot play #433

Closed
opened 2026-10-15 22:24:03 +00:00 by root · 3 comments
root commented 2026-10-15 22:24:03 +00:00 (Migrated from gitlab.core-project.space)

What happens

Game.fromFen accepts positions the engine cannot play, and they crash or corrupt it later. The front feeds Game.fromFen from storage (apps/front/src/local/stored-game.ts:42).

  • Castling right with the king off its home square. availableCastles checks the rook but not the king (packages/engine/src/rules/castling.ts:102-114).

    Game.fromFen("4k3/8/8/8/8/8/8/3K3R w K - 0 1").value.legalMoves();
    // throws "no piece at from square"
    
  • En passant square never checked (packages/engine/src/notation/fen.ts:168-177). Any square is accepted, so an en passant capture with no pawn behind it removes a phantom pawn, and the undo then adds one to the board (packages/engine/src/rules/search-board.ts:126-140,154-158).

  • Side not to move in check is accepted, and returns legal moves.

Done when

parseFen refuses each of these with its own FenError type:

  • a castling right whose king or rook is off its home square;
  • an en passant square that is not on rank 3 or 6, or has no pawn of the side that just moved on the square in front of it;
  • a position where the side not to move is in check.

Each refusal has a test, and the FEN above returns an error instead of a Game.

## What happens `Game.fromFen` accepts positions the engine cannot play, and they crash or corrupt it later. The front feeds `Game.fromFen` from storage (`apps/front/src/local/stored-game.ts:42`). - **Castling right with the king off its home square.** `availableCastles` checks the rook but not the king (`packages/engine/src/rules/castling.ts:102-114`). ```ts Game.fromFen("4k3/8/8/8/8/8/8/3K3R w K - 0 1").value.legalMoves(); // throws "no piece at from square" ``` - **En passant square never checked** (`packages/engine/src/notation/fen.ts:168-177`). Any square is accepted, so an en passant capture with no pawn behind it removes a phantom pawn, and the undo then adds one to the board (`packages/engine/src/rules/search-board.ts:126-140,154-158`). - **Side not to move in check** is accepted, and returns legal moves. ## Done when `parseFen` refuses each of these with its own `FenError` type: - a castling right whose king or rook is off its home square; - an en passant square that is not on rank 3 or 6, or has no pawn of the side that just moved on the square in front of it; - a position where the side not to move is in check. Each refusal has a test, and the FEN above returns an error instead of a `Game`.
root commented 2026-10-15 22:39:37 +00:00 (Migrated from gitlab.core-project.space)

mentioned in commit 22c74fe34a

mentioned in commit 22c74fe34a4e02515b3255543a83db78c68f7b10
root commented 2026-10-15 22:40:09 +00:00 (Migrated from gitlab.core-project.space)

mentioned in merge request !545

mentioned in merge request !545
root commented 2026-10-15 23:26:02 +00:00 (Migrated from gitlab.core-project.space)

mentioned in commit bcc826d393

mentioned in commit bcc826d3938be993c6629b8c34a609f7cf285572
root (Migrated from gitlab.core-project.space) closed this issue 2026-10-15 23:37:04 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
amaurycoudr/chess-project#433
No description provided.