- Remove stock_recycled field: recycling is now unlimited; StockEmpty only when both stock and waste are empty
- Replace all .unwrap() in draw() and move_cards() with .ok_or(MoveError::...)? propagation
- Push snapshot before recycling waste→stock so undo can reverse it
- Make StateSnapshot private (struct, not pub struct) and undo_stack private (not pub(crate))
- Add PartialEq, Eq to derives on both StateSnapshot and GameState
- Update draw_from_empty_stock_and_waste_returns_error test to use direct pile clearing since unlimited recycling means the old loop-based approach never reached both-empty
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements PileType/Pile, MoveError (thiserror), Deck with seeded shuffle,
deal_klondike layout, foundation/tableau placement rules, and Windows XP
Standard scoring — 41 tests, clippy clean.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>