at.kotoba.session
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).
Details · record, key tid
| Kind | record |
|---|---|
| Record key | tid |
| Authority | kotoba.at |
| Indexed |
Checks
Validunlimited-stringdefs.card.properties.answerNo maxLength, maxGraphemes or format limits this string.unlimited-stringdefs.card.properties.distractors.itemsNo maxLength, maxGraphemes or format limits this string.unlimited-stringdefs.card.properties.glyphNo maxLength, maxGraphemes or format limits this string.unlimited-stringdefs.card.properties.modeNo maxLength, maxGraphemes or format limits this string.unlimited-stringdefs.card.properties.typeNo maxLength, maxGraphemes or format limits this string.unlimited-stringdefs.config.properties.cardStyleNo maxLength, maxGraphemes or format limits this string.unlimited-stringdefs.config.properties.focusNo maxLength, maxGraphemes or format limits this string.unlimited-stringdefs.config.properties.recallNo maxLength, maxGraphemes or format limits this string.
{
"$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
}