# org.lichess.puzzle.defs

> Published by [pds.dad](https://lexicon.garden/identity/did:plc:rnpkyqnmsw4ipey6eotbdnnf)

## Links

- [View on Lexicon Garden](https://lexicon.garden/lexicon/did:plc:rnpkyqnmsw4ipey6eotbdnnf/org.lichess.puzzle.defs)
- [Documentation](https://lexicon.garden/lexicon/did:plc:rnpkyqnmsw4ipey6eotbdnnf/org.lichess.puzzle.defs/docs)
- [Examples](https://lexicon.garden/lexicon/did:plc:rnpkyqnmsw4ipey6eotbdnnf/org.lichess.puzzle.defs/examples)

## Definitions

### `org.lichess.puzzle.defs#themeView`

**Type**: `object`

A puzzle theme with its display name and description.

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `key` | `string` | Yes | the theme identifier used in puzzle themes and the getRandom themes filter (e.g. "fork"). |
| `name` | `string` | Yes | the human-readable display name of the theme (e.g. "Fork"). |
| `description` | `string` | Yes | a sentence describing the theme. |

### `org.lichess.puzzle.defs#puzzleView`

**Type**: `object`

The shared representation of a chess puzzle returned by the puzzle queries.

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `id` | `string` | Yes | the id of the puzzle. |
| `fen` | `string` | Yes | the FEN string of the position before the opponent makes their move. |
| `moves` | `string` | Yes | the solution to the puzzle. All player moves of the solution are "only moves", i.e. playing any other move would considerably worsen the player position. An exception is made for mates in one: there can be several. Any move that checkmates should win the puzzle. |
| `gameId` | `string` | No | the unique identifier of the specific game and move the puzzle was extracted from. The game would be accessible at https://lichess.org/{GameId} |
| `rating` | `integer` | Yes | the Glicko-2 rating of the puzzle. |
| `themes` | `array` | No | a list of puzzle themes. |
| `nbPlays` | `integer` | No | the number of times a puzzle was played. |
| `popularity` | `integer` | No | a number between 100 (best) and -100 (worst), calculated as 100 * (upvotes - downvotes)/(upvotes + downvotes). Votes are weighted by various factors such as whether the puzzle was solved successfully or the solver's puzzle rating in comparison to the puzzle's. |
| `openingTags` | `array` | No | a list of openings. This is only set for puzzles starting before move 20. |
| `ratingDeviation` | `integer` | Yes | the Glicko-2 rating deviation of the puzzle. |

### `org.lichess.puzzle.defs#resultAttestation`

**Type**: `object`

The payload a puzzle service signs when it judges a ranked attempt: proof that the service verified playerMoves against the puzzle's solution with the given solved result. The signature over it is stored in the org.lichess.puzzle.attempt record's sig field; this object itself is never stored, since every field is recoverable from the attempt record and the repo it lives in. To verify: rebuild this object from the record (kind is the constant below; player is the DID of the repo the record lives in), encode it as canonical DAG-CBOR (sorted map keys), and check the record's sig — an unpadded base64url low-S ECDSA signature over the sha256 of those bytes — against the service DID's published atproto verification key.

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `kind` | `string` | Yes | always "org.lichess.puzzle.defs#resultAttestation"; domain-separates these signatures from anything else the service key signs. |
| `nonce` | `string` | Yes | nonce of the challenge this result resolves (the attempt record's nonce field). |
| `player` | `string` (did) | Yes | DID of the player the result belongs to — the repo the attempt record lives in. Binds the signature to its owner so it cannot be replayed into another player's repo. |
| `puzzle` | `string` | Yes | Lichess puzzle ID (the attempt record's puzzleId field). |
| `solved` | `boolean` | Yes | the server-judged result (the attempt record's solved field). |
| `service` | `string` (did) | Yes | DID of the service that judged the attempt (the attempt record's service field). |
| `playerMoves` | `string` | Yes | the solution line the player submitted, exactly as judged (the attempt record's playerMoves field). |

## Raw Schema

```json
{
  "id": "org.lichess.puzzle.defs",
  "defs": {
    "themeView": {
      "type": "object",
      "required": [
        "key",
        "name",
        "description"
      ],
      "properties": {
        "key": {
          "type": "string",
          "description": "the theme identifier used in puzzle themes and the getRandom themes filter (e.g. \"fork\")."
        },
        "name": {
          "type": "string",
          "description": "the human-readable display name of the theme (e.g. \"Fork\")."
        },
        "description": {
          "type": "string",
          "description": "a sentence describing the theme."
        }
      },
      "description": "A puzzle theme with its display name and description."
    },
    "puzzleView": {
      "type": "object",
      "required": [
        "id",
        "fen",
        "moves",
        "rating",
        "ratingDeviation"
      ],
      "properties": {
        "id": {
          "type": "string",
          "description": "the id of the puzzle."
        },
        "fen": {
          "type": "string",
          "description": "the FEN string of the position before the opponent makes their move."
        },
        "moves": {
          "type": "string",
          "description": "the solution to the puzzle. All player moves of the solution are \"only moves\", i.e. playing any other move would considerably worsen the player position. An exception is made for mates in one: there can be several. Any move that checkmates should win the puzzle."
        },
        "gameId": {
          "type": "string",
          "description": "the unique identifier of the specific game and move the puzzle was extracted from. The game would be accessible at https://lichess.org/{GameId}"
        },
        "rating": {
          "type": "integer",
          "description": "the Glicko-2 rating of the puzzle."
        },
        "themes": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "a list of puzzle themes."
        },
        "nbPlays": {
          "type": "integer",
          "description": "the number of times a puzzle was played."
        },
        "popularity": {
          "type": "integer",
          "maximum": 100,
          "minimum": -100,
          "description": "a number between 100 (best) and -100 (worst), calculated as 100 * (upvotes - downvotes)/(upvotes + downvotes). Votes are weighted by various factors such as whether the puzzle was solved successfully or the solver's puzzle rating in comparison to the puzzle's."
        },
        "openingTags": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "a list of openings. This is only set for puzzles starting before move 20."
        },
        "ratingDeviation": {
          "type": "integer",
          "description": "the Glicko-2 rating deviation of the puzzle."
        }
      },
      "description": "The shared representation of a chess puzzle returned by the puzzle queries."
    },
    "resultAttestation": {
      "type": "object",
      "required": [
        "kind",
        "service",
        "player",
        "puzzle",
        "nonce",
        "solved",
        "playerMoves"
      ],
      "properties": {
        "kind": {
          "type": "string",
          "const": "org.lichess.puzzle.defs#resultAttestation",
          "description": "always \"org.lichess.puzzle.defs#resultAttestation\"; domain-separates these signatures from anything else the service key signs."
        },
        "nonce": {
          "type": "string",
          "description": "nonce of the challenge this result resolves (the attempt record's nonce field)."
        },
        "player": {
          "type": "string",
          "format": "did",
          "description": "DID of the player the result belongs to — the repo the attempt record lives in. Binds the signature to its owner so it cannot be replayed into another player's repo."
        },
        "puzzle": {
          "type": "string",
          "description": "Lichess puzzle ID (the attempt record's puzzleId field)."
        },
        "solved": {
          "type": "boolean",
          "description": "the server-judged result (the attempt record's solved field)."
        },
        "service": {
          "type": "string",
          "format": "did",
          "description": "DID of the service that judged the attempt (the attempt record's service field)."
        },
        "playerMoves": {
          "type": "string",
          "description": "the solution line the player submitted, exactly as judged (the attempt record's playerMoves field)."
        }
      },
      "description": "The payload a puzzle service signs when it judges a ranked attempt: proof that the service verified playerMoves against the puzzle's solution with the given solved result. The signature over it is stored in the org.lichess.puzzle.attempt record's sig field; this object itself is never stored, since every field is recoverable from the attempt record and the repo it lives in. To verify: rebuild this object from the record (kind is the constant below; player is the DID of the repo the record lives in), encode it as canonical DAG-CBOR (sorted map keys), and check the record's sig — an unpadded base64url low-S ECDSA signature over the sha256 of those bytes — against the service DID's published atproto verification key."
    }
  },
  "$type": "com.atproto.lexicon.schema",
  "lexicon": 1
}
```
