c01244c850
The "Promote pawn" dialog popped for any pawn "moved" toward the last rank: the commit paths checked piece type + destination rank but never the pawn's SOURCE rank. With the phantom layer now filling ranks 7-8 with tappable phantom pieces, tapping one (which falls through to the real-move handler) while a real pawn was armed triggered the dialog for a move no pawn could make — and for any phantom type, not just pawns. Root cause: incomplete promotion detection, duplicated in Game.svelte `onCommit` and the server's `isPromotionRequired`. Replaced with one shared `isPromotionMove(piece, from, to)` — pawn, from the rank adjacent to promotion, to the promotion rank, at most one file over — used by both. 7 unit tests in packages/shared. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>