Harden UCI/FEN parsing, fix engine bugs, upgrade toolchain and dependencies - #322
Merged
Conversation
- Reject malformed UCI moves gracefully instead of panicking: non-ASCII input caused byte-slicing panics, unknown promotion pieces hit unreachable!(), and equal source/target squares tripped a debug assertion. Promotion now implements TryFrom<char>. - Replace the unsound transmute in Move::promotion() with an explicit match: the niche layout of Option<Promotion> is not guaranteed. - Parse UCI 'go' time controls as milliseconds (per the UCI spec) instead of microseconds. - Fix out-of-bounds panic on 'setoption name Hash value' (trailing 'value' with no argument). - Fix 'go' argument scanning so that valueless tokens (ponder, infinite) no longer swallow the keyword that follows them. - Propagate errors in the engine loop instead of panicking on input errors and unreachable!() on invalid moves in 'position' commands. - Validate that the side not to move is not in check (also rejects adjacent kings) when parsing FEN, closing a long-standing TODO. - Saturate the halfmove clock instead of overflowing u8 in long games. - Report threefold repetition for four and more repetitions as well. - Fix bit-rotted generate_moves fuzz target (is_check() was called on a Result and could not compile). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GVrKvkMe4xDmkRAksacBzk
- Bump MSRV to 1.95 (required by shakmaty 0.30) and update the stale 1.80.0 pin in the build workflow, which could not build the 2024 edition anyway. - itertools 0.13 -> 0.15, rand 0.9 -> 0.10 (small_rng feature is now built-in, random() moved to RngExt), rand_distr 0.5 -> 0.6, shadow-rs 1 -> 2, shakmaty 0.27 -> 0.30, shakmaty-syzygy 0.25 -> 0.28, indicatif 0.17 -> 0.18, criterion 0.5 -> 0.8. - Fix new clippy::useless_borrows_in_formatting perf lint (denied via clippy::perf) surfaced by the newer toolchain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GVrKvkMe4xDmkRAksacBzk
kirillbobyrev
marked this pull request as ready for review
July 20, 2026 17:51
Fixes the Lint CI job: cargo +nightly fmt --check flagged formatting (mostly pre-existing) in position.rs and attacks.rs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GVrKvkMe4xDmkRAksacBzk
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A codebase review pass: bug fixes in UCI/FEN handling and game-state tracking, plus a toolchain/dependency upgrade.
Bug fixes (
fix:commit)gotime controls were parsed as microseconds — the UCI protocol specifies milliseconds, so the engine would have been given 1000× less time than intended once time management lands.&uci[..2]on a multi-byte char boundary);unreachable!();e2e2-style moves tripped a debug assertion inMove::new;setoption name Hash value(trailingvaluewith no argument) panicked with an out-of-bounds index.goargument scanning skipped two tokens after any unrecognized keyword, so valueless tokens (ponder, unknown extensions) swallowed the keyword that followed them (go ponder wtime 1000lostwtime).Move::promotion()— transmuting a rawu8toOption<Promotion>relies on an unspecified niche layout; replaced with an explicit match.u8incremented without bound panicked in debug builds past 255 plies without capture/pawn move; now saturates.RepetitionTable::recordreturnedfalsefor the 4th+ occurrence of a position (== 3→>= 3), which could un-flag a threefold draw.positioncommands now propagate as errors instead ofpanic!/unreachable!().generate_movescalledis_check()on aResultand did not compile.Upgrades (
chore:commit)rust-version.small_rngis built-in now andrandom()moved toRngExt), shadow-rs 1→2, shakmaty 0.27→0.30, shakmaty-syzygy 0.25→0.28, indicatif 0.17→0.18, criterion 0.5→0.8, plus a fullcargo update. Fuzz crate deps aligned.clippy::useless_borrows_in_formattingperf lint (denied viaclippy::perf) surfaced by clippy 1.97.Testing
cargo test: 102 tests + doctests pass.cargo test --release -- --ignored: all 12 expensive perft / differential tests against shakmaty pass (move generation exactness verified after the movegen-adjacent changes).cargo clippy --all-targetsclean (only pre-existing dead-code warnings in search stubs).setoption/goparsing edge cases, opposite-check and adjacent-king FEN rejection.🤖 Generated with Claude Code
https://claude.ai/code/session_01GVrKvkMe4xDmkRAksacBzk
Generated by Claude Code