**TerminalUI Coverage Fix:**
- Added explicit test for empty input case (lines 64-65 previously uncovered)
- Test "TerminalUI should explicitly handle empty input by re-prompting" validates
that multiple empty inputs are properly handled by re-prompting
- UI module coverage improved to near-100%
**MoveCommand Immutability (Anti-pattern Fix):**
- Changed MoveCommand fields from var to val: moveResult, previousBoard,
previousHistory, previousTurn
- Changed ResetCommand fields from var to val: previousBoard, previousHistory,
previousTurn
- Updated GameEngine to use .copy() instead of direct mutation when updating
command state (lines 88, 95, 103, 112)
- Removed 3 edge-case tests that relied on command mutation (now impossible with
immutable fields)
**MoveCommand Immutability Tests:**
- Added MoveCommandImmutabilityTest to verify:
- Fields cannot be mutated after creation
- equals/hashCode respect immutability invariant
- .copy() creates new instances with updated values
All tests pass; 100% core coverage maintained.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Test-driven fixes for code review blockers NCS-16:
**Observable (CRITICAL):** Added synchronized blocks to subscribe, unsubscribe,
notifyObservers, and observerCount to prevent race conditions when concurrent
threads register observers while notifications are dispatched.
**CommandInvoker (IMPORTANT):** Added synchronized blocks to all methods
(execute, undo, redo, history, getCurrentIndex, canUndo, canRedo, clear) to
ensure atomic access to mutable state (executedCommands, currentIndex).
Tests:
- Added ObservableThreadSafetyTest: 3 tests for concurrent subscribe/unsubscribe/notify
- Added CommandInvokerThreadSafetyTest: 2 tests for concurrent execute/undo/redo
- All 54 existing tests remain green
- Full build passes with 100% core coverage
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Implements PgnParser with parsePgn(), parseAlgebraicMove(), and move
resolution using geometric piece reachability with disambiguation support
for piece type, file, and rank hints.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Implements parseFen() in FenParser and gameStateToFen() in FenExporter,
covering all 6 FEN fields (piece placement, active color, castling,
en passant, half-move clock, full-move number).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements FenParser.parseBoard() to parse FEN piece-placement strings
into a Board, with proper None propagation on invalid input.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>