feat(social): hide social controls on a deleted opponent's seat #286

Merged
developer merged 1 commits from feature/deleted-seat-social into development 2026-07-27 15:15:00 +00:00
Owner

Once an opponent deletes their account, their seats stay in every shared game — so the scoreboard still offered add-friend and block (deletion drops the friendship, so the 🤝 even came back for a former friend) and a chat composer with nobody behind it. A friend request sent that way was accepted and stayed pending forever.

  • SeatView.deleted (trailing FBS field, backward-compatible) + seat.deleted in the backend DTO / gateway DTO, resolved beside the seat display names by a batch accounts.deleted_at lookup (account.Store.DeletedIDs).
  • The client hides add-friend, block and the chat composer (message + nudge, once no reachable opponent is left) for such a seat. Live events carry the game domain's seat standings and leave the mark unset, so the delta reducers preserve the cached one.
  • SendFriendRequest and Block against a tombstone return social.ErrAccountDeleted (410 account_deleted) — the source of truth for an older client.

Also checked (no change needed): deleting an account on the opponent's turn ends the game correctly — Service.Resign deliberately skips the turn check and engine.ResignSeat only advances the cursor when the resigner was to move; covered by TestResignOnOpponentTurn.

Tests: new integration tests for the refusals and for the seat mark over /games/:id/state; gateway transcode + UI codec assert the new field; new gamedelta unit tests for mark preservation. Full local run green — go build/vet/gofmt, go test, -tags=integration backend suite, svelte-check, vitest (652), vite build.

Once an opponent deletes their account, their seats stay in every shared game — so the scoreboard still offered add-friend and block (deletion drops the friendship, so the 🤝 even came back for a former friend) and a chat composer with nobody behind it. A friend request sent that way was accepted and stayed pending forever. - `SeatView.deleted` (trailing FBS field, backward-compatible) + `seat.deleted` in the backend DTO / gateway DTO, resolved beside the seat display names by a batch `accounts.deleted_at` lookup (`account.Store.DeletedIDs`). - The client hides add-friend, block and the chat composer (message + nudge, once no reachable opponent is left) for such a seat. Live events carry the game domain's seat standings and leave the mark unset, so the delta reducers preserve the cached one. - `SendFriendRequest` and `Block` against a tombstone return `social.ErrAccountDeleted` (410 `account_deleted`) — the source of truth for an older client. Also checked (no change needed): deleting an account **on the opponent's turn** ends the game correctly — `Service.Resign` deliberately skips the turn check and `engine.ResignSeat` only advances the cursor when the resigner was to move; covered by `TestResignOnOpponentTurn`. Tests: new integration tests for the refusals and for the seat mark over `/games/:id/state`; gateway transcode + UI codec assert the new field; new gamedelta unit tests for mark preservation. Full local run green — go build/vet/gofmt, go test, `-tags=integration` backend suite, svelte-check, vitest (652), vite build.
developer added 1 commit 2026-07-27 15:06:29 +00:00
feat(social): hide social controls on a deleted opponent's seat
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 29s
CI / integration (pull_request) Successful in 20s
CI / ui (pull_request) Successful in 1m17s
CI / conformance (pull_request) Successful in 11s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m49s
9471341a0e
A deleted account keeps its seats in every shared game, so its opponents
still saw the add-friend and block controls on the scoreboard (deletion
drops the friendship, so the 🤝 even reappeared for a former friend) and
a chat composer nobody was behind. A friend request sent that way was
accepted by the server and stayed pending forever.

The per-viewer game views now mark such a seat (SeatView.deleted,
resolved beside the seat display names by a batch accounts.deleted_at
lookup) and the client hides every control aimed at it: add-friend,
block, and the chat composer (message + nudge) once no reachable
opponent is left. Live events carry the game domain's seat standings and
so leave the mark unset, so the delta reducers preserve the cached one.
SendFriendRequest and Block against a tombstone are refused with
social.ErrAccountDeleted (410 account_deleted) — the source of truth for
an older client.
owner approved these changes 2026-07-27 15:14:40 +00:00
developer merged commit 6ec557d33f into development 2026-07-27 15:15:00 +00:00
developer deleted branch feature/deleted-seat-social 2026-07-27 15:15:00 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: developer/scrabble-game#286