Challenges

Direct vs standing (open)

Type standing flag Storage Visibility
Direct false CHALLENGE + user challenges_issued / challenges_received Named challengees only
Standing (open) true STANDINGCHALLENGE#<metaGame> + user challenges_standing Listed publicly per game

Direct challenges send email/push to challengees. Standing challenges appear on the open-challenges list for a metaGame.

SDG-style standing (REALSTANDING)

Separate from per-challenge standing records: REALSTANDING / <userid> stores a user's standing-request preferences (which games they want open challenges for, with optional limits). Updated via update_standing.

Flow

  1. Issue — new_challenge with challenger, challengees (direct), variants, clocks, etc.
  2. List open — standing_challenges per metaGame, or all_standing_challenges site-wide (public unfiltered; auth filters blocked issuers).
  3. Respond — challenge_response accept/decline; accepted players join players list.
  4. Revoke — challenge_revoke by challenger (cancels the whole challenge).
  5. Game start — when enough players accept, a GAME record is created.

Multi-player seats (numPlayers > 2)

Challenges track openSlots: seats anyone may fill (listed on open challenges when openSlots > 0 on a direct challenge). Named invitees stay on challengees until they accept or decline.

Standing challenges for two-player games support a duration field: 0 = indefinite; >0 = expires after that many acceptances.

Player blocking interaction

Blocking affects open challenges only:

See Player blocking.

Direct-challenge opt-out

Users may set settings.all.noDirectChallenges to true (dashboard checkbox; stored via update_user_settings). When a direct challenge names a human challengee who opted out:

Open/standing challenges and the player block list are not affected.

Teaching mode

Optional teachingMode: true on new_challenge (direct and standing). Teaching games are cooperative review sessions: either player can offer the opponent a chance to keep or undo the last completed ply batch during play (see Games and moves — teaching RPCs).

Rule Server behaviour
Two players only Rejected when numPlayers !== 2.
Non-simultaneous Rejected when the meta-game has the simultaneous flag or a simultaneous turnModel(). Allowed turn models: sequential, sequenced, skip-turn.
Unrated rated is forced to false on issue even if the client sends rated: true.
No bots Rejected when the challenger or any challengee is a bot id.
Persistence Stored on CHALLENGE / STANDINGCHALLENGE#* rows (and fillable direct projections). Copied to the GAME at start as teachingMode: true with rated: false.

Validation lives in lib/challenges/teachingModeEligible.ts. Tournaments, events, and solo games do not use this flag.

Bots

Bot challengees are notified via the bot-outbound queue (HTTPS webhook), not email. Bots respond via their endpoint; moves go through botQuery.

Record types

CHALLENGE / <challengeid>
STANDINGCHALLENGE#<metaGame> / <challengeid>
REALSTANDING / <userid>

User records hold sets: challenges_issued, challenges_received, challenges_accepted, challenges_standing.

Queries

Query Auth Purpose
new_challenge yes Create challenge
challenge_response yes Accept/decline
challenge_revoke yes Cancel
standing_challenges public / yes List open challenges for one metaGame
all_standing_challenges public / yes List all open standing challenges site-wide
challenge_details public Single challenge

Related