at.kotoba.session

kotoba.at

{
  "id": "at.kotoba.session",
  "defs": {
    "card": {
      "type": "object",
      "required": [
        "glyph",
        "type",
        "mode",
        "correct",
        "parseMs",
        "totalMs",
        "ts"
      ],
      "properties": {
        "ts": {
          "type": "string",
          "format": "datetime"
        },
        "mode": {
          "type": "string",
          "knownValues": [
            "tap",
            "type"
          ]
        },
        "type": {
          "type": "string",
          "description": "Open string; matches the pack item's type."
        },
        "glyph": {
          "type": "string"
        },
        "answer": {
          "type": "string",
          "description": "What the user answered. Optional: may be absent on a skip/timeout (app-side `given` is nullable)."
        },
        "correct": {
          "type": "boolean"
        },
        "parseMs": {
          "type": "integer",
          "description": "render -> first response/keystroke."
        },
        "totalMs": {
          "type": "integer",
          "description": "render -> submit (tap: == parseMs)."
        },
        "distractors": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Tap mode only; the romaji offered. Absent for type."
        }
      },
      "description": "One answered card. `answer` is what the user produced (the correct reading is derivable by joining packRef+glyph; not stored, per SPEC ยง3.2)."
    },
    "main": {
      "key": "tid",
      "type": "record",
      "record": {
        "type": "object",
        "required": [
          "startedAt",
          "endedAt",
          "cards",
          "rollup"
        ],
        "properties": {
          "cards": {
            "type": "array",
            "items": {
              "ref": "#card",
              "type": "ref"
            }
          },
          "config": {
            "ref": "#config",
            "type": "ref"
          },
          "rollup": {
            "ref": "#rollup",
            "type": "ref"
          },
          "endedAt": {
            "type": "string",
            "format": "datetime"
          },
          "packRef": {
            "type": "string",
            "format": "at-uri",
            "description": "at:// URI of the lesson.pack record that drove this session."
          },
          "startedAt": {
            "type": "string",
            "format": "datetime"
          }
        }
      },
      "description": "One practice session: the full per-card interaction array, the config that drove it, and session-level rollups. Append-only stack; TID rkeys (time-ordered)."
    },
    "config": {
      "type": "object",
      "required": [
        "length",
        "focus",
        "recall",
        "cardStyle"
      ],
      "properties": {
        "focus": {
          "type": "string",
          "description": "Open. all | hiragana | katakana."
        },
        "length": {
          "type": "integer",
          "description": "10 | 20 | full-count."
        },
        "recall": {
          "type": "string",
          "description": "Open. tap | mixed | type."
        },
        "cardStyle": {
          "type": "string",
          "description": "Open. genko | hanko | ma."
        }
      },
      "description": "The setup choices that drove the session (enables Drill-again + analytics slicing)."
    },
    "rollup": {
      "type": "object",
      "required": [
        "n",
        "correct",
        "medianParseMs"
      ],
      "properties": {
        "n": {
          "type": "integer"
        },
        "byType": {
          "type": "unknown",
          "description": "Map keyed by type string -> { n, correct }. `unknown` because lexicons have no dynamic-key map type (see README)."
        },
        "correct": {
          "type": "integer"
        },
        "medianParseMs": {
          "type": "integer"
        }
      },
      "description": "Precomputed so range scans avoid touching the per-card array."
    }
  },
  "$type": "com.atproto.lexicon.schema",
  "lexicon": 1
}

Validate Record

Validate a record against at.kotoba.session

Validation Options
Treat any remaining unresolved references as valid

Metadata

DID
did:plc:o5f3cgna5sku4p6iitld6mxs
CID
bafyreibciaumajmfax5prw4njafg2v4fs4ezjcowrq6tsaf7dd2is4ztq4
Indexed At
2026-06-15 20:02 UTC
AT-URI
at://did:plc:o5f3cgna5sku4p6iitld6mxs/com.atproto.lexicon.schema/at.kotoba.session

Lexicon Garden

@