Source data wraps every math fragment in display-mode $$ delimiters,
which KaTeX rendered as centered blocks mid-sentence. scripts/fix_math.py
normalizes the corpus: $$/$ pairs become inline \\(...\\) (block
derivations with newlines or environments stay display), legacy
\\matrix blocks become begin/end matrix, _\\limits/^\\limits,
\\raise/\\lower boxes, \\root/\\of, \\tag and \\, are rewritten
to KaTeX-supported forms. Batch-validated 60k inline spans: 99.98% render
clean; remaining handful are source pathologies that degrade to text.
import_examgoal.py runs the same normalization at write time.
import_examgoal.py required /tmp/pyqeval helper modules that were never
committed, so it failed on any fresh machine. The two upstream model
files now live in scripts/examgoal_model/ (relative import fixed) and
the default pickle path is scripts/examgoal_db.pkl.
scripts/import_examgoal.py pulls the MIT-licensed examgoal-derived
14,973-question pickle and keeps the 9,813 fully-text MCQs with single
correct answers (2002-2025, all subjects). chapterGroup becomes our
chapter, chapter slug becomes our subtopic. Idempotent: skips stems
already present.
views.rs gains rich() — a read-side sanitizer matching the importer's
allowlist — and all six stem/option/solution render sites use it.
KaTeX auto-render (trust:false) added to head() for $$..$$ math.
db.rs gains nine CREATE INDEX statements; the chapter loader query
drops from ~5s to 6ms on the 9.8k-question bank. DATA.md rewritten
around the real pipeline with attribution.