2026-09-23·by Sijie Wang#lucerna#software#architecture

vocabulary-loop

The vocabulary loop (tap → lookup → save → underline → review)

Parent: key-designs

The product's core loop. Each stage is concrete in code.

1. Tap a word → 3-tier lookup (usecases/lookupWord.ts, useLookup.ts).

  • L1 IndexedDB DictCache (instant, offline);
  • L2 the mainbackend global dictionary (DictionaryApi/api/v1/dictionary/entries) — a shared cache across all users;
  • L3 the user-configured LLM (api/llmLookup.ts, llmLookupBasic, temp 0.1) — word/lemma/POS/meaning/nounInfo. On an L3 hit it writes back to L1+L2 fire-and-forget, so the next reader who taps the same word pays nothing.

2. Verb enrichment (lazy, async) — if the POS is a verb, llmLookupVerbTable fills the conjugation grid and services/verbForms.ts harvests every conjugated form + the participle, appending them to the L2 dictionary. So future lookups of any conjugation hit the cache, not the LLM.

3. Save (usecases/markWordFromLookup.ts) — builds a VocabularyEntry: noun lemmas are gender-prefixed (der Kopf), the click is located to a book-absolute rawStart (via the dual-coordinate map — raw-display-cursor), and paragraph-level context is captured (paragraph → sentence → page-substring fallback) for the flashcard.

4. Underline everywhere — on book open, loadBookVocabulary paints cache-first then revalidates, and runs the all-forms migration (vocabFormsMigration): group entries by bookId::lemma, keep the earliest survivor (preserving SRS history), resolve the complete form-set (LLM first, dict fallback), rewrite word→lemma, delete duplicates — idempotent, concurrency-guarded. Then all-forms-underline paints every form.

5. Review — server-owned SRS. The client only sends a grade ('dont_know' | 'fuzzy' | 'know') to /reviews; the actual SM-2 lives in Go (mainbackend/internal/domain/review/srs.go — ease deltas −0.2/−0.15/+0.1 clamped ≥1.3, dont_know→1 day, know 1→6→×ease, grade validated server-side). Putting the algorithm on the server means the schedule is consistent across web and desktop and can't be gamed by a stale client.

The loop is why "intensive reading" works: reading produces graded vocabulary, and saved vocabulary feeds back into the reading surface as ambient underlines.

about this entry

One of sijie's wiki entries. The AI on this site is grounded in the same corpus and answers in sijie's voice, with citations back to entries like this one — answering costs sijie money, so it waits behind a code: enter an access code →