{
  "$type": "com.atproto.lexicon.schema",
  "defs": {
    "gridRow": {
      "description": "One guess row, encoded as tile-state codes only (never the letters).",
      "properties": {
        "row": {
          "description": "Exactly five tile-state codes, one per column: `G` = correct (right letter, right spot), `Y` = present (right letter, wrong spot), `B` = absent (not in the word). Example: `BGYBB`.",
          "maxLength": 5,
          "minLength": 5,
          "type": "string"
        }
      },
      "required": [
        "row"
      ],
      "type": "object"
    },
    "main": {
      "description": "An immutable record of one completed AT Mot daily puzzle, written to the player's own PDS. Write-once: no field may change after creation. The record key is deterministic, formatted as `<lang>-<puzzleNumber>` (e.g. `en-412`, `fr-7`), so each puzzle can be recorded at most once per account per language and re-solving cannot overwrite or spam. Stores tile colours only — never the answer or guessed letters — so index/firehose watchers cannot harvest answers and old records never spoil replays.",
      "key": "any",
      "record": {
        "properties": {
          "createdAt": {
            "description": "When the player finished the puzzle and the record was created.",
            "format": "datetime",
            "type": "string"
          },
          "grid": {
            "description": "The board as tile colours only, one element per guess row. Each element is an object (not a bare string) so context can be added later without a schema V2.",
            "items": {
              "ref": "#gridRow",
              "type": "ref"
            },
            "maxLength": 6,
            "type": "array"
          },
          "guessCount": {
            "description": "Number of guesses used. Present only when solved; absent on a loss (optional so a loss is representable without a sentinel value).",
            "maximum": 6,
            "minimum": 1,
            "type": "integer"
          },
          "lang": {
            "description": "BCP-47 language of the puzzle series (e.g. `en`, `fr`). Each language is an independent daily series.",
            "format": "language",
            "type": "string"
          },
          "puzzleDate": {
            "description": "UTC midnight datetime of the puzzle's calendar day.",
            "format": "datetime",
            "type": "string"
          },
          "puzzleNumber": {
            "description": "Per-language puzzle index = whole UTC days since the shared epoch (2026-06-23), +1. Launch day = 1.",
            "minimum": 1,
            "type": "integer"
          },
          "puzzleTarget": {
            "description": "The canonical per-(lang,day) permalink `https://atmot.herve.bzh/p/<lang>/<puzzleNumber>`. This is the link the Constellation backlink index aggregates to build the leaderboard. It is deliberately a synthetic web URL, NOT a com.atproto.repo.strongRef, because the puzzle is not itself a network record — this is intentional, and is exactly what lets Constellation index it as a backlink target. Format is frozen and compared literally; emit it only via the app's shared helper.",
            "format": "uri",
            "type": "string"
          },
          "solved": {
            "description": "Whether the player guessed the word within the allowed attempts.",
            "type": "boolean"
          }
        },
        "required": [
          "lang",
          "puzzleNumber",
          "puzzleDate",
          "solved",
          "puzzleTarget",
          "createdAt"
        ],
        "type": "object"
      },
      "type": "record"
    }
  },
  "id": "bzh.herve.atmot.result",
  "lexicon": 1
}
