turboblitz/textinguisher
TeXtinguisher: a benchmark of real LaTeX compile errors Real LaTeX projects that fail to compile with a located error, paired (where a human fix exists) with the smallest SEARCH/REPLACE edit that makes them compile. Verifier: latexmk (TeX Live 2025/2026). Built by scripts/build_release.py; integrity in MANIFEST.json (rows, bytes, sha256 per file). Files file rows what texse_heldout.jsonl 287 TeX.SE single-file benchmark (question's MWE + accepted… See the full description on the dataset page: https://huggingface.co/datasets/turboblitz/textinguisher.
TeXtinguisher: a benchmark of real LaTeX compile errors
Real LaTeX projects that fail to compile with a located error, paired (where a human fix exists) with the smallest SEARCH/REPLACE edit that makes them compile. Verifier: latexmk (TeX Live 2025/2026). Built by scripts/build_release.py; integrity in MANIFEST.json (rows, bytes, sha256 per file).
Files
Row ids are unique; id names the project directory, doc the reference entry.
Row format
Common fields: id, doc, engine (pdflatex/xelatex/lualatex), error_lines (parsed {file, line, text}), license; non-skew rows add log_tail, prompt (the production fix prompt: error lines + source window + log tail), error_category. Skew rows are metadata only (no project directory, no prompt/log_tail/error_category): arxiv_id, year, hist_year, signature, first_error, missing_file, n_files.
- Single-file rows:
projects/<id>/main.texis the fixed document; applybreak_edits(replacesearchbyreplace, once, in order) to obtain the failing document.targetis the fix as<edit>SEARCH/REPLACE blocks. Pool rows have nobreak_edits/target; theirmain.texis the failing document. - Multi-file rows (
lane: project):projects/<id>/is the fixed project,file_editsbreak it,targetuses<edit file="...">blocks.promptis the project-context prompt (file tree + reported file);prompt_v1is the single-file prompt for the reported file only.reported_file,fix_files,changed_files,n_filesdescribe the row. - TeX.SE provenance:
question_id,question_url,title,tags,score,created,question_author({user_id, name, url}),license;answer_id/accepted_answer_id,answer_url,answer_author,answer_licenseonly when an answer was used (absent on 3641 pool rows). - GitHub provenance:
repo,repo_url,sha(fixing commit),parent_sha(failing state),url(commit),license.
Local absolute paths were rewritten: the project path to projects/<id>, other /Users/<name>/ prefixes to ~/. Absolute paths that remain are content of the posts themselves (e.g. \graphicspath{{/home/...}}).
How rows were mined and verified
- TeX.SE (
scripts/mine_texse.py,mine_texse2.py,mine_texse_pool.py,mine_texse_multi.py): from the archive.org data dumpstackexchange_20251231. A question qualifies if its body has a full\documentclass ... \end{document}MWE and reports an error (texse: a pasted! ...line;texse2: an error mention in title/body). The MWE must fail locally with an error located inmain.tex; the fix document (longest complete document in the accepted answer, else the top answer with score >= 2 fortexse2; otherwise a snippet) must compile clean. Diff capped at 6 hunks / 40 lines; edits must apply uniquely and round-trip exactly. Rows whose first error is a missing file/font/graphic or an engine mismatch (fontspec, Unicode engine) were dropped, so those classes are absent. Funnels and error histograms:data/texse_report.md,texse2_report.md,texse_pool_report.md,multi2_report.md. - GitHub multi-file (
scripts/mine_github_multi.py,mine_github_multi2.py): commit pairs where the parent fails with a located error and the child compiles, edits round-trip exactly, max 5 rows per repo. 13github_multirows were never re-verified locally and have no reference entry; they are not in this release (unlicensed anyway). - Splits: by question id (stratified by error category) for TeX.SE, by repo/question for multi-file, by arXiv id for skew. Held-out ids, question ids, repos and arXiv ids do not appear in any train or pool file (checked by
build_release.py --check, which also reports near-duplicates: Jaccard >= 0.9 on normalizedmain.texlines finds one,texse2_437213vs pool rowtexse2_pool_437217, a follow-up question). Note thattexse_heldoutover-represents rows that were probed before the split (not a random sample).
Metrics (scripts/run_eval.py)
- compiles (
fixed): the model's edits apply andlatexmkexits clean. Headline metric; the only one for pool and skew rows. - content kept (
del<=40inscripts/heldout_table.py): compiles and the edits remove at most 40 characters of non-comment content (fix_env.deleted_chars). A heuristic guard against "delete until it compiles"; it does not see content hidden by\iffalseor comment environments. - strict: compiles and the PDF text matches the reference (
refs.json): same page count and word-levelSequenceMatcherratio >= 0.985. Penalizes valid alternative fixes. On the verified subset (refs_verified.json,REFS=refs2_heldout.json scripts/heldout_table.py <set>) strict is a fair "exact fix" measure; on the rest, TeX.SE answers often rewrite the document, so strict under-counts correct minimal fixes. - exact: the patched source equals the human-fixed source. TeX.SE labels are whole answer documents, often restyled (28% of
texserows have >= 20 diff lines), soexact/strictunder-count correct minimal fixes; filter ondiff_linesfor a minimal-fix subset.
Licences and attribution
TeX.SE license is the question's; on 125 rows answer_license differs (78 newer, 47 older; each post carries its own ContentLicense). Fixed documents are derived from both posts: the TeX.SE portion is share-alike.
Excluded and why
github_forksrows (22; 7 were inmulti2_heldout): students' theses / CVs on templates, no licence on the fork author's text. Also removes the 3 CJK rows that are unfixable under the eval harness's engine choice.- GitHub rows with
licenseNone or NOASSERTION (97 of 131 non-fork GitHub rows). - arXiv sources (
skew*,multi_synth,project_*,eval,hard_eval*): arXiv's non-exclusive licence does not permit redistribution; skew rows keep the metadata fields listed under Row format. project_train_all.jsonl,project_eval.jsonl(Sundial user projects), distilled/teacher files, and everything undercorpus/not referenced above.refs.jsonfor skew rows does not exist (no clean baseline compile by construction).
Regenerating skew rows
scripts/gen_skew.py --target 200 --seed 3 (arXiv 2008-2018 single-root papers compiled under TeX Live 2025) and scripts/gen_skew_train.py (2010-2020 multi-file papers, historical TeX Live) download the sources from arXiv and rebuild corpus/arxiv_skew*/<arxiv_id>/files; match rows by arxiv_id. Every skew row is an organic failure (no planted error), so there is no ground-truth patch and only compiles applies.
Contact
Sundial (see repository)
