full diff

at.kotoba.lesson.pack

kotoba.at +4 −0
From
bafyreigaixd5iwr5bjs2mrtgmpfs2i7as63hez5b5rce6jbgp6jb6r3ygq indexed 2026-09-16 19:18 UTC View this version
To
bafyreifyevncz6ko6kifbdq77dgdjqxtfpcndqyztgdtdrbkxcemcyve5y indexed 2026-10-15 09:08 UTC View this version

Compatibility

backward compatible Backward compatible. 2 non-breaking changes.

Non-breaking changes (2)
  • AddedVertex AddedVertex { vertex_id: "at.kotoba.lesson.pack#item.ruby" }
  • AddedEdge AddedEdge { src: "at.kotoba.lesson.pack#item", tgt: "at.kotoba.lesson.pack#item.ruby", kind: "prop", name: Some("ruby") }

Migration guidance

Added

  • AddedVertex { vertex_id: "at.kotoba.lesson.pack#item.ruby" }

Notes

  • Non-breaking: AddedEdge { src: "at.kotoba.lesson.pack#item", tgt: "at.kotoba.lesson.pack#item.ruby", kind: "prop", name: Some("ruby") }

Changes

11{
22 "$type": "com.atproto.lexicon.schema",
33 "defs": {
44 "defaults": {
55 "description": "Pack-level drill defaults (SPEC §4). Open additional keys round-trip via the pack `meta`.",
66 "properties": {
77 "katakanaMultiplier": {
88 "description": "Queue weight multiplier for katakana. Fixed-point ×10000 (e.g. 1.5 -> 15000); no float type.",
99 "type": "integer"
1010 },
1111 "tapToTypeBox": {
1212 "description": "Leitner box at/above which a glyph may graduate tap -> type.",
1313 "maximum": 5,
1414 "minimum": 1,
1515 "type": "integer"
1616 }
1717 },
1818 "type": "object"
1919 },
2020 "forms": {
2121 "description": "Authored conjugation surfaces, keyed by the form names in src/drill/conjugate.ts. Kana only — the kanji surface is derived from the item's `kanji` form. A key this build does not know is ignored, so a form added later needs no lexicon change.",
2222 "properties": {
2323 "chau": {
2424 "type": "string"
2525 },
2626 "imperative": {
2727 "type": "string"
2828 },
2929 "masu": {
3030 "type": "string"
3131 },
3232 "nai": {
3333 "type": "string"
3434 },
3535 "nakatta": {
3636 "type": "string"
3737 },
3838 "nakya": {
3939 "type": "string"
4040 },
4141 "potential": {
4242 "type": "string"
4343 },
4444 "ta": {
4545 "type": "string"
4646 },
4747 "te": {
4848 "type": "string"
4949 },
5050 "teru": {
5151 "type": "string"
5252 },
5353 "toku": {
5454 "type": "string"
5555 },
5656 "volitional": {
5757 "type": "string"
5858 }
5959 },
6060 "type": "object"
6161 },
6262 "item": {
6363 "description": "A card. A discriminated union on `type` (#1), flattened into one object because lexicons have no oneOf: a RECOGNITION item (hiragana | katakana | kanji | word) requires glyph + romaji, a GRAMMAR item (particle | contraction | usage | sentence) requires id + prompt + answer. `conjugation` is a RECOGNITION type (#146): a derived verb surface, so it carries glyph + romaji like any word. Only `type` can be required here; the per-branch requiredness is enforced by lessons/pack.schema.json (JSON Schema if/then) and src/packs/validate.ts, which is what every reader of this record already routes through.",
6464 "properties": {
6565 "accept": {
6666 "description": "GRAMMAR branch, optional. Alternative answers graded correct beside `answer` — casual forms routinely have two natural ones. Exact-match grading is unchanged; the accepted set just has more members.",
6767 "items": {
6868 "type": "string"
6969 },
7070 "type": "array"
7171 },
7272 "answer": {
7373 "description": "GRAMMAR branch, required there. The one canonical answer; graded by exact compare after trim.",
7474 "type": "string"
7575 },
7676 "choices": {
7777 "description": "GRAMMAR branch, optional. Authored options for the choice grid (#145); contains `answer` when present. Never empty — the app drops an empty or wrong-typed list at the upload boundary rather than writing one.",
7878 "items": {
7979 "type": "string"
8080 },
8181 "type": "array"
8282 },
8383 "confusableWith": {
8484 "description": "ROMAJI (not glyphs) of same-script confusers; cold-start distractor seed.",
8585 "items": {
8686 "type": "string"
8787 },
8888 "type": "array"
8989 },
9090 "forms": {
9191 "description": "Authored kana surfaces for the forms no rule derives (#136) — an irregular's whole paradigm, or one form of an otherwise regular verb (iku's itte). A form with no entry falls back to the derivation.",
9292 "ref": "#forms",
9393 "type": "ref"
9494 },
9595 "gloss": {
9696 "description": "English meaning; recommended for words/kanji, and for a grammar item it is the meaning of the whole line.",
9797 "type": "string"
9898 },
9999 "glyph": {
100100 "description": "RECOGNITION branch, required there. 1+ chars: single kana, word, or kanji.",
101101 "type": "string"
102102 },
103103 "group": {
104104 "description": "Verb conjugation class (#136): 1 godan, 2 ichidan, 3 irregular. Word items only. The app derives every form from it (src/drill/conjugate.ts) instead of the pack authoring them.",
105105 "maximum": 3,
106106 "minimum": 1,
107107 "type": "integer"
108108 },
109109 "id": {
110110 "description": "GRAMMAR branch, required there and unique within the pack. The SRS state map is glyph-keyed and a grammar item has no glyph, so it is keyed `grammar:<id>` (#145). Uniqueness is enforced by validate.ts, not here.",
111111 "type": "string"
112112 },
113113 "kanji": {
114114 "description": "Written form in kanji (or kanji + okurigana) of a kana word — にほんじん -> 日本人. The below-hint path is passive (#125); a usable ruby meaning prompt records the separate kanji-recognition lane (#171). Omit where there is no kanji form (gairaigo) or the word is normally written in kana.",
115115 "type": "string"
116116 },
117117 "meta": {
118118 "description": "Item-level open extension; UI ignores, round-trips.",
119119 "type": "unknown"
120120 },
121121 "prompt": {
122122 "description": "GRAMMAR branch, required there. The sentence, with the blank written by the author (U+FF3F). Opaque to this layer: it may carry `{kanji|kana}` ruby markup (#139).",
123123 "type": "string"
124124 },
125125 "romaji": {
126126 "description": "RECOGNITION branch, required there. Expected reading; lowercase Hepburn, exact case-insensitive match.",
127127 "type": "string"
128128 },
129129 "row": {
130130 "description": "Gojuon row label, single kana and combination kana (yoon + extended) only.",
131131 "type": "string"
132132 },
133 "ruby": {
134 "description": "Optional authored furigana boundaries for a recognition item, using `{base|reading}` markup. Used only when it reconstructs the plain `kanji` form and `glyph` reading; unusable markup falls back safely.",
135 "type": "string"
136 },
133137 "type": {
134138 "description": "Open. Recognition: hiragana | katakana | kanji | word | conjugation (#146, a derived verb surface). Grammar (#1): particle | contraction | usage | sentence.",
135139 "type": "string"
136140 },
137141 "weight": {
138142 "description": "Optional author priority override. Fixed-point ×10000 (e.g. 1.8 -> 18000); lexicons have no float type. App scales at the record edge (see README).",
139143 "type": "integer"
140144 }
141145 },
142146 "required": [
143147 "type"
144148 ],
145149 "type": "object"
146150 },
147151 "main": {
148152 "description": "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 interchange shape (lessons/pack.schema.json).",
149153 "key": "tid",
150154 "record": {
151155 "properties": {
152156 "createdAt": {
153157 "description": "ISO 8601. NOTE: the app currently stamps a date-only string (YYYY-MM-DD), not a datetime — left unformatted here pending reconciliation (see README).",
154158 "type": "string"
155159 },
156160 "defaults": {
157161 "ref": "#defaults",
158162 "type": "ref"
159163 },
160164 "items": {
161165 "items": {
162166 "ref": "#item",
163167 "type": "ref"
164168 },
165169 "type": "array"
166170 },
167171 "meta": {
168172 "description": "Pack-level open extension; UI ignores, round-trips.",
169173 "type": "unknown"
170174 },
171175 "phase": {
172176 "description": "Open. kana | vocab | grammar.",
173177 "type": "string"
174178 },
175179 "rationale": {
176180 "type": "string"
177181 },
178182 "script": {
179183 "description": "Declared scripts; drives chips + Focus. The scripts the glyphs are WRITTEN in — for a `word` item that is its kana script, not \"word\" (#99). Derived the same way if omitted; a word that is unsegmentable or mixes both kana falls back to \"word\". A declared script is cleaned by the app (#99): \"word\", junk and duplicates are dropped and the rest kept; \"word\" returns only if derivation finds an item with no derivable script.",
180184 "items": {
181185 "type": "string"
182186 },
183187 "type": "array"
184188 },
185189 "title": {
186190 "type": "string"
187191 }
188192 },
189193 "required": [
190194 "title",
191195 "items"
192196 ],
193197 "type": "object"
194198 },
195199 "type": "record"
196200 }
197201 },
198202 "id": "at.kotoba.lesson.pack",
199203 "lexicon": 1
200204}

Compare other versions