at.kotoba.session

kotoba.at

{
  "$type": "com.atproto.lexicon.schema",
  "defs": {
    "card": {
      "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).",
      "properties": {
        "answer": {
          "description": "What the user answered. Optional: may be absent on a skip/timeout (app-side `given` is nullable).",
          "type": "string"
        },
        "correct": {
          "type": "boolean"
        },
        "distractors": {
          "description": "The other options offered beside the answer: romaji on a tap card, English glosses on a meaning card. Absent for type, which has no grid.",
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "glyph": {
          "description": "The item's SRS state key: the prompt glyph for a recognition card, `grammar:<id>` for a grammar one (which has no glyph).",
          "type": "string"
        },
        "mode": {
          "description": "How the card was answered. tap = pick the romaji reading, type = write it out, meaning = pick the English gloss (a word, or a derived verb form — see `type`), choice = pick the answer to a grammar prompt from its authored options.",
          "knownValues": [
            "tap",
            "type",
            "meaning",
            "choice"
          ],
          "type": "string"
        },
        "parseMs": {
          "description": "render -> first response/keystroke.",
          "type": "integer"
        },
        "totalMs": {
          "description": "render -> submit (tap: == parseMs).",
          "type": "integer"
        },
        "ts": {
          "format": "datetime",
          "type": "string"
        },
        "type": {
          "description": "Open string; matches the pack item's type. `conjugation` is a de-conjugation card (#146) — a verb form derived at session time rather than authored in the pack, keyed on the conjugated surface.",
          "type": "string"
        }
      },
      "required": [
        "glyph",
        "type",
        "mode",
        "correct",
        "parseMs",
        "totalMs",
        "ts"
      ],
      "type": "object"
    },
    "config": {
      "description": "The setup choices that drove the session (enables Drill-again + analytics slicing).",
      "properties": {
        "cardStyle": {
          "description": "Open. genko | hanko | ma.",
          "type": "string"
        },
        "focus": {
          "description": "Open. all | hiragana | katakana.",
          "type": "string"
        },
        "length": {
          "description": "10 | 20 | full-count.",
          "type": "integer"
        },
        "recall": {
          "description": "Open. tap | mixed | type | meaning | read (type + meaning).",
          "type": "string"
        }
      },
      "required": [
        "length",
        "focus",
        "recall",
        "cardStyle"
      ],
      "type": "object"
    },
    "main": {
      "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).",
      "key": "tid",
      "record": {
        "properties": {
          "cards": {
            "items": {
              "ref": "#card",
              "type": "ref"
            },
            "type": "array"
          },
          "config": {
            "ref": "#config",
            "type": "ref"
          },
          "endedAt": {
            "format": "datetime",
            "type": "string"
          },
          "packRef": {
            "description": "at:// URI of the lesson.pack record that drove this session.",
            "format": "at-uri",
            "type": "string"
          },
          "rollup": {
            "ref": "#rollup",
            "type": "ref"
          },
          "startedAt": {
            "format": "datetime",
            "type": "string"
          }
        },
        "required": [
          "startedAt",
          "endedAt",
          "cards",
          "rollup"
        ],
        "type": "object"
      },
      "type": "record"
    },
    "rollup": {
      "description": "Precomputed so range scans avoid touching the per-card array.",
      "properties": {
        "byType": {
          "description": "Map keyed by type string -> { n, correct }. `unknown` because lexicons have no dynamic-key map type (see README).",
          "type": "unknown"
        },
        "correct": {
          "type": "integer"
        },
        "medianParseMs": {
          "type": "integer"
        },
        "n": {
          "type": "integer"
        }
      },
      "required": [
        "n",
        "correct",
        "medianParseMs"
      ],
      "type": "object"
    }
  },
  "id": "at.kotoba.session",
  "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
bafyreiau2yszseeyy6qssxivgavbwnnr7ngyt6hnleugrmldfdiestnqg4
Indexed At
2026-09-08 19:36 UTC
AT-URI
at://did:plc:o5f3cgna5sku4p6iitld6mxs/com.atproto.lexicon.schema/at.kotoba.session

Version History (2 versions)

Similar Lexicons

Lexicons whose schemas describe something close to this one. Check them before publishing a new one that overlaps.

  • Lesson content the app drills. Append-only stack; latest = active. Free-form by design: a known core the UI reads + open `meta`/`defaults` round-tripped untouched (SPEC §3.1a). This record body IS the upload interchang…

  • A finished study session. Written once; the source of study history and activity stats.

Lexicon Garden

@