Skip to content

Fix analysis engine receiving bare 'go' instead of 'go infinite'#63

Merged
fsmosca merged 4 commits intomasterfrom
copilot/fix-unresponsive-gui-buttons
Mar 29, 2026
Merged

Fix analysis engine receiving bare 'go' instead of 'go infinite'#63
fsmosca merged 4 commits intomasterfrom
copilot/fix-unresponsive-gui-buttons

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 29, 2026

Review mode analysis engine sits idle because it receives the UCI command go (no parameters) instead of go infinite. The board never updates and the GUI becomes unresponsive.

Root cause

python-chess's engine.analysis(board, limit) decides whether to append infinite via if limit:. A Limit() dataclass with all-None fields is truthy, so passing Limit(depth=None) produces bare go instead of go infinite:

# python-chess internals (engine.py)
if limit:
    self.engine._go(limit, root_moves=root_moves)          # sends "go"
else:
    self.engine._go(Limit(), root_moves=root_moves, infinite=True)  # sends "go infinite"

Changes

  • Pass limit=None for infinite analysis — When tc_type='infinite' with no depth constraint, pass None instead of Limit(depth=None) so python-chess takes the else branch and sends go infinite. Custom depth limits still use Limit(depth=X)go depth X.
# Before: Limit(depth=None) is truthy → bare "go"
limit = chess.engine.Limit(depth=self.max_depth if self.max_depth != MAX_DEPTH else None)

# After: None is falsy → "go infinite"
limit = (chess.engine.Limit(depth=self.max_depth)
         if self.max_depth != MAX_DEPTH else None)
  • Guard engine.play() fallback against None limit — The bestmove fallback path now also checks limit is not None to avoid passing None to engine.play().

  • Skip engine.play() fallback when killed (prior commit) — After _kill.set(), RunEngine.run() was falling through to engine.play(board, Limit(depth=None)) which blocked the thread indefinitely. Now skipped when the kill signal is set.

  • Non-blocking review navigation with debounce (prior commit) — Navigation signals the analysis thread to stop without blocking on join(). The actual restart is deferred via a 300ms debounce in the timeout handler, keeping the GUI responsive during rapid navigation.

Copilot AI and others added 4 commits March 29, 2026 03:01
When analysis is running and the user presses navigation buttons rapidly,
stop the analysis immediately but defer restarting it until 300ms after
the last button press. This avoids repeated blocking engine stop/start
cycles that make the GUI unresponsive.

Agent-Logs-Url: https://github.com/fsmosca/Python-Easy-Chess-GUI/sessions/71d680e7-f5da-483b-86f3-c7daf8a96f24

Co-authored-by: fsmosca <22366935+fsmosca@users.noreply.github.com>
Replace blocking stop_review_analysis() on navigation press with
non-blocking search.stop() signal. The join+restart is deferred to the
debounce handler which fires 300ms after the last button press, by which
time the old thread has already exited.

Also skip stale analysis messages from the old position during debounce
to prevent incorrect UI updates.

Agent-Logs-Url: https://github.com/fsmosca/Python-Easy-Chess-GUI/sessions/0e57255b-5a2d-4189-9dc6-ce5b07d5f43f

Co-authored-by: fsmosca <22366935+fsmosca@users.noreply.github.com>
When the analysis thread is interrupted via _kill.set(), if no bestmove
was found yet (bm is None), RunEngine.run() falls through to
engine.play(board, Limit(depth=None)) — an unconstrained synchronous
call that blocks the thread indefinitely. This makes join() hang and
freezes the GUI.

Fix: skip the engine.play() fallback when _kill is set, and also make
the move delay loop respect the kill signal.

Agent-Logs-Url: https://github.com/fsmosca/Python-Easy-Chess-GUI/sessions/225e88fb-0a7d-479d-8208-22d1eb8867e0

Co-authored-by: fsmosca <22366935+fsmosca@users.noreply.github.com>
python-chess's engine.analysis() checks `if limit:` to decide whether
to send 'go infinite'. Since Limit() with all-None fields is a truthy
dataclass instance, passing Limit(depth=None) caused python-chess to
send bare 'go' without the 'infinite' token. The engine received 'go'
with no parameters and sat idle.

Fix: pass limit=None (not Limit()) for tc_type='infinite' with no
depth constraint, so python-chess takes the else branch and sends
'go infinite'. Also guard the engine.play() fallback against limit=None.

Agent-Logs-Url: https://github.com/fsmosca/Python-Easy-Chess-GUI/sessions/d96d5ff9-9d28-43b2-bd39-3600dbd677ec

Co-authored-by: fsmosca <22366935+fsmosca@users.noreply.github.com>
@fsmosca fsmosca marked this pull request as ready for review March 29, 2026 04:02
@fsmosca fsmosca merged commit 3818962 into master Mar 29, 2026
@fsmosca fsmosca deleted the copilot/fix-unresponsive-gui-buttons branch March 29, 2026 04:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants