# Glossary

TeXForm terminology in one place: profile, rule level, fidelity, SyntaxNode, Document, parse config, overlay, phase, and the contracts behind them.

https://texform.dev/docs/glossary

TeXForm's vocabulary is small but precise, and several terms look interchangeable until you need the difference — profile versus rule level, `SyntaxNode` versus `Document`, config versus overlay. Each entry below says what the term means and links to the page that defines it in context.

## Trees and documents [#trees-and-documents]

### `SyntaxNode` [#syntaxnode]

The lossless, immutable snapshot of a parse, and the single structured-data format in TeXForm. It is what you serialize to JSON, store, transport, or use as a test fixture; it carries no editing behavior. Python sees it as a plain dict, JavaScript as a plain object, Rust as a serde type. It may contain `Error` nodes, because a partial parse is still a legitimate snapshot. See [Pipeline](https://texform.dev/docs/pipeline#syntaxnode-is-the-wire-format-document-is-the-working-format).

### `Document` [#document]

The editable working tree, and the type nearly every API takes or returns. You query it with node handles, mutate it with validated edits, serialize it with `to_latex()`, and normalize it with the transform engine. A `Document` whose `has_errors()` is true is read-only, fixed that way at construction. See [Parsing](https://texform.dev/docs/parsing#what-parsing-gives-you) and [Edit a document](https://texform.dev/docs/edit-a-document).

### `Ast` [#ast]

The internal arena tree the serializer and the transform engine operate on. `Document` wraps it and exposes a fallible surface over it, which is why no internal panic reaches a caller. `Ast` is **not** part of the public API and is not reachable from Python or JavaScript at all; the name appears in phase names like FinalizeAst and in [Architecture](https://texform.dev/docs/architecture), nowhere else. You never construct or hold one.

### Text idempotency [#text-idempotency]

The serializer's formal guarantee that parsing its output and serializing it again in the same style produces the same string: `serialize(parse(serialize(parse(src)))) == serialize(parse(src))`. It is a text-level guarantee — the recovered tree need not be the identical tree kind — and it is what makes serialized output safe to use as a cache key, a deduplication key, or a diff input. It is not normalization: serialization never rewrites `a \over b` into `\frac{a}{b}`. See [Serialization](https://texform.dev/docs/serialization#text-idempotency).

## Parsing [#parsing]

### `ParseConfig`, lenient and strict [#parseconfig-lenient-and-strict]

The two knobs that decide how the parser reacts to trouble: `reject_unknown` for names the knowledge base does not recognize, and `abort_on_error` for syntax errors it cannot continue past. For both, `True` means stricter. **Lenient** is the corner where both are `False` — the default in every binding — and **strict** is the corner where both are `True`. Rust exposes those corners as the constants `ParseConfig::LENIENT` and `ParseConfig::STRICT`; Python and JavaScript express them through constructor defaults and per-call overlays instead, so there is no `ParseConfig.LENIENT` constant to import. See [Parsing](https://texform.dev/docs/parsing#configuring-strictness).

### Context item [#context-item]

A record you hand the parser to inject knowledge it does not have: a command, an environment, or a delimiter control, each with a name and an argspec. The parser then reads the item's arguments exactly as if it were built in. Context items add *parsing* knowledge only — they cannot add rewrite rules. See [Inject custom commands](https://texform.dev/docs/inject-custom-commands).

## The transform engine [#the-transform-engine]

### Profile [#profile]

Your choice of downstream use, and the only decision the engine requires: `Authoring`, `Faithful`, `Corpus`, or `Equiv`. A profile is fixed when you construct a `TransformEngine`, and it determines both which rules are active and the default per-phase switches. Profiles form a ladder rather than a quality dial — a stronger profile is not a better one, just a different target. See [Transforms](https://texform.dev/docs/transforms#pick-a-profile).

### `RuleLevel` [#rulelevel]

The level every rewrite rule belongs to, ordered `Authoring < Faithful < Corpus < Equiv`. A rule's level is the first profile that accepts the rule's output as a suitable product, and each profile runs its own level plus every level below it. This is what "a profile selects rules" means mechanically. See [What the engine guarantees](https://texform.dev/docs/transforms#what-the-engine-guarantees).

### `RuleFidelity` [#rulefidelity]

A rule's worst-case equivalence guarantee over its declared input domain, ordered `Math < Reading < Render`: `Render` means the rendering is equivalent, `Reading` means notation content, reading order, and structural roles survive, and `Math` means only mathematical meaning does. Fidelity is independent of level — a high-fidelity rule is not automatically an earlier-level rule — and it is a metadata contract, not a comparison the engine runs. See [Rules and the transform contract](https://texform.dev/docs/rule-contract).

### `RuleLevelSet` [#rulelevelset]

The set of rule levels a compiled engine has turned on, derived from the profile. It is the Rust-side representation of "which rules this engine will attempt". You do not set it directly; choosing a profile chooses it.

### Phase [#phase]

One stage of the transform pipeline: LowerAttributes, Rewrite, FinalizeAst, or FlattenGroups. The engine repeats LowerAttributes → Rewrite → LowerAttributes → FinalizeAst → FlattenGroups until all enabled phases reach a common fixed point. You can switch a phase off for a single run. Switching a phase off is not the same as changing rule levels: the profile's rule selection is compiled into the engine and a per-run switch cannot change it. See [Transforms](https://texform.dev/docs/transforms#the-pipeline).

### Overlay [#overlay]

A partial configuration merged onto a complete one. Every per-run config in the Python and JavaScript bindings is an overlay: you name only what you want to change, nested one level per phase — `rewrite={"enabled": False}` in Python, `{ rewrite: { enabled: false } }` in JavaScript — and everything you omit keeps the profile's value. An unknown key, or a Python-style key handed to the JavaScript binding, raises a configuration error rather than being ignored. See [Transforms](https://texform.dev/docs/transforms#switch-a-phase-off-with-an-overlay).

### Eliminated-form contract [#eliminated-form-contract]

Each rewrite rule declares the forms it eliminates — forms that must not appear anywhere in the engine's output. After every mutating phase has run, the engine checks the final tree and reports a surviving eliminated form as a hard transform error rather than a warning. The same contract is re-checked against real-world datasets through corpus regression, so a rule that fails to eliminate what it promised is caught on actual formulas. See [Rules and the transform contract](https://texform.dev/docs/rule-contract).

- [What TeXForm is](https://texform.dev/docs/what-is-texform) — The product boundary, in one page.

- [Transforms](https://texform.dev/docs/transforms) — Where profile, rule level, phase, and overlay all come together.

- [Rule reference](https://texform.dev/rules) — Every built-in rewrite rule with its level, fidelity, and eliminated forms.

