Replace T1 immediate-apply semantics with a single-slot pending
queue (T2-ADR-1). On `modifier-profile.update` receipt the server
validates shape + layout legality, stashes the profile on
`Room.pendingProfile` with the proposer's token, and acks the
sender with a new `modifier-profile.queued` message. The actual
`reconcileProfileSwap` + version bump + `modifier-profile.updated`
broadcast now runs in `applyPendingProfileIfAny` after the next
successful `applyMove` — either player's move triggers it.
- `Room` gains `pendingProfile` and `pendingProposerToken`
(token-keyed for reconnect-safe NACK routing).
- `game-session.ts` exposes `setPendingProfile`,
`applyPendingProfile`, `clearPendingProfile`. Apply re-runs
`validateProfile` as defence in depth; rejections clear the
slot and surface the validator error code.
- New `modifier-profile.queued` wire schema (server\u2192client ack
carrying the expected post-apply version).
- Last-write-wins: a second update overwrites the pending slot
because the server's `profileVersion` only bumps on apply, so
the second request legitimately carries the same version.
- Existing early-rejection paths (non-host, stale version,
invalid profile) remain unchanged.
Tests updated: 7 scenarios covering queued ACK, deferred apply,
last-write-wins, opponent-move-drains-queue, and all original
rejection paths. 1220 unit tests + 18 modifier Playwright tests
green (e2e specs never used `modifier-profile.update` at
runtime so were unaffected).