# Renderer validation

How TeXForm derives full, partial, and none renderer support: case generation, the three engines tested, and why partial happens.

https://texform.dev/docs/renderer-validation

Read this if you want to know what the **full**, **partial**, and **none** labels on [renderer support](https://texform.dev/latex/renderers) actually mean — how they are measured, against which engines, and why a command ends up **partial** rather than **full**.

## How support statuses are determined [#how-support-statuses-are-determined]

Support is measured by rendering, not by reading documentation. Each entry in the [knowledge base](https://texform.dev/docs/knowledge-base) carries an [argspec](https://texform.dev/docs/argspec) describing its argument structure. From that argspec, a set of test cases is generated and each case is rendered against three engines. The status for a renderer summarizes the outcome of an entry's **positive** cases — cases that are expected to render:

* **full** — every positive case rendered without error.
* **partial** — at least one positive case rendered and at least one failed.
* **none** — no positive case rendered, or the renderer does not recognize the entry.

Test cases are generated with a one-factor-at-a-time (OFAT) strategy: from each argspec, one case fills the required arguments and omits the optional ones, then further cases vary a single argument form at a time — enabling one optional argument, dropping the braces around a required argument, and so on. Varying one factor per case means a failure points at a specific argument form rather than a tangle of interacting ones.

This generation and three-renderer comparison is performed by `argspecs-validator`, an internal tool that is not open source. It reads the package specs, generates the OFAT cases, runs them through the three renderers, and writes the pass/fail results that this site's support data is built from.

## The renderers tested [#the-renderers-tested]

Three engines are exercised, chosen to span the common deployment targets for LaTeX math:

* **MathJax** (version 4) — the reference web renderer, with the package matching each entry enabled.
* **KaTeX** (version 0.16) — a faster web renderer with a smaller built-in command set and no per-package isolation, so its built-in commands are always active.
* **XeTeX** (TeX Live 2026) — a full TeX engine, run with only the packages mapped to the entry under test.

Validation is package-scoped: each entry is rendered against its own package's behavior, not against a runtime with every package loaded at once. A result therefore answers "does this entry match this package's behavior in this engine?" — not "what happens when every package is enabled together?"

## Why "partial" happens [#why-partial-happens]

A **partial** status means an entry works in one argument form but not another. The OFAT cases surface this because they probe each form independently. Common causes:

* **Bare-argument forms.** A renderer may accept `\rule{1pt}{1pt}` but reject the unbraced `\rule 1pt{1pt}`, so the braced cases pass and the bare case fails.
* **Optional-argument forms.** An optional argument that one engine does not implement fails only on the cases that exercise it, leaving the baseline case passing.
* **Spacing and box commands.** Length- or box-valued arguments are a frequent source of divergence between engines.

Negative cases — inputs an entry should reject, such as text injected into a math-only slot — are tracked separately and do not contribute to the support status.

## How XeTeX gaps should be read [#how-xetex-gaps-should-be-read]

Because XeTeX is validated in math mode with only the entry's own package mapped, some commands report **none** for XeTeX even though they render in a complete XeTeX document. Text-mode commands and commands that depend on packages outside the one under test fall into this category. The XeTeX column is a faithful report of the validation scope, not a claim that XeTeX cannot render the command in any context.

## Renderer versions and refresh [#renderer-versions-and-refresh]

The current data was produced with MathJax 4, KaTeX 0.16, and XeTeX from TeX Live 2026. The results are regenerated when the knowledge base or the validation tooling changes; the support data on this site reflects the most recent run rather than a fixed schedule.

## Source map [#source-map]

The `argspecs-validator` that generates and runs the OFAT cases is not open source, so there is no public path for the generator, the renderer harnesses, or the raw result files. What is public is the input it reads, in the [TeXForm repository](https://github.com/texform-dev/texform):

| Path                                        | What it defines                                                                                     |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `crates/texform-knowledge/resources/specs/` | The per-package argspecs that every generated test case is derived from.                            |
| `crates/texform-argspec/`                   | The signature language those argspecs are written in, including which argument forms exist to vary. |

## Related [#related]

- [Renderer support](https://texform.dev/latex/renderers) — The full, partial, and none statuses, per entry and engine.

- [The knowledge base](https://texform.dev/docs/knowledge-base) — Where the argspecs being validated come from.

- [Reading argspecs](https://texform.dev/docs/argspec) — The notation that decides which cases get generated.

